粉丝服务

[新文导读] Protobuf到底比JSON快几倍?全方位实测!

一、引言

本系列的前几篇主要是从各个角度讲解Protobuf的基本概念、技术原理这些内容,但回过头来看,对比JSON这种事实上的数据协议工业标准,Protobuf到底性能到底高多少?

本篇将以Protobuf为基准,对比市面上的一些主流的JSON解析库,通过全方位测试来证明给你看看Protobuf到底比JSON快几倍。

二、本文目录

1)前言
2)系列文章
3)写在前面
4)本次评测对象
5)整数解码性能测试(Decode Integer)
6)整数编码性能测试(Encode Integer)
7)双精度浮点数解码性能测试(Decode Double)
8)双精度浮点数编码性能测试(Encode Double)
9)对象解码性能测试(Decode Object)
10)对象编码性能测试(Encode Object)
11)整形列表解码性能测试(Decode Integer List)
12)整形列表编码性能测试(Encode Integer List)
13)对象列表解码性能测试(Decode Object List)
14)对象列表编码性能测试(Encode Object List)
15)双精度浮点数数组解码性能测试(Decode Double Array)
16)双精度浮点数数组编码性能测试(Encode Double Array)
17)字符串解码性能测试(Decode String)
18)字符串编码性能测试(Encode String)
19)本文总结
20)参考资料

三、系列文章

本文是系列文章中的第 4 篇,本系列总目录如下:

四、写在前面

拿 JSON 衬托 Protobuf 的文章真的太多了,经常可以看到文章中写道:“快来用 Protobuf 吧,JSON 太慢啦”。

但是 Protobuf 真的有吹的那么牛么?

我觉得从 JSON 切换到 Protobuf 怎么也得快一倍吧,要不然对不起付出的切换成本。然而,DSL-JSON 的家伙们居然说在Java语言里 JSON 和那些二进制的编解码格式有得一拼,这太让人惊讶了!

虽然你可能会说,咱们能不用苹果和梨来做比较了么?两个东西根本用途完全不一样好么。咱们用 Protobuf 是冲着跨语言无歧义的 IDL 的去的,才不仅仅是因为性能呢。好吧,这个我同意。但是仍然有那么多人盲目相信,Protobuf 一定会快很多,我觉得还是有必要彻底终结一下这个关于速度的传说。

DSL-JSON 的博客里只给了他们的测试结论,但是没有给出任何原因,以及优化的细节,这很难让人信服数据是真实的。你要说 JSON 比二进制格式更快,真的是很反直觉的事情。

稍微琢磨一下这个问题,就可以列出好几个 Protobuf 应该更快的理由。

比如:

  • 1)更容容易绑定值到对象的字段上。JSON 的字段是用字符串指定的,相比之下字符串比对应该比基于数字的字段tag更耗时;

  • 2)JSON 是文本的格式,整数和浮点数应该更占空间而且更费时;

  • 3)Protobuf 在正文前有一个大小或者长度的标记,而 JSON 必须全文扫描无法跳过不需要的字段。


但是仅凭这几点是不是就可以盖棺定论了呢?未必。

也有相反的观点:

  • 1)如果字段大部分是字符串,占到决定性因素的因素可能是字符串拷贝的速度,而不是解析的速度。在这个评测中,我们看到不少库的性能是非常接近的。这是因为测试数据中大部分是由字符串构成的;

  • 2)影响解析速度的决定性因素是分支的数量。因为分支的存在,解析仍然是一个本质上串行的过程。虽然Protobuf里没有[] 或者 {},但是仍然有类似的分支代码的存在。如果没有这些分支的存在,解析不过就是一个 memcpy 的操作而已。只有 Parabix 这样的技术才有革命性的意义,而 Protobuf 相比 JSON 只是改良而非革命;

  • 3)也许 Protobuf 是一个理论上更快的格式,但是实现它的库并不一定就更快。这取决于优化做得好不好,如果有不必要的内存分配或者重复读取,实际的速度未必就快。


有多个 benchmark 都把 DSL-JSON列到前三名里,有时甚至比其他的二进制编码更快。

经过我仔细分析,原因出在了这些 benchmark 对于测试数据的构成选择上。

因为构造测试数据很麻烦,所以一般评测只会对相同的测试数据,去测不同的库的实现。

这样就使得结果是严重倾向于某种类型输入的。

比如 https://github.com/eishay/jvm-serializers/wiki 选择的测试数据的结构是这样的:

01020304050607080910111213141516171819202122232425262728293031323334message Image {  required string uri = 1;      //url to the thumbnail  optional string title = 2;    //used in the html ALT  required int32 width = 3;     // of the image  required int32 height = 4;    // of the image  enum Size {    SMALL = 0;    LARGE = 1;  }  required Size size = 5;       // of the image (in relative terms, provided by cnbc for example)} message Media {  required string uri = 1;      //uri to the video, may not be an actual URL  optional string title = 2;    //used in the html ALT  required int32 width = 3;     // of the video  required int32 height = 4;    // of the video  required string format = 5;   //avi, jpg, youtube, cnbc, audio/mpeg formats ...  required int64 duration = 6;  //time in miliseconds  required int64 size = 7;      //file size  optional int32 bitrate = 8;   //video  repeated string person = 9;   //name of a person featured in the video  enum Player {    JAVA = 0;    FLASH = 1;  }  required Player player = 10;   //in case of a player specific media  optional string copyright = 11;//media copyright} message MediaContent {  repeated Image image = 1;  required Media media = 2;}


无论怎么去构造 small/medium/large 的输入,benchmark 仍然是存在特定倾向性的。

而且这种倾向性是不明确的。比如 medium 的输入,到底说明了什么?medium 对于不同的人来说,可能意味着完全不同的东西。

所以,在这里我想改变一下游戏的规则。不去选择一个所谓的最现实的配比,而是构造一些极端的情况。

这样,我们可以一目了然的知道,JSON的强项和弱点都是什么。通过把这些缺陷放大出来,我们也就可以对最坏的情况有一个清晰的预期。具体在你的场景下性能差距是怎样的一个区间内,也可以大概预估出来。

五、本次评对象

好了,废话不多说了,JMH 撸起来。

benchmark 的对象有以下几个:

  • 1)Jackson:Java 程序里用的最多的 JSON 解析器。benchmark 中开启了 AfterBurner 的加速特性;

  • 2)DSL-JSON:世界上最快的 Java JSON 实现;

  • 3)Jsoniter:抄袭 DSL-JSON 写的实现;

  • 4)Fastjson:在中国很流行的 JSON 解析器;

  • 5)Protobuf:在 RPC (远程方法调用)里非常流行的二进制编解码格式;

  • 6)Thrift:另外一个很流行的 RPC 编解码格式。这里 benchmark 的是 TCompactProtocol。

六、参考资料

[1] Protobuf从入门到精通,一篇就够!

http://www.52im.net/thread-4080-1-1.html

[2] 如何选择即时通讯应用的数据传输格式

http://www.52im.net/thread-276-1-1.html

[3] 强列建议将Protobuf作为你的即时通讯应用数据传输格式

http://www.52im.net/thread-277-1-1.html

[4] APP与后台通信数据格式的演进:从文本协议到二进制协议

http://www.52im.net/thread-1536-1-1.html

[5] 面试必考,史上最通俗大小端字节序详解

http://www.52im.net/thread-3101-1-1.html

[6] 移动端IM开发需要面对的技术问题(含通信协议选择)

http://www.52im.net/thread-133-1-1.html

[7] 简述移动端IM开发的那些坑:架构设计、通信协议和客户端

http://www.52im.net/thread-289-1-1.html

[8] 理论联系实际:一套典型的IM通信协议设计详解

http://www.52im.net/thread-283-1-1.html

[9] 58到家实时消息系统的协议设计等技术实践分享

http://www.52im.net/thread-298-1-1.html


七、全文链接

即时通讯网(52im.net)社区链接:http://www.52im.net/thread-4095-1-1.html,或点击下文的“阅读原文”!



本栏目精选

热门推荐

频道导航