2009-09-26 11 views
32

Obsługuję aplikację do obsługi wiadomości Java, która wymaga małego opóźnienia (< 300 mikrosekund przetwarzających każdą wiadomość). Jednak nasze profilowanie pokazuje, że wirtualna maszyna Sun Java działa początkowo i przyspiesza po pierwszych 5000 wiadomościach. Pierwsze 5000 wiadomości ma opóźnienie 1-4 milisekund. Po około pierwszych 5 000 kolejnych komunikatów opóźnienie wynosi ~ 250 mikrosekund, z sporadycznymi wartościami odstającymi.Technika lub narzędzie minimalizujące czas rozgrzewki Java?

Powszechnie wiadomo, że jest to typowe zachowanie aplikacji Java. Z biznesowego punktu widzenia nie można jednak powiedzieć klientowi, że musi poczekać, aż JVM się "rozgrzeje", zanim zobaczą wymaganą wydajność. Aplikacja musi być „podgrzewana” przed pierwszym komunikacie klienta są przetwarzane

JVM jest Sun 1.6.0 Aktualizacja 4.

Pomysły na przezwyciężenie tego problemu:

  1. ustawienia JVM, takie jak -XX: CompileThreshold =
  2. Dodaj komponent do "rozgrzewania" aplikacji podczas uruchamiania, na przykład wysyłając "fałszywe wiadomości" za pośrednictwem aplikacji.
  3. Statyczne ładowanie aplikacji i klas JDK podczas uruchamiania aplikacji, aby klasy nie były ładowane z plików JAR podczas przetwarzania komunikatów klienta.
  4. Niektóre narzędzia lub agent Java, który realizuje jedną lub obie powyższe dwie koncepcje, dzięki czemu nie muszę ponownie wymyślać koła.

UWAGA: Oczywiście dla tego rozwiązania sprawdzam wszystkie czynniki, w tym łuk, typ i konfigurację dysku oraz ustawienia systemu operacyjnego. Jednak na to pytanie chcę się skupić na tym, co można zrobić, aby zoptymalizować aplikację Java i zminimalizować czas "rozgrzewki".

+0

Myślę, że lepiej przyjrzeć się podstawowej przyczynie początkowego opóźnienia. Narzędzia profilujące mogą pomóc. – Thomas

+1

Wysyła 5000 fałszywych wiadomości do serwera w ramach procedury instalacji i uruchamiania. – Zed

+1

5000 fałszywych wiadomości (nawet jeśli to był dobry pomysł) brzmi, jakby dodać 5 do 20 sekund do czasu uruchomienia aplikacji. –

Odpowiedz

24

„Rozgrzewka” w Javie jest zazwyczaj około dwóch rzeczy:

(1): Lazy klasa ładowania: może to być praca wokół siłą go załadować.

Łatwym sposobem na to jest wysłanie fałszywej wiadomości. Powinieneś być pewien, że fałszywa wiadomość wywoła cały dostęp do klas. Przykładowo, jeśli wyślesz pustą wiadomość, ale twój progrom sprawdzi, czy wiadomość jest pusta i unikniesz pewnych rzeczy, to nie zadziała.

Innym sposobem na zrobienie tego jest wymuszenie inicjowania klasy przez uzyskanie dostępu do tej klasy podczas uruchamiania programu.

(2): Optymalizacja czasu rzeczywistego: W czasie wykonywania Java VM zoptymalizuje część kodu. Jest to główny powód, dla którego w ogóle jest czas rozgrzewania.

Aby to ułatwić, możesz wysłać kilka fałszywych (ale wyglądających na prawdziwe) wiadomości, aby optymalizacja mogła się zakończyć, zanim użytkownik z niej skorzysta.

Innym rozwiązaniem, które może pomóc w złagodzeniu tego stanu, jest obsługa wbudowanych usług, takich jak korzystanie z usług prywatnych i ostatecznych, jak tylko możliwe. Powodem jest to, że VM nie musi sprawdzać tabeli dziedziczenia, aby zobaczyć, jaka metoda jest faktycznie wywoływana.

Mam nadzieję, że to pomoże.

11

Twoim problemem nie jest ładowanie klasy, ale kompilacja "na czas".

Spróbuj -XX:CompileThreshold=1

To zmusi Java skompilować wszystko, to po raz pierwszy uruchamia go. Spowoduje to spowolnienie uruchamiania twojego kodu, ale nie kodu VM (ponieważ zostanie skompilowany po zainstalowaniu Java). Występuje błąd, który umożliwia Java kompilowanie niestandardowych plików JAR w podobny sposób i zapisywanie wyniku dla późniejszych wykonań, co znacznie zmniejszy obciążenie, ale nie ma żadnej presji, aby naprawić ten błąd w najbliższym czasie.

Drugą opcją byłoby wysłanie 5'000 fałszywych wiadomości do aplikacji w celu "rozgrzania". Sprzedaj to jako "upewniając się, że wszystko jest poprawnie skonfigurowane".

[EDIT] Niektóre informacje tło w klasach prekompilacja: Class Data Sharing

Możesz spróbować wersję IBM Java, ponieważ tutaj można dodać więcej klas do wspólnej puli: Overview of class data sharing

[Edit2] Aby odpowiedzieć na pytania zgłoszone przez kittylyst: To prawda, że ​​szybko to zapełni pamięć podręczną kodu metodami, które są używane tylko raz. Może nawet spowolnić całą aplikację.

Jeśli ustawisz niską wartość, czas uruchamiania aplikacji może stać się strasznie wolny. Dzieje się tak, ponieważ optymalizacja JIT + uruchamianie skompilowanego kodu jest droższa niż jednorazowe uruchomienie kodu w trybie interpretacji.

Głównym problemem jest to, że kod jest nadal kompilowany "na czas". Tak długo, jak nie możesz uruchomić każdej metody, której potrzebujesz, przynajmniej raz, aplikacja będzie "hickupować" przez kilka milisekund za każdym razem, gdy napotka coś, co nie zostało wcześniej skompilowane.

Ale jeśli masz pamięć RAM, Twoja aplikacja jest mała lub możesz zwiększyć rozmiar pamięci podręcznej kodu i nie masz nic przeciwko powolnemu uruchamianiu, możesz spróbować. Ogólnie ustawienie domyślne jest całkiem dobre.

+1

+1 za obniżenie progu kompilacji hot spot. –

+0

Sugestia: Edytuj, aby dodać link do faktycznego zgłoszenia błędu. –

+0

Gdzie jest ten błąd? Miałem tę dyskusję z facetem kompilatora Sun i przekonał mnie, że to będzie "bardzo trudne" i znacznie bardziej skomplikowane, niż mogłoby się wydawać pierwsze rumieniec. – Mainguy

3

Czy używasz klienta lub serwera JVM? Spróbuj uruchomić program z:

java -server com.mycompany.MyProgram 

Uruchamiając Sun JVM w tym trybie JIT będzie skompilować do kodu bajtowego wcześniej; z tego powodu program będzie trwał dłużej, ale później będzie działał szybciej.

referencyjny: Frequently Asked Questions About the Java HotSpot VM

Cytat:

Jaka jest różnica między -client i -server systemów?

Te dwa systemy to różne pliki binarne. Są to zasadniczo dwa różne kompilatory (JIT) współpracujące z tym samym systemem uruchomieniowym. System kliencki jest optymalny dla aplikacji, które wymagają krótkich czasów uruchamiania lub niewielkich rozmiarów, a system serwera jest optymalny dla aplikacji, w których najważniejsza jest ogólna wydajność. Ogólnie system klienta jest lepiej dostosowany do interaktywnych aplikacji, takich jak GUI. Niektóre inne różnice obejmują strategię kompilacji, ustawienia sterty i strategię wstawiania.

+0

Działa domyślnie w trybie serwera, ponieważ działa na maszynie "klasy serwera" (16 GB pamięć, 8 rdzeni) – noahlz

+0

Ok, nie powiedziałeś tego w swoim pytaniu powyżej. – Jesper

+0

zarówno w trybie serwera, jak i klienta kompilacja JIT. Różnica polega na liczbie wywołań rzeczywistej metody (3000 dla klienta i 10000 dla trybu serwera). Ponadto w przypadku 64-bitowej maszyny JVM tryb serwera jest używany domyślnie. – gyorgyabraham

-4

Wydaje się Twój projekt będzie korzystać z realnych gwarancji czasowych:

Patrz: Real Time Java

+0

Nie, absolutnie nie. "Czas rzeczywisty" dotyczy spójności odpowiedzi, a nie bezwzględnej wartości. Java w czasie rzeczywistym zazwyczaj działa znacznie wolniej niż zwykła Java, ale z mniejszą różnicą w profilu wydajności. Zwykle nie nadaje się do zastosowań o małym opóźnieniu. – kittylyst

3

Jeśli działa w trybie serwera HotSpot dotyczącego współczesnego sprzętu (z 2 lub więcej rdzeni na CPU) oraz z najnowszej wersji JDK następnie po opcja może być używana za przekroczenie prędkości na rozgrzewkę:

 
-server -XX:+TieredCompilation 
+0

Domyślnie włączona jest opcja TieredCompilation. Ref: http: //docs.oracle.com/javase/8/docs/technotes/tools/unix/java.html – okwap

4

Wystarczy uruchomić kilka no-op wiadomości za pośrednictwem systemu zanim zostanie otwarty dla prawdziwego ruchu klientów. 10k wiadomości to zwykle numer.

W przypadku aplikacji finansowych (np. FIX), często odbywa się to poprzez wysyłanie zamówień (po cenie z daleka od ostatniej nocy, na wszelki wypadek) na rynek, zanim zostanie on otwarty. Wszystkie zostaną odrzucone, ale to nie ma znaczenia.

Jeśli używany protokół to homebrew, to następnym razem, gdy uaktualnisz do niego biblioteki, dodaj jawną obsługę typu komunikatu "WARMUP" lub "TEST" lub "SANITYCHECK".

Oczywiście, to nie spowoduje kompilacji ścieżek specyficznych dla aplikacji, ale w przyzwoitej aplikacji do obsługi wiadomości część dotycząca ruchu sieciowego będzie prawie na pewno dominującą częścią stosu, tak więc nie robi tego ". Nieważne.

+1

Tak, to jest podejście, które podjęliśmy. Ale nie spamowaliśmy rynku. Stworzyliśmy fałszywe połączenia "loopback". – noahlz

2

Stary wątek, wiem, ale znalazłem to w internecie:

Bardzo ciekawą rzeczą jest wpływ opcji-XX: CompileThreshold = 1500 Sun HotSpot JVM. Wartość domyślna to 10000 dla maszyny wirtualnej serwera i 1500 dla maszyny wirtualnej klienta. Jednak ustawienie go na 1500 dla Server VM sprawia, że ​​jest szybszy niż VM klienta. Ustawienie go na 100 faktycznie obniża wydajność. A użycie opcji-Xcomp (co oznacza, że ​​cały kod jest kompilowany przed użyciem) daje jeszcze niższą wydajność, co jest zaskakujące.

Teraz już wiesz, co robić.

Powiązane problemy