Thrift和Protocol Buffers的最大区别是什么?

314

4
顺便提一下,Marc Gravell 维护了一个与 Google protobuf 一起使用的库,名为 protobuf.net,网址为 http://code.google.com/p/protobuf-net/。 - RCIX
7
这个问题和接下来的一些答案大约有6年的历史了。可能自那时以来发生了很多变化。 - AlikElzin-kilaka
1
为什么要关闭它,即使它基于个人观点 - 它也有助于开发人员了解当前的思考,以帮助做出明智的技术选择。 - mark
15个回答

177

它们都提供许多相同的功能;但是,它们之间存在一些区别:

  • Thrift支持'exceptions'
  • Protocol Buffers有更好的文档和示例
  • Thrift具有内置的Set类型
  • Protocol Buffers允许"扩展" - 您可以扩展外部proto以添加额外字段,同时仍允许外部代码对值进行操作。在Thrift中没有这样的方法
  • 我发现Protocol Buffers更容易阅读

基本上,它们基本等价(根据我所了解的,Protocol Buffers稍微更加高效)。


19
这份演示文稿是2013年的,清晰地解释了PB、Thrift和Avro之间的区别。链接为http://www.slideshare.net/IgorAnishchenko/pb-vs-thrift-vs-avro - BAR
13
Thrift 支持大约 10 种新的语言。 - Ilya Saunkin
1
对于某些编程语言,您可以添加扩展。例如,Thrift 为 C# 生成部分类,这些类易于扩展。但是,这并不是普遍规律,这是真的。 - JensG
grpc 1.0(proto3)支持map - KindDragon

88

另一个重要的区别是默认支持的语言不同。

  • Protocol Buffers: Java、Android Java、C++、Python、Ruby、C#、Go、Objective-C、Node.js
  • Thrift: Java、C++、Python、Ruby、C#、Go、Objective-C、JavaScript、Node.js、Erlang、PHP、Perl、Haskell、Smalltalk、OCaml、Delphi、D、Haxe

两者都可以扩展到其他平台,但这些是开箱即用的语言绑定。


16
protobuf提供了出色的Ruby支持,可以在https://github.com/macks/ruby-protobuf和http://code.google.com/p/ruby-protobuf/上找到相关信息。我同时在C#(版本3.5)和Ruby中使用protobuf对数据进行序列化操作,C#负责序列化数据,而在需要时,Ruby则会对数据进行反序列化并执行相关任务。 - Bryan Bailliache
6
http://code.google.com/p/protobuf/wiki/ThirdPartyAddOns 列出了 PHP、Ruby、Erlang、Perl、Haskell、C#、OCaml 以及 ActionScript、Common Lisp、Go、Lua、Mathlab 和 Visual Basic 等语言的内容。但需要注意的是这些都是第三方实现,非官方版本。 - Igor Gatis
你可以直接在Objective-C中(适用于iOS和OS X)使用protobuf C++文件。查看此问题 - Tushar Koul
我看到 https://code.google.com/p/protobuf-net/ 经常被提及作为C#的protobuf端口,但这并不完全正确。Protobuf和Thrift的一个重要特性是外部结构定义,因此相同的定义可以被不同的语言使用。protobuf-net不支持此功能,因为它将结构定义嵌入到C#代码中。 - Andriy Tylychko
@AndyT:这是有争议的 - 这取决于结构定义是否对您想要支持的所有语言都是一个优势。使用protobuf-net,您在C#中定义数据结构,并从中生成.proto文件,然后可以用它来创建其他语言的支持。我认为这是一个优势,因为我非常关注C#,并正在将Android/Java与现有的大型.Net应用程序集成。因此,我希望继续将我的C#类视为定义结构的权威。 - RenniePet
今天,也就是2015年,Thrift现在支持20多种语言的OOTB。仍在不断增长。 - JensG

79

RPC是另一个重要的区别。Thrift生成代码来实现RPC客户端和服务器,而Protocol Buffers似乎主要设计为仅数据交换格式。


13
不是这样的。协议缓冲区定义了一个RPC服务API,有一些库可用于实现消息传递。 - Stephen
7
我并没有说 Protobuf 没有定义 RPC,只是它似乎并非为此而设计的,至少不是所有人都可以访问的外部版本。请阅读这位谷歌工程师在这里发表的评论。 - saidimu apale
9
更重要的是,Thrift内置了RPC支持。Protobuf目前依赖于第三方库,这意味着少了很多人看、测试和可靠性代码。 - Alec Thomas
2
对我来说,ProtoBuf 的一个好处是,如果你只需要序列化,就不会添加无用的代码。而且,如果将来需要通过 RPC 发送它,也没有问题,它可以正常工作。 我使用 Netty 进行网络通信,而 Protobuf 完美地集成在其中,所以没有问题,不需要测试,并且可以最大化性能。 - Kikiwa
21
实际上,Protobufs 的设计考虑了 RPC。谷歌最近开源了该组件 - grpc.io。 - andybons
显示剩余2条评论

64
  • Protobuf序列化对象比Thrift小约30%。
  • 除非您打开option optimize_for = SPEED,否则您可能想要执行的大多数操作与protobuf对象(创建,序列化,反序列化)相比要慢得多
  • Thrift具有更丰富的数据结构(Map,Set)
  • Protobuf API看起来更干净,尽管生成的类都被打包为内部类,这不太好。
  • Thrift枚举不是真正的Java枚举,即它们只是整数。Protobuf具有真正的Java枚举。

要更深入地了解差异,请查看此开源项目中的源代码差异。


1
快速建议:如果有另一种非二进制格式(XML或JSON?)作为基准,那将是很好的。目前还没有好的测试显示出普遍趋势--假设PB和Thrift更有效率,但如果是这样,效率提高了多少,这仍然是一个开放的问题。 - StaxMan
4
0.02秒?!我没有那样的时间闲置。 - Chris S
2
现在Thrift已经有多个协议(包括TCompactProtocol),我认为第一个要点不再适用了。 - Janus Troelsen
14
现在,协议缓冲区(http://code.google.com/apis/protocolbuffers/docs/proto.html)的默认选项是优化速度。 - Willem
6
使用 "optimize_for=speed" 设置时,我们能否获得30%更小的对象?还是会有妥协? - Prashant Sharma
显示剩余3条评论

59

正如我在"Thrift vs Protocol buffers"话题中所说:

参考Thrift vs Protobuf vs JSON比较

  • Thrift是根据Apache 2许可证发布的
  • 此外,对于这些解决方案,还有许多有趣的附加工具可用,这可能会起到决定性作用。以下是Protobuf的示例:Protobuf-wiresharkprotobufeditor


    12
    现在这是一个完整的循环。你已经将完全相同的答案发布到三个(类似的)问题中,总是链接回到任一一个。我感觉自己像在玩《塞尔达传说》,错过了一个标记。 - ChrisR
    +ChrisR 嘿,我不记得它是怎么发生的了。虽然有几个类似的问题,也许我应该用三个像结构而不是循环。总之... 这是一个非常老的问题,现在我正在手机上回复。无论如何,谢谢你的提醒! - Grzegorz Wierzowiecki
    10
    “节俭”带有一个好的教程——多么有趣啊。这是我见过最不完整的教程。只要你想做除了TSimpleServer以外的任何事情,你就会被卡住。 - Marian Klühspies
    Thrift 也有 Wireshark 插件:https://github.com/andrewcox/wireshark-with-thrift-plugin - CCoder

    9
    Protocol Buffers似乎具有更紧凑的表示形式,但这只是我从阅读Thrift白皮书中得到的印象。用他们自己的话说:
    “我们决定不使用一些极端的存储优化(例如将小整数打包成ASCII或使用7位连续格式),以简化和清晰代码。如果我们遇到需要性能关键的用例,这些更改可以很容易地进行。”
    此外,可能只是我的印象,但Protocol Buffers似乎在结构版本控制方面具有一些更厚重的抽象。Thrift确实具有某些版本支持,但需要付出一些努力才能实现。

    1
    为什么Thrift承认不够紧凑,这让你相信Protocol Buffers是更好的选择? - Michael Mior
    1
    协议缓冲区确实使用可变长度整数编码,对于值和字段标识符均是如此。因此,在发送具有小值的int字段的常见情况下,将使用两个字节,而不是int16和int32。 - poolie
    1
    协议缓冲区确实使用可变长度整数编码,TCompactProtocol也是如此。 - JensG

    8
    我能够通过使用基于文本的协议来获得比Python中的protobuf更好的性能。但是,它没有类型检查或其他protobuff提供的高级utf8转换等功能。
    因此,如果您只需要序列化/反序列化,则可能可以使用其他东西。
    参考链接:http://dhruvbird.blogspot.com/2010/05/protocol-buffers-vs-http.html

    8

    我认为大多数观点忽略了Thrift是一个RPC框架的基本事实,它具有使用各种方法(二进制、XML等)序列化数据的能力。

    Protocol Buffers仅设计用于序列化,它不像Thrift那样是一个框架。


    3
    RPC框架是一种允许软件系统之间进行远程过程调用的机制。与其它RPC框架相比,gRPC是基于Google开发的protobuf协议的框架。 - marcelocra
    gRPC并没有与protobuf一起打包。它是在protobuf之后大约10年开发的。Thrift则与完整的RPC框架一起打包。它们是同时开发的。 - trilogy

    7
    ProtocolBuffers更快。
    这里有一个不错的基准测试:
    https://github.com/eishay/jvm-serializers/wiki (最近更新于2016年,但是截至2020年已有包含更快序列化程序的分支,例如ActiveJ创建了一个分支来展示他们在JVM上的速度:https://github.com/activej/jvm-serializers)。
    你可能还想了解一下Avro,它可能更快。.NET中有两个Avro库:
    1. Apache.Avro
    2. Chr.Avro - 由供应链物流公司C.H.Robinson的工程师编写
    顺便说一下,我见过的最快的是Cap'nProto;可以在Marc Gravell的Github存储库中找到C#实现。

    7

    还有一件显而易见但尚未提及的事情是,它们都可以是优点也可以是缺点(对于两者都是如此),那就是它们是二进制协议。这允许更紧凑的表示和可能更高的性能(优点),但会降低可读性(或者说,调试能力)(缺点)。

    此外,与像xml(甚至json)这样的标准格式相比,它们都具有较少的工具支持。

    (编辑)这里有一个有趣的比较,涉及大小和性能差异,并包括其他一些格式(xml、json)的数字。


    3
    使用my_proto.DebugString()命令,将Protocol Buffer数据输出为文本形式,这种方式比XML更容易被人类读懂。示例请参考 https://code.google.com/apis/protocolbuffers/docs/overview.html。 - SuperElectric
    当然,所有二进制格式都是如此--但这并不意味着它们可以直接阅读(在线调试)。更糟糕的是,对于protobuf,您真的需要模式定义才能知道字段名称。 - StaxMan
    Thrift支持不同的协议,甚至支持用户自定义协议。你可以使用二进制、紧凑型、JSON或者你上周刚刚发明的东西。 - JensG

    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接