Apache Thrift,Google Protocol Buffers,MessagePack,ASN.1和Apache Avro之间的主要区别是什么?

所有这些都提供了二进制序列化,RPC框架和IDL。 我感兴趣的是它们之间的主要区别和特性(性能,易用性,编程语言支持)。

如果您了解其他类似的技术,请在回答中提及。

ASN.1是ISO / ISE标准。 它有一个非常可读的源语言和各种后端,二进制和人类可读。 作为一个国际标准(还有一个老的标准!),源语言有点像厨房一般(与大西洋有点潮湿的方式差不多),但它是非常明确的,并且具有相当数量的支持。 (如果你足够深入的挖掘,你可以find任何你想要的语言的ASN.1库,如果没有的话,你可以在FFI中使用很好的C语言库)。它是一个标准化的语言,有几个很好的教程可用。

节俭不是一个标准。 它最初来自Facebook,后来是开源的,目前是Apache项目的顶层。 它没有很好的文档logging – 特别是教程级别 – 并且对于我的(不言而喻)一目了然,似乎并没有增加任何其他的,以前的努力尚未做(在某些情况下更好)。 为了公平起见,它拥有相当多令人印象深刻的语言,它支持开箱即用,包括一些高调的非主stream语言。 IDL也是模糊的C型。

协议缓冲区不是一个标准。 这是一个Google产品正在向更广泛的社区发布。 在开箱即用的语言方面有一点限制(它只支持C ++,Python和Java),但是对其他语言(高度可变的质量)有很多第三方支持。 Google使用协议缓冲区完成了大部分的工作,所以它是一个经过战斗testing,加强战斗力的协议(虽然不如ASN.1那样具有战斗力,但它比Thrift有更好的文档logging, Google产品很可能会变得不稳定(在不断变化的意义上,而不是不可靠),IDL也是类C的。

上述所有系统都使用某种IDL中定义的模式来生成目标语言的代码,然后将其用于编码和解码。 Avro没有。 Avro的打字是dynamic的,它的模式数据在运行时直接用于编码和解码(这在处理中有一些明显的成本,但是对于dynamic语言还有一些明显的好处,并且不需要标记types等等) 。 它的模式使用JSON,如果已经有一个JSON库,使得支持Avro的新语言更易于pipe理。 同样,与大多数车轮重新发明协议描述系统一样,Avro也没有标准化。

就个人而言,尽pipe我有爱/恨的关系,但是我可能会使用ASN.1来进行大多数RPC和消息传输的目的,尽pipe它没有真正的RPC栈(你必须创build一个,但国际石油公司做到这一点很简单)。

我们刚刚做了一个关于序列化的内部研究,这里有一些结果(为了我未来的参考!)

Thrift =序列化+ RPC堆栈

最大的区别是Thrift不仅仅是一个序列化协议,它是一个完整的RPC栈,就像现代的SOAP栈一样。 所以在序列化之后,对象可以 (但不是强制的)通过TCP / IP在机器之间发送。 在SOAP中,您从一个完整描述可用服务(远程方法)和预期参数/对象的WSDL文档开始。 这些对象是通过XML发送的。 在Thrift中,.thrift文件充分描述了可用的方法,期望的参数对象和对象通过一个可用的序列化器(使用Compact Protocol ,一种高效的二进制协议,在生产中最stream行)序列化。

ASN.1 =大爸爸

ASN.1由80年代的电信人员devise,由于与CompSci人员出现的最近序列化器相比,由于库支持有限,使用起来很尴尬 。 有两种变体,DER(二进制)编码和PEM(ascii)编码。 两者都很快,但DER更快,更有效率的两个。 实际上,ASN.1 DER可以很容易地跟上(有时甚至是打败) 30年后devise的序列化器,这是对它的devise良好的certificate。 它非常紧凑,比Protocol Buffers和Thrift小,只被Avro殴打。 问题是有伟大的图书馆来支持,现在Bouncy Castle似乎是C#/ Java最好的一个。 ASN.1是安全和encryption系统的先驱,不会消失,所以不要担心“未来打样”。 只是得到一个好的图书馆…

MessagePack =包的中间

这并不坏,但它既不是最快的,也不是最小的,也不是最好的支持。 没有生产的理由select它。

共同

除此之外,他们非常相似。 大多数是基本TLV: Type-Length-Value原则。

协议缓冲区(Google发起),Avro(基于Apache,Hadoop中使用),Thrift(Facebook起源,现在是Apache项目)和ASN.1(电信起源)都涉及到一定程度的代码生成,您首先在串行器特定的格式,那么串行器“编译器”将通过代码生成阶段为您的语言生成源代码。 然后,您的应用程序源将这些code-gen类用于IO。 请注意,某些实现(例如:Microsoft的Avro库或Marc Gavel的ProtoBuf.NET)可让您直接装饰应用程序级别的POCO / POJO对象,然后库直接使用这些装饰类而不是任何代码生成的类。 我们已经看到这个提供了一个提升性能,因为它消除了对象复制阶段(从应用程序级POCO / POJO字段到代码生成字段)。

一些结果和一个现场项目玩

这个项目( https://github.com/sidshetye/SerializersCompare )比较了C#世界中的重要序列化器。 爪哇人已经有了类似的东西 。

 1000 iterations per serializer, average times listed Sorting result by size Name Bytes Time (ms) ------------------------------------ Avro (cheating) 133 0.0142 Avro 133 0.0568 Avro MSFT 141 0.0051 Thrift (cheating) 148 0.0069 Thrift 148 0.1470 ProtoBuf 155 0.0077 MessagePack 230 0.0296 ServiceStackJSV 258 0.0159 Json.NET BSON 286 0.0381 ServiceStackJson 290 0.0164 Json.NET 290 0.0333 XmlSerializer 571 0.1025 Binary Formatter 748 0.0344 Options: (T)est, (R)esults, s(O)rt order, (S)erializer output, (D)eserializer output (in JSON form), (E)xit Serialized via ASN.1 DER encoding to 148 bytes in 0.0674ms (hacked experiment!) 

关于ASN.1的一件大事是,这是为规范 devise的, 不是实现。 因此,它非常善于隐藏/忽略任何“真实”编程语言的实现细节。

它是ASN.1-Compiler的工作,将编码规则应用到asn1文件,并从它们两者生成可执行代码。 编码规则可以用EnCoding Notation(ECN)给出,也可以是BER / DER,PER,XER / EXER等标准规范中的一种。 这就是ASN.1的types和结构,编码规则定义了networking编码,最后但并非最不重要的是,编译器将其转换为您的编程语言。

据我所知,免费的编译器支持C,C ++,C#,Java和Erlang。 商业编译器是非常多才多艺的,通常绝对是最新的,有时支持更多的语言,但是看到他们的网站(OSS Nokalva,Marben等)。

使用这种技术指定完全不同的编程文化的各方(例如“embedded式”人员和“服务器农民”)之间的接口是令人惊讶的容易的:asn.1-文件,编码规则,例如BER和例如UML交互图。 无忧如何实施,让大家用“他们的东西”! 对我来说,它工作得很好。 顺便说一句:在OSS Nokalva的网站上,您可能会发现至less两本关于ASN.1的免费下载书籍(Larius和Dubuisson)。

恕我直言,大多数其他产品只是尝试成为另一个RPC-存根发生器,为序列化问题带来了大量的空气。 那么,如果需要的话,可能会很好。 但是对我来说,他们看起来像是对Sun-RPC(从80年代末)的改造,但是,嘿,这也工作得很好。

Uber最近在他们的工程博客上评估了几个这样的库:

https://eng.uber.com/trip-data-squeeze/

他们的赢家? MessagePack + zlib进行压缩

我们的目标是以最快的速度find最紧凑的编码协议和压缩algorithm的组合。 我们testing了来自Uber纽约市的2,219个伪随机匿名旅程的编码协议和压缩algorithm组合(以文本文件JSON的forms)。

这里的教训是,你的要求驱动哪个图书馆适合你。 对于Uber,由于消息传递的无模式性质,他们不能使用基于IDL的协议。 这消除了一堆select。 对于他们来说,不仅仅是原始的编码/解码时间,还有数据的大小。

尺寸结果

尺寸结果

速度结果

在这里输入图像说明

微软的Bond( https://github.com/Microsoft/bond )在性能,function和文档方面都非常出色。 但是,截至目前(2015年12月13日),它不支持许多目标平台。 我只能假设这是因为它是非常新的。 目前它支持python,c#和c ++。 它被无处不在的MS使用。 我试了一下,因为使用bond的ac#开发人员比使用protobuf要好,但是我也使用过节俭,我面临的唯一问题是使用文档,我不得不尝试很多事情来理解事情是如何完成的。

Bond上的资源很less,如下所示( https://news.ycombinator.com/item?id=8866694,https://news.ycombinator.com/item?id=8866848,https://microsoft.github.io/ bond / why_bond.html )

对于性能,一个数据点是jvm-serializers基准testing – 这是非常特定的,小的消息,但是如果你在Java平台上,可能会有所帮助。 我认为一般的performance往往不是最重要的区别。 另外:不要把作者的话作为福音, 很多广告宣称是伪造的(例如msgpack站点有一些可疑的说法;可能速度很快,但是信息很粗略,用例不太现实)。

一个很大的区别是是否必须使用一个模式(PB,至less是Thrift; Avro可能是可选的; ASN.1我也想; MsgPack,不一定)。

另外:在我看来,能够使用分层的模块化devise是很好的; 也就是说,RPC层不应该规定数据格式,序列化。 不幸的是,大多数候选人紧紧捆绑这些

最后,在select数据格式时,现在的性能并不排除使用文本格式。 有快速的JSONparsing器(和快速stream式XMLparsing器); 当考虑脚本语言和易用性的互操作性时,二进制格式和协议可能不是最好的select。