2012-04-20 25 views
18

Ho un'applicazione Rails 3.2.2 che sto cercando di eseguire utilizzando JRuby 1.6.7 (modalità 1.9.2).JRuby Performance

Ho un app campione in esecuzione in risonanza magnetica ruby ​​1.9.3 e una richiesta tipica sta tornando in ~ 40ms: Completato 200 OK in 36ms (Viste: 27.5ms | ActiveRecord: 8.2ms)

Sotto JRuby utilizzando la stessa richiesta è ovunque da 3 a 20 volte più lento a seconda della pagina. Per la stessa operazione di cui sopra ci vogliono ~ 180 ms: Completato 200 OK a 180 ms (Visualizzazioni: 153.0 ms | ActiveRecord: 24.0 ms)

Si tratta di una differenza di prestazioni normale? Ho letto che JRuby è approssimativamente uguale alla velocità con la risonanza magnetica. I risultati rimangono sul mio Mac e su un server Windows (dove sfortunatamente dovrà essere eseguito). Imballare con Warbler che corre sotto Tomcat è altrettanto lento.

I tempi sopra indicati provengono da un'app di base creata per testare JRuby. Nell'app più complessa i tempi sono ancora più distanti. Su quell'app viene eseguito più codice ruby ​​su alcune pagine. Sembra che più la pagina è dipendente dal rubino, maggiore è la differenza di prestazioni che sto osservando. Non ho effettuato alcuna messa a punto di JRuby, dal momento che non so da dove iniziare.

Quindi le mie domande sono: è normale? Cosa posso fare per sintonizzare JRuby?

risposta

18
Is this a normal performance difference? 
I have read that JRuby is roughly equal on speed with MRI. 

No, non è normale. Una volta che la JVM si è riscaldata, le richieste di Rails sotto JRuby sono in genere significativamente più performanti rispetto alla RM, sia in termini di velocità di esecuzione raw che di garbage collection.

Sembra che l'app non sia configurata correttamente. La prima cosa da verificare è la configurazione di Rails stesso: assicurati che Rails non sia in modalità sviluppo e che config.threadsafe! sia abilitato nell'ambiente di produzione. La modalità Threadsafe risulterà in una sola copia condivisa di Rails caricata in memoria quando la tua app è in esecuzione.

Verificare inoltre che la configurazione del database stia sfruttando il pool di connessioni, ad es. pool: 20 in database.yml.

Infine, controlla le impostazioni di JVM e JRuby: entrambe sono altamente sintonizzabili. È necessario assicurarsi che vi sia sufficiente memoria allocata alla JVM all'avvio e quindi sufficiente memoria per il normale funzionamento della vostra applicazione; in caso contrario, la JVM sarà costantemente costretta a raccogliere i dati in modo prematuro e frequente, il che ridurrà in modo significativo le prestazioni.

Per esempio alcune delle impostazioni per una VPS modestamente speccato potrebbe essere qualcosa di simile:

-Xmx500m -Xss1024k -Djruby.memory.max=500m -Djruby.stack.max=1024k

... ma non copiare queste impostazioni alla cieca! Dovrai sperimentare e capire cosa ti fa bene rispetto alle risorse di memoria disponibili sul tuo server.

Detto questo, mentre JRuby probabilmente consumerà meno memoria rispetto alla somma totale di più processi Rails sotto MRI, sarà sicuramente necessario allocare un po 'più in anticipo per un singolo processo JVM.Siate generosi con JRuby, e JRuby vi ricompenserà per la vostra gentilezza :-)

Si può leggere di più su sintonizzazione JRuby e la JVM qui: https://github.com/jruby/jruby/wiki/PerformanceTuning

Aggiornamento

Non è necessario impostare config.threadsafe! in Rails 4.0 e versioni successive; è sicuro per impostazione predefinita.

+0

L'esecuzione in modalità 'produzione', rispetto alla modalità di sviluppo comporta una risposta a volte 5-6 volte più rapida. Almeno quello era nel mio caso. Grazie per averlo notato – Aleks

3

Aggiornamento a jruby 1.6.8 o jruby 1.7.x con JAVA 7!

Prestazioni eccezionali.

Abbiamo avuto lo stesso problema ed è tremendamente veloce ora (con il solo cambio di versioni).

+2

Ho le stesse cattive prestazioni. Provato java 7 e Jruby 1.7, una nuova app per i binari è più lenta di un forte progetto in corso con la risonanza magnetica. Erg. – m4tm4t

4

Sto vedendo lo stesso comportamento, ma tenete presente che JRuby ha bisogno di molto più tempo per riscaldarsi. In realtà sono un po 'ottimista sul fatto che JRuby alla fine recupererà.

È possibile rendere più veloce questo "riscaldamento" impostando alcune opzioni. The Ruby - compilatore> Bytecode Java può essere insegnato a JIT compilare ogni metodo sulla prima invocazione impostando la seguente env var:

export JRUBY_OPTS="-J-Djruby.jit.threshold=1 -J-Djruby.jit.max=16384"

Per me, dopo l'aggiornamento di una pagina di Rails un paio di volte, è ancora 2 -3x più lento del MRI Ruby, ma almeno 3 volte più veloce di prima.

Inoltre, il java runtime è JIT che compila il codice java java al codice macchina in modo simile, ma questo JIT non esegue il kick in finché non viene richiamato un metodo 10.000x quando si utilizza il runtime del server. Questo può essere configured as well.

export JRUBY_OPTS="-J-Djruby.jit.threshold=10 -J-Djruby.jit.max=16384 -J-XX:CompileThreshold=10" -J-XX:ReservedCodeCacheSize=128M"

Con queste opzioni, JRuby on Rails dà circa lo stesso o prestazioni migliori rispetto risonanza magnetica.

Si prega di notare che queste opzioni sono solo per il benchmarking impaziente! In realtà è quasi sempre una cattiva idea eseguire la compilation JIT in modo aggressivo; Stai sprecando tempo prezioso e memoria sulla compilazione del codice JIT che potrebbe essere eseguita solo poche volte. Mostra, tuttavia, come le eventuali prestazioni di JRuby potrebbero essere migliori di quanto previsto in base alle corse iniziali.

Fammi sapere se questo funziona per voi.