2009-09-26 11 views
32

Sto supportando un'applicazione di messaggistica Java che richiede bassa latenza (< 300 microsecondi che elaborano ciascun messaggio). Tuttavia, la nostra profilazione mostra che la Sun Java Virtual Machine funziona lentamente all'inizio e accelera dopo i primi 5.000 messaggi o giù di lì. I primi 5000 messaggi hanno una latenza di 1-4 millisecondi. Dopo circa i primi 5.000, i messaggi successivi hanno una latenza di ~ 250 microsecondi, con valori anomali occasionali.Tecnica o utilità per ridurre al minimo il tempo di "riscaldamento" di Java?

È generalmente inteso che questo è un comportamento tipico per un'applicazione Java. Tuttavia, da un punto di vista aziendale non è accettabile dire al cliente che devono aspettare che la JVM si "scaldi" prima di vedere le prestazioni che richiedono. L'applicazione deve essere "riscaldato-up" prima che il primo messaggio cliente viene elaborato

La JVM è Sun 1.6.0 aggiornamento 4.

Idee per superare questo problema:

  1. impostazioni JVM, come -XX: CompileThreshold =
  2. Aggiungi un componente per "riscaldare" l'applicazione all'avvio, ad esempio inviando "messaggi falsi" attraverso l'applicazione.
  3. Caricamento statico dell'applicazione e classi JDK all'avvio dell'applicazione, in modo che le classi non vengano caricate dai JAR durante l'elaborazione dei messaggi dei clienti.
  4. Alcuni programmi di utilità o Java che eseguono una o entrambe le due idee precedenti, in modo da non dover re-inventare la ruota.

NOTA: Ovviamente per questa soluzione sono presenti tutti i fattori, inclusi il chip arch, il tipo di disco e la configurazione e le impostazioni del sistema operativo. Tuttavia, per questa domanda voglio concentrarmi su cosa si può fare per ottimizzare l'applicazione Java e minimizzare il tempo di "riscaldamento".

+0

Penso che dovresti esaminare la causa alla base di questo ritardo iniziale. Strumenti di profiling potrebbero aiutare. – Thomas

+1

Invia 5000 falsi messaggi al server come parte della procedura di installazione e avvio. – Zed

+1

5000 messaggi falsi (anche se fosse una buona idea) sembrano aggiungere 5 o 20 secondi al tempo di avvio dell'app. –

risposta

24

"Warm-up" in Java è in genere di due cose:

(1): pigro classe di carico: Questo può essere un lavoro in giro con la forza che si carichi.

Il modo semplice per farlo è inviare un messaggio falso. Dovresti essere sicuro che il falso messaggio attiverà tutti gli accessi alle classi. Per esempio, se si invia un messaggio vuoto ma il progrom controllerà se il messaggio è vuoto ed eviterà di fare certe cose, allora questo non funzionerà.

Un altro modo per farlo è forzare l'inizializzazione della classe accedendo a quella classe all'avvio del programma.

(2): L'ottimizzazione in tempo reale: in fase di esecuzione, Java VM ottimizzerà parte del codice. Questo è il motivo principale per cui c'è un periodo di riscaldamento.

Per semplificare l'operazione, è possibile inviare una serie di messaggi falsi (ma di aspetto reale) in modo che l'ottimizzazione possa essere completata prima che l'utente la utilizzi.

Un altro che si può aiutare a facilitare questo è quello di supportare in linea come usare privato e finale il più possibile. il motivo è che, la VM non ha bisogno di cercare la tabella di ereditarietà per vedere quale metodo per essere effettivamente chiamato.

Spero che questo aiuti.

11

Il tuo problema non è la compilazione della classe ma la compilazione "just in time".

Prova -XX:CompileThreshold=1

che costringerà Java per compilare tutto la prima volta che lo gestisce. Rallenterà un po 'l'avvio del codice, ma non il codice della macchina virtuale (dal momento che viene compilato quando Java è installato). C'è un bug aperto per consentire a Java di compilare JAR personalizzati in modo simile e salvare il risultato per le esecuzioni successive che ridurrebbe notevolmente questo overhead, ma non c'è alcuna pressione per correggere questo bug in qualunque momento.

Una seconda opzione sarebbe quella di inviare 5'000 messaggi falsi all'app per "riscaldarlo". Vendi come "assicurandoti che tutto sia impostato correttamente".

[EDIT] Alcuni retroscena info in classi precompilazione: Class Data Sharing

Si consiglia di provare la versione IBM di Java, in quanto qui, è possibile aggiungere più classi alla piscina in comune: Overview of class data sharing

[EDIT2] Per rispondere alle domande sollevate da kittylyst: È vero che questo riempirà rapidamente la cache del codice con metodi che vengono utilizzati una sola volta. E potrebbe anche rallentare l'intera app.

Se si imposta su un valore basso, il tempo di avvio dell'applicazione può diventare terribilmente lento. Questo perché l'ottimizzazione JIT + che esegue il codice compilato è più costoso rispetto all'esecuzione del codice una volta in modalità interpretata.

Il problema principale qui è che il codice è ancora compilato "just in time". Finché non è possibile eseguire tutti i metodi necessari almeno una volta, l'app eseguirà un "hickup" per alcuni millisecondi ogni volta che incontra qualcosa che non è stato compilato prima.

Ma se hai la RAM, la tua app è piccola o puoi aumentare la dimensione della cache del codice e non ti importa il tempo di avvio lento, puoi provarlo. Generalmente, l'impostazione predefinita è abbastanza buona.

+1

+1 per la riduzione della soglia di compilazione degli hot spot. –

+0

Suggerimento: Modifica per aggiungere il link alla segnalazione dei bug effettiva. –

+0

Dov'è quel bug? Ho avuto questa discussione con un compilatore di Sun e lui mi ha convinto che sarebbe stato "molto difficile" e molto più complicato che il primo blush sembrerebbe indicare. – Mainguy

3

Si sta utilizzando il client o il server JVM? Provare ad avviare il programma con:

java -server com.mycompany.MyProgram 

Durante l'esecuzione di JVM di Sun in questa modalità, il JIT compila il bytecode in codice nativo in precedenza; per questo motivo, il programma impiegherà più tempo per avviarsi, ma dopo sarà più veloce.

Riferimento: Frequently Asked Questions About the Java HotSpot VM

Citazione:

Qual è la differenza tra il -client e sistemi -server?

Questi due sistemi sono binari diversi. Sono essenzialmente due diversi compilatori (JIT) che si interfacciano con lo stesso sistema runtime. Il sistema client è ottimale per le applicazioni che richiedono tempi di avvio rapidi o impronte ridotte, il sistema server è ottimale per le applicazioni in cui le prestazioni complessive sono più importanti. In generale, il sistema client è più adatto per applicazioni interattive come le GUI. Alcune delle altre differenze includono la politica di compilazione, i valori predefiniti dell'heap e la politica di inlining.

+0

È in esecuzione in modalità server per impostazione predefinita perché è in esecuzione su una macchina "server-class" (16 GB memoria, 8 core) – noahlz

+0

Ok, non l'hai detto nella tua domanda sopra. – Jesper

+0

server e client entrambi compilano JIT. La differenza è nel numero di chiamate di un metodo effettivo (3000 per client e 10000 per modalità server). Inoltre, con una JVM a 64 bit, la modalità server viene utilizzata come impostazione predefinita. – gyorgyabraham

-4

Sembra come il progetto potrebbe beneficiare di garanzie in tempo reale:

See: Real Time Java

+0

No, assolutamente no. "Tempo reale" riguarda la coerenza della risposta, non il valore assoluto. Real Time Java funziona in genere molto più lentamente del normale Java, ma con una varianza ridotta nel profilo delle prestazioni. Questo non è in genere adatto per applicazioni a bassa latenza. – kittylyst

3

Se in esecuzione in modalità server di Hotspot su hardware contemporaneo (con 2 o più core per CPU) e con l'ultima versione del JDK poi seguendo opzione può essere utilizzata per eccesso di velocità di riscaldamento:

 
-server -XX:+TieredCompilation 
+0

Per impostazione predefinita, l'opzione TieredCompilation è abilitata. Rif: http: //docs.oracle.com/javase/8/docs/technotes/tools/unix/java.html – okwap

4

Basta eseguire una serie di messaggi non-op tramite il sistema prima che venga aperto per una vera traffico dei clienti. 10k messaggi è il solito numero.

Per le app finanziarie (ad esempio FIX), questo viene spesso eseguito inviando ordini (a un prezzo molto lontano dalla chiusura della scorsa notte, per ogni evenienza) al mercato prima dell'apertura. Saranno tutti respinti, ma non importa.

Se il protocollo che si sta utilizzando è homebrew, al prossimo aggiornamento delle librerie, aggiungere il supporto esplicito per un tipo di messaggio "WARMUP" o "TEST" o "SANITYCHECK".

Ovviamente, questo probabilmente non compilerà i percorsi specifici della logica dell'applicazione, ma in un'app di messaggistica decente, la parte che si occupa del traffico di rete sarà quasi sicuramente la parte dominante dello stack, quindi non lo fa t importa

+1

Sì, questo è l'approccio che abbiamo preso. Ma non abbiamo spamizzato il mercato. Abbiamo creato false connessioni "loopback". – noahlz

2

thread vecchio, lo so, ma ho trovato questo in internet:

Una cosa molto interessante è l'influenza di opzione della XX: CompileThreshold = 1500 a SUN JVM HotSpot. Il valore predefinito è 10000 per Server VM e 1500 per Client VM. Tuttavia impostarlo su 1500 per Server VM rende più veloce della VM client. Impostarlo su 100 diminuisce le prestazioni. E l'uso dell'opzione-Xcomp (che significa che tutto il codice è compilato prima dell'uso) offre prestazioni ancora più basse, il che è sorprendente.

Ora sai cosa fare.

Problemi correlati