对于一些缓存,我正在考虑为即将到来的项目做的事情,我一直在考虑Java序列化.即,是否应该使用?
现在我已经在过去几年中出于各种原因编写了自定义序列化和反序列化(Externalizable).目前互操作性已成为一个问题,我可以预见需要与.Net应用程序进行交互,因此我想到了使用独立于平台的解决方案.
有没有人有过使用GPB的高性能经验?它在速度和效率方面与Java的本机序列化相比如何?或者,还有其他值得考虑的方案吗?
我没有在协议速度方面将Protocol Buffers与Java的本机序列化进行比较,但是为了实现互操作性,Java的本机序列化是一个严肃的禁忌.在大多数情况下,它在空间方面也不会像协议缓冲区那样高效.当然,就它可以存储的内容以及参考等方面来说,它更灵活一些.协议缓冲区非常擅长它的目的,当它满足你的需求它很棒 - 但是由于互操作性有明显的限制(和其他东西).
我最近在Java和.NET中发布了一个Protocol Buffers基准测试框架.Java版本位于Google主项目中(在基准测试目录中),.NET版本位于我的C#端口项目中.如果你想比较PB速度和Java序列化速度,你可以编写类似的类并对它们进行基准测试.如果您对interop感兴趣,我真的不会再考虑本机Java序列化(或.NET本机二进制序列化).
除了协议缓冲区之外,还有其他可互操作的序列化选项 - Thrift,JSON和YAML会让人想起,而且其他人无疑也会如此.
编辑:好的,因为互操作不是那么重要,所以值得尝试从序列化框架中列出您想要的不同质量.您应该考虑的一件事是版本控制 - 这是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消息,每条消息的消息也不到一毫秒.
还有一个数据点:这个项目:
http://code.google.com/p/thrift-protobuf-compare/
给出了小对象的预期性能的一些概念,包括PB上的Java序列化.
根据您的平台,结果差异很大,但有一些一般趋势.
您还可以查看FST,它是内置JDK序列化的直接替代品,它应该更快并且输出更小.
我近几年经常进行的基准测试的原始估计:
100%=基于二进制/结构的方法(例如SBE,fst-structs)
不方便
后处理(在接收方建立"真正的"对象)可能会消耗性能优势,并且从未包含在基准测试中
~10%-35%的protobuf和衍生物
~10%-30%快速序列化器,如FST和KRYO
方便的,反序列化的对象最常使用,无需额外的手动翻译代码.
可以拉皮条表演(注释,课程注册)
保留对象图中的链接(没有对象序列化两次)
可以处理循环结构
通用解决方案,FST与JDK序列化完全兼容
~2%-15%JDK序列化
〜1%-15%快速JSon(例如杰克逊)
不能处理任何对象图,但只能处理一小部分java数据结构
没有ref恢复
0.001-1%完整图形JSon/XML(例如JSON.io)
这些数字旨在给出非常粗略的数量级印象.请注意,性能取决于要序列化/基准测试的数据结构.所以单个简单类基准测试大多没用(但很流行:例如忽略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
如果你在速度和效率方面混淆PB和本机java序列化,那就去PB吧.
PB旨在实现这些因素.请参阅http://code.google.com/apis/protocolbuffers/docs/overview.html
PB数据非常小,而java序列化往往会复制整个对象,包括其签名.为什么我总是得到我的班级名称,字段名称...序列化,即使我知道它在接收器里面?
考虑跨语言发展.如果一方使用Java,一方使用C++会变得越来越难......
一些开发人员建议使用Thrift,但我会使用Google PB,因为"我相信谷歌":-) ..无论如何,它值得一看:http: //stuartsierra.com/2008/07/10/thrift-vs-protocol -buffers
高性能意味着什么?如果你想要毫秒级序列化,我建议你使用最简单的序列化方法.如果您想要亚毫秒,则可能需要二进制格式.如果您想要低于10微秒,则可能需要自定义序列化.
我没有看到许多序列化/反序列化的基准测试,但很少支持序列化/反序列化的200微秒.
独立于平台的格式需要付出代价(在您的努力和延迟上),您可能需要决定是否需要性能或平台独立性.但是,没有理由不能将两者都作为配置选项,您可以根据需要切换.