Высокопроизводительная сериализация:Java против буферов протокола Google против…?

StackOverflow https://stackoverflow.com/questions/647779

Вопрос

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

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

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

Это было полезно?

Решение

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

Недавно я опубликовал инфраструктуру тестирования протоколов в Java и .NET. Версия Java находится в главном проекте Google каталог тестов ), версия .NET находится в мой проект порта C # . Если вы хотите сравнить скорость 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 на сообщение уходит меньше миллисекунды.

Другие советы

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

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

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

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

Вы также можете посмотреть ФСТ, замена встроенной сериализации JDK, которая должна быть быстрее и иметь меньший результат.

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

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

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

~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/a-persistent-keyvalue-server-in-40.html

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

Если вы путаете между PB и собственной сериализацией Java по скорости и эффективности, просто выберите 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

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

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

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

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

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

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top