Wysoka wydajność serializacji: Java vs Google Protocol Buffers vs ...?

Jeśli chodzi o buforowanie, które zastanawiam się nad zrobieniem dla nadchodzącego projektu, myślałem o serializacji w Javie. A mianowicie, czy należy go używać?

Teraz wcześniej pisałem niestandardową serializację i deserializację (zewnętrznie) z różnych powodów w przeszłości. W dzisiejszych czasach interoperacyjność stała się jeszcze większym problemem i mogę przewidzieć potrzebę interakcji z aplikacjami.Net, więc pomyślałem o użyciu rozwiązania niezależnego od platformy.

Czy ktoś miał jakieś doświadczenie z wykorzystaniem GPB o wysokiej wydajności? Jak wypada w porównaniu pod względem szybkości i wydajności z natywną serializacją Javy? Alternatywnie, czy są jakieś inne programy warte rozważenia?

Author: cletus, 2009-03-15

7 answers

Nie porównałem buforów protokołów z natywną serializacją Javy pod względem szybkości, ale dla interoperacyjności natywna serializacja Javy jest poważnym Nie-Nie. W większości przypadków nie będzie on również tak wydajny pod względem przestrzeni, jak bufory protokołów. Oczywiście jest nieco bardziej elastyczny pod względem tego, co może przechowywać, a także pod względem referencji itp. Bufory protokołów są bardzo dobre w tym, do czego są przeznaczone, a kiedy pasują do Twoich potrzeb, są świetne - ale są oczywiste ograniczenia ze względu na do interoperacyjności (i innych rzeczy).

Niedawno opublikowałem Framework testowania buforów protokołów w Javie i. NET. Wersja Javy znajduje się w głównym projekcie Google (w katalogu benchmarks), wersja.Net jest w moim projekcie C# port. Jeśli chcesz porównać szybkość PB z szybkością serializacji Javy, możesz napisać podobne klasy i je porównać. Jeśli jednak interesuje Cię interop, naprawdę nie dałbym natywnej serializacji Javy (lub. NET natywna binarna serializacja) druga myśl.

Oprócz buforów protokołów istnieją inne opcje interoperacyjnej serializacji - Thrift, JSON i YAML przychodzą na myśl i są niewątpliwie inni.

EDIT: ok, ponieważ interop nie jest tak ważny, warto spróbować wymienić różne cechy, które chcesz z RAM serializacji. Jedną z rzeczy, o których warto pomyśleć, jest wersjonowanie-to kolejna rzecz, do której PB jest przeznaczony dobrze radzisz sobie, zarówno do tyłu, jak i do przodu ( aby nowe oprogramowanie mogło odczytać stare dane i odwrotnie) - oczywiście przy trzymaniu się sugerowanych reguł:) {]}

Starając się być ostrożnym w kwestii wydajności Javy i natywnej serializacji, nie zdziwiłbym się, gdyby PB i tak było szybsze. Jeśli masz taką możliwość, użyj maszyny wirtualnej serwera - moje ostatnie testy wykazały, że maszyna wirtualna serwera jest ponad dwa razy szybsza przy serializacji i deserializacji przykładowych danych. Chyba kod PB bardzo ładnie pasuje do JIT serwera VM:)

Podobnie jak przykładowe dane wydajności, serializując i deserializując dwie wiadomości (jeden 228 bajtów, jeden 84750 bajtów) otrzymałem te wyniki na moim laptopie przy użyciu serwera VM:

Benchmarking benchmarks.GoogleSize$SizeMessage1 with file google_message1.dat 
Serialize to byte string: 2581851 iterations in 30.16s; 18.613789MB/s 
Serialize to byte array: 2583547 iterations in 29.842s; 18.824497MB/s 
Serialize to memory stream: 2210320 iterations in 30.125s; 15.953759MB/s 
Deserialize from byte string: 3356517 iterations in 30.088s; 24.256632MB/s 
Deserialize from byte array: 3356517 iterations in 29.958s; 24.361889MB/s 
Deserialize from memory stream: 2618821 iterations in 29.821s; 19.094952MB/s 

Benchmarking benchmarks.GoogleSpeed$SpeedMessage1 with file google_message1.dat 
Serialize to byte string: 17068518 iterations in 29.978s; 123.802124MB/s 
Serialize to byte array: 17520066 iterations in 30.043s; 126.802376MB/s 
Serialize to memory stream: 7736665 iterations in 30.076s; 55.93307MB/s 
Deserialize from byte string: 16123669 iterations in 30.073s; 116.57947MB/s 
Deserialize from byte array: 16082453 iterations in 30.109s; 116.14243MB/s
Deserialize from memory stream: 7496968 iterations in 30.03s; 54.283176MB/s 

Benchmarking benchmarks.GoogleSize$SizeMessage2 with file google_message2.dat 
Serialize to byte string: 6266 iterations in 30.034s; 16.826494MB/s 
Serialize to byte array: 6246 iterations in 30.027s; 16.776697MB/s 
Serialize to memory stream: 6042 iterations in 29.916s; 16.288969MB/s 
Deserialize from byte string: 4675 iterations in 29.819s; 12.644595MB/s 
Deserialize from byte array: 4694 iterations in 30.093s; 12.580387MB/s 
Deserialize from memory stream: 4544 iterations in 29.579s; 12.389998MB/s 

Benchmarking benchmarks.GoogleSpeed$SpeedMessage2 with file google_message2.dat 
Serialize to byte string: 39562 iterations in 30.055s; 106.16416MB/s 
Serialize to byte array: 39715 iterations in 30.178s; 106.14035MB/s 
Serialize to memory stream: 34161 iterations in 30.032s; 91.74085MB/s 
Deserialize from byte string: 36934 iterations in 29.794s; 99.98019MB/s 
Deserialize from byte array: 37191 iterations in 29.915s; 100.26867MB/s 
Deserialize from memory stream: 36237 iterations in 29.846s; 97.92251MB/s 

"Prędkość" vs "rozmiar" to to, czy wygenerowany kod jest zoptymalizowany pod kątem prędkości czy rozmiaru kodu. (Serializowane dane są takie same w obu przypadkach. Wersja "rozmiar" jest przewidziana dla przypadku, w którym zdefiniowano wiele wiadomości i nie chcesz zabierać dużo pamięci za Kod.)

Jak widzisz, dla mniejszej wiadomości może to być bardzo szybko - ponad 500 małych wiadomości serializowanych lub deserializowanych na milisekundę . Nawet z wiadomością 87K zajmuje mniej niż milisekundę na wiadomość.

 55
Author: Jon Skeet,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-02-05 20:24:27

Jeszcze jeden punkt danych: ten projekt:

Http://code.google.com/p/thrift-protobuf-compare/

Daje pewne wyobrażenie o oczekiwanej wydajności dla małych obiektów, w tym serializacji Javy na PB.

Wyniki różnią się znacznie w zależności od platformy, ale istnieją pewne ogólne trendy.

 14
Author: StaxMan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-03-31 18:17:53

Jeśli mylisz PB i natywną serializację Javy pod względem szybkości i wydajności, po prostu wybierz PB.

  • PB został zaprojektowany, aby osiągnąć takie czynniki. Zobacz http://code.google.com/apis/protocolbuffers/docs/overview.html
  • Dane PB są bardzo małe, podczas gdy serializacja Javy ma tendencję do replikowania całego obiektu, w tym jego sygnatury. Dlaczego zawsze dostaję nazwę mojej klasy, nazwę pola... serializowane, mimo że znam to na wylot w odbiorniku?
  • Think about across rozwój języka. Jest coraz trudniej, jeśli jedna strona używa Javy, a druga C++...

Niektórzy programiści sugerują Thrift, ale ja użyłbym Google PB, bo "wierzę w google": -).. W każdym razie, warto zajrzeć: http://stuartsierra.com/2008/07/10/thrift-vs-protocol-buffers

 6
Author: instcode,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-03-15 17:25:05

Co masz na myśli przez wysoką wydajność? Jeśli chcesz milisekundowej serializacji, sugeruję skorzystanie z podejścia serializacji, które jest najprostsze. Jeśli chcesz sub milisekund, prawdopodobnie potrzebujesz formatu binarnego. Jeśli potrzebujesz znacznie poniżej 10 mikro-sekund, prawdopodobnie będziesz potrzebować niestandardowej serializacji.

Nie widziałem wielu benchmarków dla serializacji / deserializacji, ale kilka obsługuje mniej niż 200 mikro-sekund dla serializacji / deserializacji.

Platforma niezależna formaty są kosztowne (w wysiłku z twojej strony i opóźnienia) być może będziesz musiał zdecydować, czy chcesz wydajności lub niezależności platformy. Nie ma jednak powodu, dla którego nie można mieć obu opcji konfiguracji, które można przełączać w razie potrzeby.

 5
Author: Peter Lawrey,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-03-15 13:53:26

Możesz również spojrzeć na FST , zamiennik wbudowanej serializacji JDK, która powinna być szybsza i mieć mniejszą wydajność.

Surowe szacunki dotyczące częstych benchmarkingu, które zrobiłem w ostatnich latach:

100% = podejścia oparte na binarnych/struct (np. SBE, FST-structs)

  • niewygodne
  • [[9]}postprocessing (budowanie "prawdziwych" obejcts po stronie odbiornika) może pochłonąć zalety wydajności i nigdy nie jest uwzględniany w benchmarki

~10%-35% protobuf & pochodne

~10%-30% szybkie serializery, takie jak FST i KRYO

  • wygodne, deserializowane obiekty mogą być używane najczęściej bezpośrednio bez dodatkowego kodu tłumaczenia ręcznego.
  • może być pimped dla wydajności (adnotacje, Rejestracja klasy)
  • zachowaj linki w grafie obiektu (bez obiektu serializowanego dwa razy)
  • może obsługiwać struktury cykliczne
  • ogólne rozwiązanie, FST jest w pełni kompatybilny z JDK serializacja

~2%-15% serializacja JDK

~1%-15% szybki JSon (np. Jackson)

  • nie może obsługiwać żadnego grafu obiektowego, a jedynie niewielki podzbiór struktur danych Javy
  • no ref

0.001-1% full graph JSon / XML (np. JSON.io)

Te liczby mają dać bardzo szorstki obraz rzędu wielkości. Należy pamiętać, że wydajność zależy w dużej mierze od serializowanych/benchmarkowanych struktur danych. So single simple class benchmarks są w większości bezużyteczne (ale popularne: np. ignorowanie unicode, brak kolekcji,..).

Zobacz też

Http://java-is-the-new-c.blogspot.de/2014/12/a-persistent-keyvalue-server-in-40.html

Http://java-is-the-new-c.blogspot.de/2013/10/still-using-externalizable-to-get.html

 5
Author: R.Moeller,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-05-26 08:10:08

Oto propozycja dnia off the wall: -) (właśnie podkręciłeś coś w mojej głowie, co teraz chcę wypróbować)...

Jeśli możesz przejść do całego rozwiązania buforowania przez to może działać: Project Darkstar . Został zaprojektowany jako bardzo wydajny serwer gier, specjalnie po to, aby odczyty były szybkie (tak dobre dla pamięci podręcznej). Ma Java i C API więc wierzę (myślałem, że dawno na to nie patrzyłem, a wtedy o tym nie myślałem), że można zapisać obiektów z Javą i odczytać je z powrotem w C i odwrotnie.

Jeśli nic więcej to da ci coś do poczytania dzisiaj: -)

 1
Author: TofuBeer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-03-15 15:36:35

W przypadku serializacji przyjaznej przewodowi, rozważ użycie interfejsu zewnetrznego. Sprytnie wykorzystane, będziesz miał intymną wiedzę, aby zdecydować, jak optymalnie marshall i unmarshall konkretnych dziedzinach. To powiedziawszy, będziesz musiał poprawnie zarządzać wersjami każdego obiektu - łatwe do usunięcia, ale ponowne ustawienie obiektu V2, gdy twój kod obsługuje V1, spowoduje złamanie, utratę informacji lub, co gorsza, uszkodzenie danych w sposób, w jaki aplikacje nie są w stanie poprawnie przetworzyć. Jeśli szukasz optymalna ścieżka, uważaj Żadna biblioteka nie rozwiąże Twojego problemu bez kompromisów. Ogólnie biblioteki będą pasować do większości przypadków użycia i będą dostarczane z dodatkową korzyścią, że będą dostosowywać i ulepszać z czasem bez Twojego wkładu, jeśli zdecydowałeś się na aktywny projekt open source. Mogą też dodawać problemy z wydajnością, wprowadzać błędy, a nawet naprawiać błędy, które jeszcze na ciebie nie wpłynęły!

 0
Author: user4992332,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-06-09 21:06:39