2016-07-17 507 views
8

L'utilizzo di apachebench con le opzioni "ab -k -c 50 -n 1000000" (50 thread simultanei) mostra una differenza di prestazioni di 10 volte tra i seguenti 2 metodi (serializzazione manuale e gestita a molla). È possibile ottenere le stesse prestazioni tramite la configurazione della serializzazione Spring?Perché la serializzazione Spring MVC json è 10 volte più lenta rispetto alla chiamata manuale di jackson?

Sto eseguendo il test su Windows 7, JDK8, i7-6700. Incorporato Tomcat, risultati simili con Undertow o Jetty anche. Una simile WildFly 10 JAX-RS prestazioni di app di esempio produce risultati simili a quella manuale primaverile, quindi non vedo alcun motivo per cui la modalità automatica Spring dovrebbe essere così lenta.

il codice sorgente completo:

@SpringBootApplication 
@Controller 
public class DemoApplication { 

    public static void main(String[] args) { 
    SpringApplication.run(DemoApplication.class, args); 
    } 

    ObjectMapper mapper = new ObjectMapper(new JsonFactory()); 

    @RequestMapping(value = "/auto", produces = "application/json; charset=utf-8") 
    @ResponseBody 
    public Lol automaticSerialization() { 

    Lol lol = new Lol(); 
    lol.a = UUID.randomUUID().toString(); 
    lol.b = System.currentTimeMillis(); 

    return lol; 
    } 

    @RequestMapping(value = "/manual", produces = "application/json; charset=utf-8") 
    @ResponseBody 
    public String manualSerialization() throws JsonProcessingException { 

    Lol lol = new Lol(); 
    lol.a = UUID.randomUUID().toString(); 
    lol.b = System.currentTimeMillis(); 

    return mapper.writeValueAsString(lol); 
    } 

    public static class Lol { 

    String a; 
    long b; 

    public void setA(String a) { 
     this.a = a; 
    } 

    public void setB(long b) { 
     this.b = b; 
    } 

    public String getA() { 
     return a; 
    } 

    public long getB() { 
     return b; 
    } 
    } 

} 

Edit: Traccia di serializzazione automatica: Trace of automatic serialization

Traccia di serializzazione manuale: Trace of manual serialization

+0

L'unica differenza che vedo è l'esecuzione dei vari HttpMessageConverter per trovare il convertitore di jackson. Questo convertitore chiama 'ObjectMapper.canSerialize' e gestisce' @ JsonView' ma onestamente, non vedo perché queste chiamate possano aggiungere un overhead x10 –

+0

È davvero strano. Ho allegato alcuni screenshot dei risultati di profilazione. – GeorgeStone

+0

Hai provato le stesse chiamate ma hai restituito elenchi di 100 LOL?Mi chiedo se ci sia un po 'di ottimizzazione del lotto in gioco con tempi più lenti rispetto al semplice writeValueAsString – RutledgePaulV

risposta

2

L'unica idea che ho è che L'impostazione predefinita di Spring ObjectMapper è configurata in modo leggermente diverso da quello che usi nel tuo benchmark. Come i commenti citati, probabilmente vedresti un po 'di overhead se lasci che Spring gestisca la mappatura automaticamente, ma non dovrebbe avere un impatto di oltre il qualche per cento.

Per essere sicuri che il confronto è giusto, aggiungere questa definizione di fagioli alla propria configurazione:

@Bean 
@Primary 
ObjectMapper objectMapper() { 
    return new ObjectMapper(new JsonFactory()); 
} 

e sostituire ObjectMapper mapper = new ObjectMapper(new JsonFactory()); con un campo autowired:

@Autowired 
ObjectMapper mapper; 

e vedere se i parametri di riferimento restituire il stesso valore

EDIT

ho voluto verificare questo per myselt così ho scritto un piano JMeter ed eseguito ogni endpoint esattamente 5kk volte, con un periodo di riscaldamento di 1 minuto. I risultati sono stati come previsto, senza grandi differenze tra gli approcci:

Label,# Samples,Average,Min,Max,Std. Dev.,Error %,Throughput,KB/sec,Avg. Bytes 
Auto Request,5000000,2,0,108,5.88,0.00%,15577.3,3088.08,203.0 
Manual Request,5000000,2,0,149,5.99,0.00%,15660.2,2813.94,184.0 

La cosa importante da notare è la differenza di throughput - auto di 15.577,3 vs manuale 15660,2.

Here's my JMeter test plan, se si desidera testarlo da soli, stavo correndo sulla porta 8081. Se trovo il tempo, proverò un altro framework di benchmarking, forse Gatling.

+0

Grazie, testato questo approccio, ma questo ha lo stesso risultato. – GeorgeStone

+0

Ho provato a eseguire il test tramite JMeter ma non sono riuscito a riprodurre i risultati, vedere la risposta aggiornata –

+0

JMeter restituisce risultati uguali per i 2 tipi di metodo, quindi questo problema è probabilmente un problema apachebench. Forse il modo in cui la connessione è scritta/scaricata dal flusso di output di Jackson ha qualcosa a che fare con esso. – GeorgeStone