Высокопроизводительная сериализация: Java vs Google Protocol Buffers vs...?

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

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

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

44
задан 15 марта '09 в 16:00
источник поделиться
7 ответов

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

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

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

EDIT: Ладно, если interop не так важен, стоит попытаться перечислить различные качества, которые вы хотите, из рамки сериализации. Одна вещь, о которой вы должны подумать, это управление версиями - это еще одна вещь, которую PB предназначен для хорошей обработки, как назад, так и вперед (так что новое программное обеспечение может читать старые данные и наоборот) - когда вы придерживаетесь предложенных правил, конечно:)

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

Как примерные показатели производительности, сериализация и десериализация двух сообщений (один 228 байт, один 84750 байт), я получил эти результаты на своем ноутбуке с использованием 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 

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

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

55
ответ дан 15 марта '09 в 16:16
источник

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

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

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

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

14
ответ дан 31 марта '09 в 21:17
источник

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

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

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

6
ответ дан 15 марта '09 в 20:25
источник

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

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

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

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

~ 10% -35% protobuf и производные

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

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

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

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

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

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

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

см. также

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
ответ дан 07 дек. '12 в 1:17
источник

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

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

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

5
ответ дан 15 марта '09 в 16:53
источник

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

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

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

1
ответ дан 15 марта '09 в 18:36
источник

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

0
ответ дан 10 июня '15 в 0:06
источник

Другие вопросы по меткам или Задайте вопрос