131

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

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

4

6 回答 6

101

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

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

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

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

就个人而言,尽管我对它又爱又恨,但我可能会将 ASN.1 用于大多数 RPC 和消息传输目的,尽管它并没有真正的 RPC 堆栈(你必须制作一个,但 IOC 会这样做)很简单)。

于 2011-01-08T12:24:48.110 回答
41

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

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 人已经有了类似的东西

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!)
于 2013-12-27T19:14:29.543 回答
15

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

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

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

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

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

尺寸结果

尺寸结果

速度结果

在此处输入图像描述

于 2016-04-09T13:40:20.140 回答
13

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 世纪后期开始)的改造,但是,嘿,它也很好用。

于 2012-11-04T18:28:05.120 回答
7

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

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

于 2015-02-13T11:19:12.927 回答
5

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

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

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

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

于 2011-01-12T20:08:48.850 回答