2012-04-20 17 views
18

Mam aplikację Rails 3.2.2, którą chcę uruchomić przy użyciu JRuby 1.6.7 (tryb 1.9.2).JRuby Wydajność

Mam app próbki uruchomiony w MRI Ruby 1.9.3 i typowy wniosek wraca w ~ 40ms: Zakończony 200 OK w 36ms (Views: 27.5ms | ActiveRecord: 8.2ms)

Pod użyciu JRuby to samo żądanie jest od 3 do 20 razy wolniejsze w zależności od strony. Dla tej samej operacji jak powyżej zajmuje to ~ 180ms: Ukończono 200 OK w ciągu 180ms (wyświetlenia: 153.0ms | ActiveRecord: 24.0ms)

Czy to normalna różnica w wydajności? Czytałem, że JRuby jest mniej więcej równy prędkości z MRI. Wyniki utrzymują się na moim Macu i serwerze Windows (gdzie niestety będzie trzeba uruchomić). Pakowanie go z Warblerem działającym pod Tomcat jest równie powolne.

Powyższe czasy pochodzą z podstawowej aplikacji szyny stworzonej do testowania JRuby. W bardziej złożonej aplikacji czasy są jeszcze bardziej oddalone. W tej aplikacji na niektórych stronach uruchamiany jest więcej kodu ruby. Wygląda na to, że im więcej strona jest zależna od rubinu, tym większa różnica wydajności obserwuję. Nie zrobiłem tuningu JRuby, ponieważ nie wiem od czego zacząć.

Moje pytania brzmią: czy to normalne? Co mogę zrobić, aby dostroić JRuby?

Odpowiedz

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

Nie, to nie jest normalne. Po rozgrzaniu JVM, żądania Railsów pod JRuby są zwykle znacznie bardziej wydajne niż w MRI, zarówno pod względem szybkości wykonywania surowego jak i odśmiecania.

Wygląda na to, że Twoja aplikacja jest źle skonfigurowana. Pierwszą rzeczą do sprawdzenia jest konfiguracja samego Railsów - upewnij się, że Railsy nie są w trybie programowania i że config.threadsafe! jest włączone w twoim środowisku produkcyjnym. W trybie Threadsafe będzie istniała tylko jedna udostępniona kopia Railsów załadowanych do pamięci podczas działania aplikacji.

Sprawdź również, czy konfiguracja bazy danych wykorzystuje pulę połączeń, np. pool: 20 w database.yml.

Na koniec sprawdź ustawienia JVM i JRuby - oba są bardzo przestrajalne. Musisz upewnić się, że przy uruchamianiu jest przydzielona wystarczająca ilość pamięci dla JVM, a następnie wystarczająca ilość pamięci dla prawidłowego działania aplikacji; w przeciwnym razie JVM będzie stale zmuszana do przedwczesnego i często nieużytecznego zbierania śmieci, co znacznie obniży wydajność.

Na przykład niektóre ustawienia dla skromnie specced VPS może być coś takiego:

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

... ale nie kopiuj tych ustawień ślepo! Będziesz musiał eksperymentować i wypracować, co jest dla ciebie dobre w odniesieniu do zasobów pamięci dostępnych na twoim serwerze.

To powiedziawszy, podczas gdy JRuby prawdopodobnie zużyje mniej pamięci niż całkowita suma wielu procesów Railsowych w MRI, z pewnością będziesz musiał przydzielić trochę więcej z góry dla pojedynczego procesu JVM.Bądź hojny dla JRuby i JRuby wynagrodzi cię za życzliwość :-)

można przeczytać więcej na temat strojenia JRuby i JVM tutaj: https://github.com/jruby/jruby/wiki/PerformanceTuning

Aktualizacja

Nie trzeba ustawić config.threadsafe! w Rails 4.0 i wyżej; jest domyślnie bezpieczny dla wątków.

+0

Uruchomienie w trybie 'produkcji', w porównaniu do trybu programowania, daje czasami 5-6-krotnie szybszą odpowiedź. Przynajmniej tak było w moim przypadku. Dzięki za zwrócenie na to uwagi. – Aleks

3

Upgrade do jruby 1.6.8 lub jruby 1.7.x z JAVA 7!

Niesamowita wydajność.

Mieliśmy ten sam problem i jego niesamowicie szybki teraz (po prostu przełączanie wersji).

+2

Mam takie same złe występy. Próbowałem java 7 i Jruby 1.7, świeża aplikacja szyn jest wolniejsza niż silny projekt prądowy z MRI. Erg. – m4tm4t

4

Widzę to samo zachowanie, ale należy pamiętać, że JRuby potrzebuje znacznie dłużej, aby się rozgrzać. Jestem trochę optymistycznie nastawiony do tego, że JRuby w końcu dogoni.

Można przyspieszyć to "rozgrzewanie", ustawiając kilka opcji. Ruby - kompilator> Bytecode Java można nauczyć JIT kompilacji każdą metodę na pierwszym wezwaniem ustawiając następujące env var:

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

dla mnie, po odświeżeniu strony Rails kilka razy, to jeszcze 2 -3x wolniej niż MRI Ruby, ale co najmniej 3 razy szybciej niż wcześniej.

Należy również pamiętać, że środowisko wykonawcze Java to JIT kompilujące kod bajtowy java do kodu maszyny w podobny sposób, ale ten JIT nie zostanie uruchomiony, dopóki metoda nie zostanie wywołana 10.000x podczas korzystania ze środowiska wykonawczego serwera. Może to być configured as well.

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

Z tych opcji, JRuby on Rails daje o takiej samej lub lepszej wydajności niż MRI.

Należy pamiętać, że te opcje dotyczą tylko niecierpliwego testu porównawczego! W rzeczywistości prawie zawsze złym pomysłem jest agresywne uruchamianie kompilacji JIT; Marnujesz cenny czas i pamięć na kompilację kodu JIT, która może być uruchamiana tylko kilka razy. Pokazuje jednak, w jaki sposób ostateczna wydajność JRuby może być lepsza niż można się spodziewać na podstawie początkowych przebiegów.

Daj mi znać, czy to działa dla Ciebie.