Dlaczego zespół LMAX wykorzystał Javę i zaprojektował architekturę, aby za wszelką cenę unikać GC?


24

Dlaczego zespół LMAX zaprojektował LMAX Disruptor w Javie, ale wszystkie ich punkty konstrukcyjne minimalizują użycie GC? Jeśli nie chce się uruchamiać GC, to po co używać języka bezużytecznego?

Ich optymalizacje, poziom wiedzy o sprzęcie i myśl, którą włożyli, są po prostu niesamowite, ale dlaczego Java?

Nie jestem przeciwny Jawie ani nic, ale dlaczego język GC? Dlaczego nie użyć czegoś takiego jak D lub inny język bez GC, ale pozwala na wydajny kod? Czy zespół najlepiej zna Javę, czy też Java ma jakąś wyjątkową zaletę, której nie widzę?

Powiedzmy, że rozwijają go za pomocą D z ręcznym zarządzaniem pamięcią, jaka byłaby różnica? Musieliby myśleć o niskim poziomie (którym już są), ale potrafią wycisnąć najlepszą wydajność z systemu, ponieważ jest on natywny.


6
Niewiele wiem o tym projekcie, ale wydaje się, że jest to jakiś szkielet, na którym inni mogą budować. A jeśli uda ci się napisać to w Javie (i pozwolisz innym pisać w Javie i czerpać korzyści), będziesz mieć DUŻO większą „bazę klientów” niż gdybyś napisał to w D.
Joachim Sauer

6
@kadaj: tak naprawdę nie ma znaczenia, czy konsument jest publiczny czy wewnętrzny: jeśli udostępnisz go w powszechnie znanym języku, będzie on bardziej użyteczny, nawet do wewnętrznego rozwoju. Jeśli zaczniesz (hipotetyczny) argument od: „Załóżmy, że wszyscy znają D tak dobrze, jak oni znają Javę ...”, to prawdopodobnie czegoś brakuje.
Joachim Sauer

6
Niektórzy ludzie lubią używać młotków do wszelkiego rodzaju problemów. Masz ostrą krawędź, którą chcesz strugać, uderz ją młotkiem, aż będzie gładka. Masz śrubę, którą musisz wbić, uderz ją młotkiem, aż się znajdzie. Masz delikatną ozdobę, którą musisz zeszlifować, uderz młotkiem, a następnie obwiniaj ornament za „ssanie”. C lub C ++ byłby lepszym wyborem niż D, gdyby tylko dla istniejącej bazy wiedzy. Nie jestem pewien, dlaczego nawet przywołałeś D jako przykład TBH.
gbjbaanb

2
@gbjbaanb Wspomniałem o D, ponieważ zapewnia zbieranie śmieci (w przypadkach, w których konieczne są abstrakcje na wysokim poziomie, a manipulowanie pamięcią jest zbyt trudne dla mózgu), ale umożliwia także ręczne zarządzanie pamięcią w malloc w stylu C i za darmo. D jest trochę podobny do Objective-C z ARC (bez prawdziwej GC), ale lepszy. Ale tak, C / C ++ pasowałby do rachunku.

4
@kadaj Widzę, że dostajesz tutaj odrobinę flaku za wychowywanie D, ale chcę powiedzieć, że jestem rozczarowany tonem używanym przez innych i wyjaśnij, dlaczego moim zdaniem D ma kluczowe znaczenie dla tego pytania. Podczas gdy D nie jest tak naprawdę powszechnie używany, D zapewnia pewne konstrukcje wysokiego poziomu, których mógłbym oczekiwać w powiedzmy Java lub C #, ale nie w (przynajmniej w starym stylu) C ++. Nadal zapewnia miksowanie zarządzanego i niezarządzanego - co jest prawie jedynym językiem, jaki znam! Więc D to nie tylko wybór zwierzaka, ale raczej taki, którego cele pokrywają się z pierwotnymi pytaniami dotyczącymi GC.
J Trana

Odpowiedzi:


20

Ponieważ istnieje ogromna różnica między optymalizacją wydajności a wyłączeniem całkowicie bezpieczeństwa

Zmniejszając liczbę GC, ich struktura jest bardziej responsywna i może działać (przypuszczalnie) szybciej. Teraz optymalizacja dla śmieciarza nie oznacza, że ​​nigdy nie robią śmieci. Oznacza to po prostu, że robią to rzadziej, a kiedy to robią, działa to naprawdę szybko. Tego rodzaju optymalizacja obejmuje:

  1. Minimalizowanie liczby obiektów, które przenoszą się na przestrzeń ocalałych (tj. Które przetrwały co najmniej jeden zbiór śmieci) za pomocą małych obiektów wyrzucanych. Obiekty, które przeniosły się w przestrzeń ocalałych, są trudniejsze do zebrania, a wywóz śmieci tutaj czasami oznacza zamrożenie całej JVM.
  2. Nie przydzielaj zbyt wielu obiektów na początek. Może się to zdarzyć, jeśli nie będziesz ostrożny, ponieważ obiekty młodego pokolenia są super tanie w przydzielaniu i zbieraniu.
  3. Upewnij się, że nowy obiekt wskazuje stary (a nie na odwrót), aby młody obiekt był łatwy do zebrania, ponieważ nie ma odniesienia do nich, które spowodowałoby, że byłyby przechowywane

Kiedy wyłączysz wydajność, zazwyczaj dostroisz bardzo specyficzny „gorący punkt”, ignorując kod, który nie jest często uruchamiany. Jeśli zrobisz to w Javie, możesz pozwolić, aby śmieciarz nadal zajmował się tym ciemnym rogiem (ponieważ nie zrobi to dużej różnicy), jednocześnie optymalizując bardzo ostrożnie dla obszaru, który działa w ciasnej pętli. Możesz więc wybrać, gdzie chcesz zoptymalizować, a gdzie nie, a tym samym skoncentrować swój wysiłek tam, gdzie to ważne.


Teraz, jeśli całkowicie wyłączysz śmieci, nie będziesz mógł wybrać. Musisz ręcznie pozbyć się każdego obiektu, zawsze. Ta metoda jest wywoływana co najwyżej raz dziennie? W Javie możesz na to pozwolić, ponieważ jego wpływ na wydajność jest znikomy (może pozwolić na to, aby pełny GC pojawiał się co miesiąc). W C ++ nadal wyciekają zasoby, więc musisz zająć się nawet tą niejasną metodą. Musisz więc płacić cenę za zarządzanie zasobami w każdej pojedynczej części aplikacji, podczas gdy w Javie możesz się skupić.


Ale jest coraz gorzej.

Co się stanie, jeśli masz błąd, powiedzmy w ciemnym rogu aplikacji, do której dostęp jest dostępny tylko w poniedziałek w pełni księżyca? Java ma silną gwarancję bezpieczeństwa. Niewiele jest „niezdefiniowanych zachowań”. Jeśli użyjesz czegoś niewłaściwego, zgłoszony zostanie wyjątek, program się zatrzyma i nie nastąpi uszkodzenie danych. Jesteś więc pewien, że nic złego się nie stanie bez Twojej uwagi.

Ale w czymś takim jak D, możesz mieć zły dostęp do wskaźnika lub przepełnienie bufora i możesz uszkodzić swoją pamięć, ale twój program nie będzie wiedział (wyłączyłeś bezpieczeństwo, pamiętasz?) I będzie działał z niepoprawnym danych i róbcie dość paskudne rzeczy i niszczcie swoje dane, a wy nie wiecie, a gdy więcej korupcji się zdarza, wasze dane stają się coraz bardziej błędne, a potem nagle się psują, i to było w krytycznej dla życia aplikacji, i jakiś błąd wydarzyło się w obliczeniach rakiety, i tak to nie działa i rakiety wybuch, a ktoś umrzeć, a firma jest na pierwszej stronie każdej gazety i punkt szef jej palec do ciebie mówiąc: „Ty jesteś inżynier, który zasugerował, że użyliśmy D do optymalizacji wydajności, dlaczego nie pomyślałeś o bezpieczeństwie?". To twoja wina. Zabiłeś tych ludzi głupią próbą działania.


OK, ok, przez większość czasu jest to znacznie mniej dramatyczne. Ale nawet aplikacja o znaczeniu krytycznym dla biznesu lub po prostu aplikacja GPS lub, powiedzmy, rządowa witryna opieki zdrowotnej może mieć dość negatywne konsekwencje w przypadku błędów. Bardzo dobrym pomysłem jest używanie języka, który albo całkowicie im zapobiegnie, albo szybko się nie powiedzie.

Wyłączenie bezpieczeństwa kosztuje. Być rodzimym nie zawsze ma sens. Czasami jest o wiele prostsze i bezpieczniejsze po prostu zoptymalizować nieco bezpieczny język, który pasuje do języka, w którym możesz strzelać sobie w stopę przez długi czas. Poprawność i bezpieczeństwo w wielu przypadkach przebija kilka nanosekund, które zostałyby złomowane przez całkowite wyeliminowanie GC. W takich sytuacjach można zastosować Disruptor , więc myślę, że LMAX-Exchange wykonał właściwe połączenie.

Ale co w szczególności z D? Masz GC, jeśli chcesz dla ciemnych rogów, a podzbiór SafeD (o którym nie wiedziałem przed edycją) usuwa niezdefiniowane zachowanie (jeśli pamiętasz, aby go użyć!).

W takim razie jest to proste pytanie o dojrzałość. Ekosystem Java jest pełen dobrze napisanych narzędzi i dojrzałych bibliotek (lepszych do programowania). Znacznie więcej programistów zna Javę niż D (lepiej w utrzymaniu). Wybór nowego i mało popularnego języka dla czegoś tak krytycznego jak aplikacja finansowa nie byłby dobrym pomysłem. W przypadku mniej znanego języka, jeśli masz problem, niewielu może ci pomóc, a biblioteki, które znajdziesz, mają zwykle więcej błędów, ponieważ były narażone na mniej ludzi.

Tak więc moja ostatnia uwaga pozostaje ważna: jeśli chcesz uniknąć problemów z tragicznymi konsekwencjami, trzymaj się bezpiecznych wyborów. Na tym etapie życia D jego klientami są małe start-upy gotowe na szalone ryzyko. Jeśli problem może kosztować miliony, lepiej pozostać dalej na krzywej innowacji .


2
Oryginalny post wyraźnie woła D.. W rzeczywistości istnieje dość duża różnica między C ++ i D pod względem szczegółowości wyboru. Nawet jeśli zdecydujesz się przejść w pełni zarządzany w podzbiorze SafeD, myślę, że masz znacznie większą kontrolę nad niektórymi aspektami zbierania i synchronizacji (włączanie / wyłączanie, zbieranie, minimalizowanie). Sprawdź strategie Digital Mars dotyczące zarządzania pamięcią!
J Trana

2
lmax celowo wycofał się z bezpieczeństwa, jakie zapewnia Java
James

To byłaby świetna odpowiedź, z tym że Java nie jest licencjonowana na oprogramowanie o znaczeniu krytycznym. Jeśli masz reaktor jądrowy, zostanie napisany w języku C ++, a nie w Javie, co w pewnym sensie wyrzuca cały aspekt „bezpieczeństwa”.
gbjbaanb

@gbjbaanb, [potrzebne źródło]. Standardy / wytyczne dotyczące niezawodności, które widziałem, zalecają najpierw unikanie C / C ++ na rzecz innych języków; a jeśli się do nich dostaniesz, użyj wysoce ograniczonych wersji języków (MISRA itp.). A kiedy zaakceptujesz ograniczenia, nie rozumiem, dlaczego nie możesz zrobić tego samego z żadnym innym językiem. Jeśli zastanawiałeś się nad wzmianką o Java Licence o „nie dla obiektów nuklearnych” w sekcji OGRANICZENIA, wygląda na to, że to się zmieniło jakiś czas temu, a teraz zamiast tego mówi coś w rodzaju „bądź ostrożny, a nie nasza odpowiedzialność”. Mimo to zakładam (...)
hmijail

(...) oryginalne sformułowanie przypominało licencje gcc i clang: brak gwarancji na określone cele. Więc nie użyłbyś ich do czegoś, co wymagałoby niezawodności, a zamiast tego musiałbyś użyć certyfikowanego kompilatora, jeśli nie przechodziłbyś do jakiegoś konkretnego języka dla zadania (Ada?).
hmijail

4

Wydaje się, że powodem, dla którego napisano w Javie, jest to, że mają oni wewnętrzną wiedzę na temat języka Java i prawdopodobnie został napisany (chociaż wciąż jest w fazie rozwoju), zanim C ++ zaczął działać razem z C ++ 0x / 11.

Ich kod to tak naprawdę tylko Java z nazwy, używają sun.misc.Unsafe całkiem sporo, co w pewnym sensie pokonuje sens Java i rzekomo zapewnia bezpieczeństwo. Napisałem port C ++ Disruptor, który przewyższa kod Java, który wysyłają (nie spędziłem dużo czasu na dostrajaniu JVM).

To powiedziawszy, zasady, którymi kieruje się moduł zakłócający, nie są specyficzne dla języka, np. Nie oczekuj kodu C ++ o niskim opóźnieniu, który przydziela lub uwalnia ze stosu.


Czy możesz wskazać swoje wdrożenie? Widziałem kilka takich ponownych wdrożeń, niż twierdziłem, wyższą wydajność, ale oba oszukane z uproszczeniami: na przykład, hardwiring 1 producent + 1 konsument zamiast bycia multi-producentem / konsumentem zdolnym jak oryginalny Disruptor. Sam autor Disruptor wspomniał w wątku Grup dyskusyjnych Google, że wydajność można poprawić przez parametry przewodowe w wersji Java.
hmijail

4

To pytanie określa nieprawidłową przesłankę jako fakt, a następnie wysuwa argument na temat tej nieprawidłowej przesłanki.

Pozwala zagłębić się w to… „wszystkie ich punkty konstrukcyjne w celu zminimalizowania wykorzystania GC” - po prostu nie jest prawdą. Innowacja w urządzeniu zakłócającym ma niewiele wspólnego z GC. Disruptor działa, ponieważ jego konstrukcja sprytnie uwzględnia sposób działania nowoczesnych komputerów - coś, co jest znacznie mniej powszechne, niż można by się spodziewać. Zobacz dyskusję Cliff Click http://www.azulsystems.com/events/javaone_2009/session/2009_J1_HardwareCrashCourse.pdf w celu omówienia.

Powszechnie wiadomo, że LMax to klienci Azul. Wiem z pierwszej ręki, że z GC firmy Azul są po prostu sprawą nierozerwalną - nawet przy stosach 175 GB.


Jest w tym ziarno prawdy. Ponownie uruchamiają maszynę wirtualną co noc, aby uniknąć dużej kolekcji. Tak zresztą napisał Martin Fowler i nie jest manekinem: „Podobnie jak reszta systemu, zakłócacze są odbijane z dnia na dzień. Odbicie to ma na celu przede wszystkim wyczyszczenie pamięci, dzięki czemu istnieje mniejsze prawdopodobieństwo kosztownego wywozu śmieci podczas handlu”. martinfowler.com/articles/lmax.html
JimmyJames

2
Nie do końca. Kiedyś uruchamialiśmy ręczną GC każdej nocy w 5-minutowej luce transakcyjnej i dostosowywaliśmy ją tak, aby była to jedyna ważna GC w ciągu dnia. To stało się zbędne z Azulem Zingiem. (Źródło: do niedawna pracowałem w LMAX)
Tom Johnson

@TomJohnson Uwielbiam otrzymywać wewnętrzną miarkę. Mówisz, że opis Martina Fowlera jest błędny? Czy to możliwe, że rozwiązanie ewoluowało z czasem?
JimmyJames

2
Mówię, że nie miał racji co do niektórych drobnych szczegółów. Nigdy nie odbijaliśmy naszych systemów codziennie, ale zrobiliśmy porządki na koniec dnia.
Tom Johnson

3

Musieliby myśleć na niskim poziomie

Powyżej stanowi połowę odpowiedzi, której szukasz. Możesz znaleźć kolejną połowę, aby uzupełnić rozumowanie nie dalej niż na blogu LMAX :

Chociaż jest bardzo wydajny, może prowadzić do wielu błędów, ponieważ bardzo łatwo go zepsuć ...

Jak przyznają programiści LMAX, taki kod może być dość trudny do opracowania, zrozumienia i debugowania - nawet w Javie. Zejście niżej niżej niż obecnie, tylko pogorszy ten problem, jak wskazano w artykule Wikipedii na temat języków programowania niskiego poziomu :

Program napisany w języku niskiego poziomu może być uruchamiany bardzo szybko i przy bardzo małej powierzchni pamięci; równoważny program w języku wysokiego poziomu będzie miał większą wagę. Języki niskiego poziomu są proste, ale uważa się je za trudne w użyciu ze względu na liczne szczegóły techniczne, o których należy pamiętać .

Dla porównania, język programowania wysokiego poziomu izoluje semantykę wykonania architektury komputera od specyfikacji programu, co upraszcza programowanie ...


3

Jeśli używasz języka Java jako języka składniowego i unikasz jego bibliotek JDK, może on być tak szybki, jak skompilowany język inny niż GC. GC nie jest odpowiedni dla systemów czasu rzeczywistego, ale możliwe jest tworzenie systemów w Javie, które nie pozostawiają żadnych śmieci. W rezultacie GC nigdy się nie uruchamia.

Wierzymy, że język Java i platforma mają wiele zalet w stosunku do C / C ++ i opracowaliśmy i przetestowaliśmy niektóre komponenty Java o bardzo niskim opóźnieniu, aby to udowodnić. W tym artykule rozmawiamy o technikach, jak to zrobić: Programowanie Java bez GC .


2
Istnieją śmieciarki odpowiednie dla systemów czasu rzeczywistego. Domyślny moduł zbierający JVM może nie być, ale to nie znaczy, że GC ogólnie nie nadaje się do działania w czasie rzeczywistym. Ale zwykły malloc/freenie nadaje się również w czasie rzeczywistym, ponieważ czas alokacji jest nieograniczony z powodu fragmentacji.
Doval

1
Zalecamy stosowanie szybkich pul obiektów do wszystkiego, aby po rozgrzaniu nie doszło do alokacji.
rdalmeida

2

LMAX to wysokowydajna biblioteka przesyłania wiadomości między wątkami.

Aby być użytecznym, ktoś inny musi napisać kod, aby każdy wątek wykonał użyteczną pracę. Biorąc pod uwagę, że kod najprawdopodobniej znajduje się w Javie lub C #, a zatem istnieje bardzo niewiele wyborów języka, który dobrze z nimi współpracuje.

Używanie C lub C ++ nie jest dobrą opcją, chyba że chcesz ograniczyć użytkowników do jednego systemu operacyjnego, ponieważ nie ma w nich zdefiniowanego modelu wątków.

Java jest obecnie standardem w wielu programach, więc jeśli nie masz uzasadnionego powodu, jest to najlepszy wybór. (Gdy w Rzymie postępujcie jak Rzymianie…)

Pisanie oprogramowania o wysokiej wydajności w Javie (lub C #) jest często wykonywane w celu udowodnienia, że…


1
Nowy standard C ++ 11 obsługuje wielowątkowość ...
Casey

@Casey i ile kompilatorów C ++ z niego korzysta? Ile kosztują te kompilatory. Może za 20 lat będzie to przydatne, do tego czasu nie można na nim polegać.
Ian

Disruptor dość często używa sun.misc.Unsafe, co pokazuje, że nie można tak naprawdę pisać kodu o niskim opóźnieniu w Javie bez zanurzania palca w ziemi C
James

3
Gcc obsługuje wątki C ++ i jest bezpłatny
James

@Ian: 2 lata później i wszystkie powszechnie używane kompilatory go obsługują;). Nawet te, które są bezpłatne.
Rutix,
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.