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

Posted

技术标签:

【中文标题】Apache Thrift、Google Protocol Buffers、MessagePack、ASN.1 和 Apache Avro 之间的主要区别是啥?【英文标题】:What are the key differences between Apache Thrift, Google Protocol Buffers, MessagePack, ASN.1 and Apache Avro?Apache Thrift、Google Protocol Buffers、MessagePack、ASN.1 和 Apache Avro 之间的主要区别是什么? 【发布时间】:2011-06-05 17:43:44 【问题描述】:

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

如果您知道任何其他类似的技术,请在回答中提及。

【问题讨论】:

en.wikipedia.org/wiki/Comparison_of_data_serialization_formats @Zenikoder:该链接没有 5 种查询格式中的 2 种的任何信息。 能帮忙吗:slideshare.net/IgorAnishchenko/pb-vs-thrift-vs-avro ? 对于那些不了解 RPC - Remote Prodecure Call, IDL - 接口定义语言的人 【参考方案1】:

ASN.1 是 ISO/ISE 标准。它具有非常易读的源语言和各种后端,包括二进制和人类可读的。作为一个国际标准(而且是一个旧标准!)源语言有点厨房(就像大西洋有点潮湿一样),但它的规范非常好并且有相当多的支持. (如果您足够努力地挖掘,您可能会为您命名的任何语言找到一个 ASN.1 库,如果没有的话,您可以在 FFI 中使用好的 C 语言库。)它是一种标准化语言,有着令人着迷的文档和还有一些很好的教程。

节俭不是标准。它最初来自 Facebook,后来开源,目前是*** Apache 项目。它没有很好的文档记录——尤其是教程级别——而且在我(诚然简短的)一眼看来,它似乎没有添加任何其他以前的努力还没有做的事情(在某些情况下更好)。公平地说,它开箱即用地支持的语言数量相当可观,包括一些知名度较高的非主流语言。 IDL 也隐约类似于 C。

Protocol Buffers 不是标准。这是一个正在向更广泛的社区发布的 Google 产品。它在开箱即用支持的语言方面有点有限(它只支持 C++、Python 和 Java),但它确实有很多第三方对其他语言的支持(质量参差不齐)。 Google 几乎所有的工作都使用 Protocol Buffers,所以它是一个经过实战考验、久经考验的协议(尽管不像 ASN.1 那样久经沙场。它的文档比 Thrift 好得多,但是,作为一个Google 产品,极有可能是不稳定的(在不断变化的意义上,而不是在不可靠的意义上)。IDL 也是类 C 的。

上述所有系统都使用某种 IDL 中定义的模式来生成目标语言的代码,然后用于编码和解码。 Avro 没有。 Avro 的类型是动态的,它的模式数据在运行时直接用于编码和解码(这在处理上有一些明显的成本,但相对于动态语言和不需要标记类型等也有一些明显的好处) .它的模式使用 JSON,如果已经有 JSON 库,这使得用新语言支持 Avro 更容易管理。同样,与大多数***改造协议描述系统一样,Avro 也没有标准化。

就个人而言,尽管我对它又爱又恨,但我可能会将 ASN.1 用于大多数 RPC 和消息传输目的,尽管它实际上并没有 RPC 堆栈(你必须制作一个,但是IOC 让这一切变得非常简单)。

【讨论】:

感谢您的详细解释。但是版本控制呢,我听说 protobuf 可以处理它,其他库呢,它是如何通用的呢?此外,除了 JSON 之外,Avro 现在似乎还具有类似 C 语法的 IDL。 ASN.1 支持通过 ... 扩展标记进行手动版本控制,或通过模块标题中的 EXTENSIBILITY IMPLIED 自动进行版本控制。协议缓冲区,IIRC,支持手动版本控制。我不知道它是否支持诸如隐含可扩展性之类的东西(而且我懒得去查找它)。 Thrift 还支持一些版本控制,但我还是觉得它是一个手动过程,没有隐含的可扩展性。 为了记录,Protocol Buffers 总是通过数字显式编码字段,如果有额外的字段,在库级别永远不会出错,如果它们被标记为可选或缺少的字段,则不会出错明确的。因此所有协议缓冲区消息都有EXTENSIBILITY IMPLIED 国际奥委会 - 你的意思是控制反转? php 中的 RPC 堆栈有什么用途,比如 XML-RPC 扩展?还是必须自己写一些东西? Avro 更加灵活,因为它允许在定义的模式上动态工作,或者生成样板类。根据我的经验,它非常强大:它的优势在于其丰富的功能集,包括 RPC 生成器(这是 Thrift 的常见功能)。【参考方案2】:

就性能而言,一个数据点是jvm-serializers 基准测试——它非常具体,消息很少,但如果您使用的是 Java 平台,可能会有所帮助。我认为总的来说,性能通常不是最重要的区别。另外:永远不要把作者的话当成福音;许多广告声明都是虚假的(例如 msgpack 网站有一些可疑的声明;它可能很快,但信息非常粗略,用例不太现实)。

一个很大的区别是是否必须使用架构(至少是 PB,Thrift;Avro 可能是可选的;我认为也是 ASN.1;MsgPack,不一定)。

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

最后,在选择数据格式时,如今的性能并不排除使用文本格式。有超快的 JSON 解析器(和非常快的流式 xml 解析器);在考虑脚本语言的互操作性和易用性时,二进制格式和协议可能不是最佳选择。

【讨论】:

感谢您分享经验,但我认为我仍然需要二进制格式(我有非常大量的数据)并且可能会坚持使用 Avro。 是的,那可能是有道理的。无论使用何种格式,您都可能希望以任何速率使用压缩(LZF 很好,因为与 gzip/deflate 相比,它的压缩/解压缩速度非常快)。【参考方案3】:

ASN.1 的一大特点是,它是为 规范 而不是实现而设计的。因此,它非常擅长隐藏/忽略任何“真实”编程语言中的实现细节。

ASN.1-Compiler 的工作是将编码规则应用于 asn1 文件并从它们两者中生成可执行代码。编码规则可能以编码表示法 (ECN) 给出,也可能是标准化规则之一,例如 BER/DER、PER、XER/EXER。 那就是 ASN.1 是类型和结构,编码规则定义在线编码,最后但并非最不重要的是编译器将其传输到您的编程语言。

据我所知,免费的编译器支持 C、C++、C#、Java 和 Erlang。 (非常昂贵和专利/许可证缠身)商业编译器非常通用,通常绝对是最新的,有时甚至支持更多语言,但请参阅他们的网站(OSS Nokalva、Marben 等)。

使用这种技术在完全不同的编程文化的各方(例如“嵌入式”人员和“服务器农民”)之间指定一个接口非常容易:一个 asn.1 文件,编码规则,例如BER 和例如UML 交互图。不用担心它是如何实现的,让每个人都使用“他们的东西”!对我来说,它运作良好。 顺便说一句:在 OSS Nokalva 的网站上,您可以找到至少两本关于 ASN.1 的免费下载书籍(一本由 Larmouth 撰写,另一本由 Dubuisson 撰写)。

恕我直言,大多数其他产品只是尝试成为又一个 RPC 存根生成器,为序列化问题注入了大量空气。好吧,如果有人需要,那可能就可以了。但对我来说,它们看起来像是对 Sun-RPC(从 80 世纪后期开始)的改造,但是,嘿,它也很好用。

【讨论】:

【参考方案4】:

我们刚刚对序列化器进行了内部研究,以下是一些结果(也供我将来参考!)

Thrift = 序列化 + RPC 堆栈

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

ASN.1 = 爷爷

ASN.1 是由电信人员在 80 年代设计的,与 CompSci 人员最近出现的序列化程序相比,由于库支持有限,使用起来尴尬。有两种变体,DER(二进制)编码和 PEM(ascii)编码。两者都很快,但 DER 速度更快,并且两者的尺寸效率更高。事实上,ASN.1 DER 可以轻松地跟上(有时甚至击败)在其设计之后 30 年 设计的序列化程序,这证明了它的精心设计的设计。它非常紧凑,比 Protocol Buffers 和 Thrift 更小,仅被 Avro 击败。问题在于有很好的库需要支持,现在 Bouncy Castle 似乎是 C#/Java 最好的库。 ASN.1 是安全和加密系统的王者,不会消失,所以不要担心“未来的证明”。找个好图书馆就好了……

MessagePack = 中间包

它还不错,但它既不是最快的,也不是最小的,也不是最好的支持。没有生产理由选择它。

常见

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

Protocol Buffers(源自 Google)、Avro(基于 Apache,用于 Hadoop)、Thrift(源自 Facebook,现在是 Apache 项目)和 ASN.1(源自电信)都涉及某种级别的代码生成,您首先在其中表达数据以特定于序列化程序的格式,然后序列化程序“编译器”将通过code-gen 阶段为您的语言生成源代码。然后,您的应用程序源将这些 code-gen 类用于 IO。请注意,某些实现(例如:Microsoft 的 Avro 库或 Marc Gavel 的 ProtoBuf.NET)允许您直接装饰您的应用程序级别的 POCO/POJO 对象,然后该库直接使用这些装饰的类而不是任何代码生成的类。我们已经看到这提供了性能提升,因为它消除了对象复制阶段(从应用程序级别的 POCO/POJO 字段到代码生成字段)。

一些结果和一个可以玩的现场项目

这个项目 (https://github.com/sidshetye/SerializersCompare) 比较了 C# 世界中的重要序列化程序。 Java 人已经有something similar。

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 还具有 BER(基本编码规则)、PER(打包编码规则)和 XER(XML 编码规则)。 DER 是 BER 的一种变体,主要用于加密,因为它保证每个数据的唯一编码。 BER 和 PER 都比 DER 更有效。大多数图书馆处理 DER。有些不能正确处理所有 BER 结构。对于那些有兴趣了解更多信息的人:luca.ntop.org/Teaching/Appunti/asn1.html 它还有 JER——javascript 对象符号编码规则。您还可以使用 ECN(编码控制符号)定义自己的编码规则。带有下载链接的规范列表:oss.com/asn1/resources/standards-define-asn1.html There are two variants, DER (binary) encoding and PEM (ascii) encoding。请记住,PEM 只是 BEGIN END cmets 内的 base-64 编码二进制数据。这个二进制数据可能是使用 DER 编码生成的,所以比较 PEM 和 DER 很奇怪。【参考方案5】:

Microsoft 的 Bond (https://github.com/Microsoft/bond) 在性能、功能和文档方面令人印象深刻。但是,截至目前(2015 年 2 月 13 日),它不支持许多目标平台。我只能假设这是因为它很新。目前它支持python、c#和c++。 MS到处都在使用它。我试过了,对我来说,作为 ac# 开发人员,使用债券比使用 protobuf 更好,但是我也使用过 thrift,我面临的唯一问题是文档,我不得不尝试很多事情来了解事情是如何完成的。

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

【讨论】:

【参考方案6】:

除了性能方面,Uber 最近还在其工程博客上评估了其中几个库:

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

他们的赢家? MessagePack + zlib 用于压缩

我们的目标是找到编码协议和 压缩算法在最高处得到最紧凑的结果 速度。我们测试了编码协议和压缩算法 来自优步纽约的 2,219 次伪随机匿名旅行的组合 城市(以 JSON 格式放入文本文件中)。

这里的教训是,您的需求决定了哪个库适合您。对于 Uber,由于消息传递的无模式特性,他们无法使用基于 IDL 的协议。这消除了一堆选择。同样对他们来说,发挥作用的不仅是原始编码/解码时间,还有静态数据的大小。

尺码结果

速度结果

【讨论】:

以上是关于Apache Thrift、Google Protocol Buffers、MessagePack、ASN.1 和 Apache Avro 之间的主要区别是啥?的主要内容,如果未能解决你的问题,请参考以下文章

Windows 上的 Thrift / Google 协议缓冲区

Apache thrift 和 cpp 代码生成

thrift和google protobuffer各有啥优劣

Apache Thrift 的使用

Apache Thrift系列详解- 概述与入门

Apache Avro 与 Thrift 比较