对于我正在考虑为即将到来的项目做的一些缓存,我一直在考虑 Java 序列化。也就是说,应该使用它吗?

现在,我在过去几年中出于各种原因编写了自定义序列化和反序列化(Externalized)。如今,互操作性已变得更加成为一个问题,我可以预见需要与 .Net 应用程序交互,因此我考虑使用独立于平台的解决方案。

有人有过GPB高性能使用的经验吗?与 Java 的原生序列化相比,它的速度和效率如何?或者,还有其他值得考虑的方案吗?

有帮助吗?

解决方案

我没有将 Protocol Buffers 与 Java 的本机序列化在速度方面进行比较,但对于互操作性来说,Java 的本机序列化是一个严重的禁忌。在大多数情况下,它在空间方面也不会像协议缓冲区那样高效。当然,它在存储内容和引用等方面更加灵活。Protocol Buffers 非常擅长它的用途,当它满足您的需求时它就很棒 - 但由于互操作性(和其他因素)而存在明显的限制。

我最近发布了 Java 和 .NET 中的 Protocol Buffers 基准测试框架。Java 版本位于 谷歌主要项目 (在里面 基准测试目录),.NET 版本位于 我的 C# 端口项目. 。如果您想将 PB 速度与 Java 序列化速度进行比较,您可以编写类似的类并对它们进行基准测试。如果您对互操作感兴趣,我真的不会再考虑本机 Java 序列化(或 .NET 本机二进制序列化)。

除了协议缓冲区之外,还有其他可互操作序列化的选项 - 节约, JSONYAML 我想到了,毫无疑问还有其他的。

编辑:好吧,由于互操作并不是那么重要,因此值得尝试列出您想要从序列化框架中获得的不同品质。你应该考虑的一件事是版本控制 - 这是 PB 旨在处理好向后和向前的另一件事(因此新软件可以读取旧数据,反之亦然) - 当然,当你坚持建议的规则时:)

在尝试对 Java 性能与本机序列化保持谨慎之后,我真的不会惊讶地发现 PB 更快。如果有机会,请使用服务器虚拟机 - 我最近的基准测试显示服务器虚拟机是 速度快两倍以上 在序列化和反序列化示例数据时。我认为 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 

“速度”与“大小”是生成的代码是否针对速度或代码大小进行了优化。(两种情况下序列化的数据是相同的。“size”版本是为您定义了很多消息并且不想为代码占用大量内存的情况提供的。)

正如您所看到的,对于较小的消息,它可以是 非常 快速 - 超过 500 条小消息被序列化或反序列化 每毫秒. 。即使使用 87K 消息,每条消息花费的时间也不到一毫秒。

其他提示

一个或多个数据点:该项目:

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

给出了小物件,包括关于PB Java序列预期性能的一些想法。

结果根据您的平台上有很大的差异,但也有一些普遍的趋势。

您可能还可以看看 FST, ,内置 JDK 序列化的直接替代品,它应该更快并且输出更小。

对我近年来所做的频繁基准测试的原始估计:

100% = 基于二进制/结构的方法(例如SBE,第一结构)

  • 不方便
  • 后处理(在接收器端构建“真实”对象)可能会消耗性能优势,并且永远不会包含在基准测试中

~10%-35% protobuf 及衍生物

~10%-30% 快速序列化器,例如 FST 和 KRYO

  • 方便,反序列化的对象可以直接使用,无需额外的手动翻译代码。
  • 可以拉皮条以提高性能(注释、类注册)
  • 保留对象图中的链接(没有对象序列化两次)
  • 可以处理循环结构
  • 通用解决方案,FST完全兼容JDK序列化

~2%-15% JDK 序列化

~1%-15% 快的 JSon(例如杰克逊)

  • 无法处理任何对象图,但只能处理 Java 数据结构的一小部分
  • 没有参考恢复

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,因为“我相信 google”:-)..不管怎样,还是值得一看的:http://stuartsierra.com/2008/07/10/thrift-vs-protocol-buffers

你这是什么意思的高性能?如果你想毫秒的系列化,我建议你使用序列化的做法,是最简单的。如果你想分毫秒的你很可能需要一个二进制格式。如果你想远低于10微秒,你很可能需要一个自定义序列化。

我还没有看到序列化/反序列化,但很少支持小于200微秒序列化/反序列化许多基准。

独立于平台的格式是有代价的(在努力对您的部分和延迟),您可能需要决定是否要性能还是平台独立性。然而,没有理由不能兼得作为你需要之间切换的配置选项。

下面是新的一天:-)壁建议(你刚刚调整了在我的头上的东西,我现在想尝试)...

如果你可以通过这个去整个缓存解决方案,它可能工作: Darkstar项目。它被设计成非常高性能的游戏服务器,特别是使读取速度快(所以缓存好)。它有Java和C的API,所以我相信(认为它已经很长一段时间,因为我看着它,我没有想到这个当时的),你可以保存Java对象和读取回用C,反之亦然。

如果没有别的它会给你的东西今天读了起来: - )

有关电线友好系列化,可以考虑使用Externalizable接口。巧妙运用,你就会有亲密knowlege决定如何以最佳方式编组和解组特定的领域。这就是说,你需要管理的每一个正确的对象版本 - 易非马歇尔,但重新编组一个V2对象时,你的代码支持的方式V1要么休息,丢失信息,或者更糟损坏数据的应用不能够正确地处理。如果你正在寻找一个最优路径,谨防没有库将解决你的问题,而一些妥协。一般来说图书馆将适合大多数使用情况,并会与他们就没有你输入一段时间适应和提高,如果你选择了一个活跃的开源项目的好处。他们可能会增加性能问题,引入错误,甚至修复并没有影响你的呢错误!

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top