Высокопроизводительная сериализация: Java против буферов протокола Google против ...? - PullRequest
50 голосов
/ 15 марта 2009

Для некоторого кеширования, которое я думаю сделать для будущего проекта, я думал о сериализации Java. А именно, стоит ли его использовать?

Теперь я ранее писал собственные сериализацию и десериализацию (Externalizable) по разным причинам в прошлые годы. В наши дни совместимость стала еще более серьезной проблемой, и я могу предвидеть необходимость взаимодействия с приложениями .Net, поэтому я подумал об использовании независимого от платформы решения.

Кто-нибудь имел опыт высокопроизводительного использования GPB? Как это соотносится с точки зрения скорости и эффективности с собственной сериализацией Java? В качестве альтернативы, есть ли другие схемы, которые стоит рассмотреть?

Ответы [ 7 ]

58 голосов
/ 15 марта 2009

Я не сравнивал буферы протокола с собственной сериализацией Java с точки зрения скорости, но для совместимости собственная сериализация Java - серьезное нет-нет. В большинстве случаев он также не будет столь же эффективным с точки зрения пространства, как буферные протоколы. Конечно, он несколько более гибкий с точки зрения того, что он может хранить, а также с точки зрения ссылок и т. Д. Протоколные буферы очень хороши для того, для чего они предназначены, и когда они соответствуют вашим потребностям, это здорово - но есть очевидные ограничения из-за взаимодействия (и другие вещи).

Недавно я опубликовал инфраструктуру тестирования протоколов в Java и .NET. Версия Java находится в основном проекте Google (в каталоге тестов ), версия .NET находится в моем проекте C # port . Если вы хотите сравнить скорость PB со скоростью сериализации Java, вы можете написать схожие классы и сравнить их. Однако, если вы заинтересованы во взаимодействии, я бы не стал задумываться о нативной сериализации Java (или нативной двоичной сериализации .NET).

Существуют и другие опции для совместимой сериализации, кроме буферов протокола - Thrift , JSON и YAML приходят на ум, и есть, несомненно, другие.

РЕДАКТИРОВАТЬ: Хорошо, поскольку взаимодействие не так важно, стоит попытаться перечислить различные качества, которые вы хотите из среды сериализации. Одна вещь, о которой вы должны подумать - это управление версиями - это еще одна вещь, которую PB спроектировал так, чтобы хорошо справляться как в обратном, так и в обратном направлении (чтобы новое программное обеспечение могло считывать старые данные и наоборот) - конечно, когда вы придерживаетесь предложенных правил :)

Пытаясь быть осторожным относительно производительности Java по сравнению с нативной сериализацией, я действительно не удивлюсь, обнаружив, что PB все равно быстрее. Если у вас есть возможность, используйте сервер vm - мои последние тесты показали, что виртуальная машина сервера была в два раза быстрее при сериализации и десериализации данных примера. Я думаю, что код PB очень хорошо подходит для JIT виртуальной машины сервера:)

Так же, как примеры показателей производительности, сериализации и десериализации двух сообщений (одно 228 байтов, одно 84750 байтов), я получил эти результаты на своем ноутбуке с использованием виртуальной машины сервера:

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 

«Скорость» против «размера» - это оптимизированный сгенерированный код для скорости или размера кода. (Сериализованные данные одинаковы в обоих случаях. Версия "size" предоставляется для случая, когда вы определили много сообщений и не хотите занимать много памяти для кода.)

Как видите, для меньшего сообщения оно может быть очень быстрым - более 500 небольших сообщений сериализуются или десериализуются в миллисекунду . Даже с сообщением 87K на сообщение уходит менее миллисекунды.

15 голосов
/ 31 марта 2009

Еще одна точка данных: этот проект:

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

дает некоторое представление об ожидаемой производительности для небольших объектов, включая сериализацию Java на PB.

Результаты сильно различаются в зависимости от вашей платформы, но есть некоторые общие тенденции.

8 голосов
/ 07 декабря 2012

Вы также можете взглянуть на FST , заменяющую встроенную сериализацию JDK, которая должна быть быстрее и иметь меньшую производительность.

приблизительные оценки по частым сравнительным тестам, которые я проводил в последние годы:

100% = бинарные / структурные подходы (например, SBE, fst-structs)

  • 1010 * неудобные *
  • постобработка (создание «настоящих» объектов на стороне получателя) может привести к снижению производительности и никогда не включается в тесты

~ 10% -35% простейших и производных

~ 10% -30% быстрых сериализаторов, таких как FST и KRYO

  • удобные десериализованные объекты могут использоваться чаще всего напрямую без дополнительного кода ручного перевода.
  • может быть увеличено для производительности (аннотации, регистрация класса)
  • сохранить ссылки в графе объектов (объект не сериализуется дважды)
  • может обрабатывать циклические структуры
  • универсальное решение, FST полностью совместимо с сериализацией JDK

~ 2% -15% сериализации JDK

~ 1% -15% быстро JSon (например, Джексон)

  • не может обрабатывать любой граф объектов, но только небольшое подмножество структур данных Java
  • ссылка не восстанавливается

0,001-1% полного графика JSon / XML (например, JSON.io)

Эти числа предназначены для получения очень грубого впечатления порядка величины. Обратите внимание, что производительность зависит от множества структур данных, которые сериализуются / сравниваются. Поэтому одиночные простые тесты классов в основном бесполезны (но популярны: например, игнорирование юникода, никаких коллекций, ..).

см. Также

http://java -is-the-new-c.blogspot.de / 2014/12 / а-стойкие-KeyValue-сервер-в-40.html * * +1050

http://java -is-the-new-c.blogspot.de / 2013/10 / все еще используя-Externalizable к get.html

6 голосов
/ 15 марта 2009

Если вы путаетесь между PB и нативной сериализацией Java по скорости и эффективности, просто перейдите на PB.

  • PB был разработан для достижения таких факторов. Смотри http://code.google.com/apis/protocolbuffers/docs/overview.html
  • Данные PB очень малы, в то время как сериализация Java имеет тенденцию копировать весь объект, включая его подпись. Почему я всегда получаю имя моего класса, имя поля ... сериализованным, даже если я знаю его на приемнике?
  • Подумайте о развитии языка. Становится трудно, если одна сторона использует Java, другая - C ++ ...

Некоторые разработчики предлагают Thrift, но я бы использовал Google PB, потому что «Я верю в Google» :-) .. В любом случае, стоит взглянуть: http://stuartsierra.com/2008/07/10/thrift-vs-protocol-buffers

5 голосов
/ 15 марта 2009

Что вы подразумеваете под высокой производительностью? Если вы хотите сериализацию в миллисекунды, я предлагаю вам использовать самый простой подход к сериализации. Если вы хотите меньше миллисекунды, вам, вероятно, понадобится двоичный формат. Если вы хотите намного меньше 10 микросекунд, вам, вероятно, понадобится настраиваемая сериализация.

Я не видел много тестов для сериализации / десериализации, но немногие поддерживают сериализацию / десериализацию менее 200 микросекунд.

Форматы, независимые от платформы, стоят дорого (в зависимости от ваших усилий и задержки), вам, возможно, придется решить, хотите ли вы производительность или независимость от платформы. Тем не менее, нет никаких причин, по которым вы не можете использовать оба варианта конфигурации, если вы переключаетесь между ними по мере необходимости.

1 голос
/ 15 марта 2009

Вот внушительное предложение дня :-) (вы только что подправили что-то в моей голове, что я теперь хочу попробовать) ...

Если вы можете использовать целое решение для кэширования, это может сработать: Project Darkstar . Он спроектирован как очень высокопроизводительный игровой сервер, особенно для быстрого чтения (что хорошо для кэша). У него есть Java и C API, поэтому я считаю (я думал, что прошло много времени с тех пор, как я на это смотрел, и я не думал об этом), что вы можете сохранять объекты с Java и читать их обратно в C и наоборот.

Если ничего другого, это даст вам кое-что для чтения сегодня: -)

0 голосов
/ 10 июня 2015

Для проводной дружественной сериализации рассмотрите возможность использования интерфейса Externalizable. При умном использовании вы будете иметь глубокие знания, чтобы решить, как оптимально маршалировать и демаршировать определенные поля. Тем не менее, вам нужно будет правильно управлять версиями каждого объекта - легко маршалировать, но повторная маршализация объекта V2, когда ваш код поддерживает V1, приведет к повреждению, потере информации или ухудшению поврежденных данных, как ваши приложения. не в состоянии правильно обрабатывать. Если вы ищете оптимальный путь, будьте осторожны, никакая библиотека не решит вашу проблему без каких-либо компромиссов. Как правило, библиотеки будут соответствовать большинству сценариев использования и будут иметь дополнительное преимущество, заключающееся в том, что они будут адаптироваться и улучшаться со временем без вашего участия, если вы выбрали активный проект с открытым исходным кодом. И они могут добавлять проблемы с производительностью, вносить ошибки и даже исправлять ошибки, которые еще не затронули вас!

...