重新审视 Flatbuffers 与 Protocol Buffers

Revisit of Flatbuffers vs. Protocol Buffers

提问人:GentlemanS 提问时间:7/18/2023 最后编辑:jonrsharpeGentlemanS 更新时间:8/22/2023 访问量:245

问:

自从这篇文章Kenton Varda 于 2014 年撰写)以来,使用 FlatBuffers 与 Protobuf 的用例有什么变化吗?或者,是否出现了其他东西,现在是数据交换的首选格式/库?

特征 普罗托布夫 Cap'n Proto(卡普普罗托酒店) SBE公司 FlatBuffers(平缓冲器)
架构演变 是的 是的 警告 是的
零拷贝 是的 是的 是的
随机存取读取 是的 是的
防止恶意输入 是的 是的 是的 预先选择加入
反射/泛型算法 是的 是的 是的 是的
初始化顺序 任何 任何 预购 自下而上
未知字段保留 在 proto3 中移除 是的
具有对象功能的 RPC 系统 是的
架构语言 习惯 习惯 XML 格式 习惯
可作为可变状态使用 是的
填充占用电线上的空间? 自选 是的 是的
未设置的字段占用了电线上的空间? 是的 是的
指针占用电线上的空间? 是的 是的
C++ 是的 是 (C++11)* 是的 是的
爪哇岛 是的 是的* 是的 是的
C# 是的 是的* 是的 是的*
是的 是的 是的*
其他语言 很多! 6+ 其它*
作者的首选用例 分布式计算 平台/沙盒 金融交易 游戏

据我所知,自 2014 年的文章以来,似乎没有变化或变化很小,可以总结为:

  • 普罗托布夫

    • 首选较小的消息(1MB 或更小)
    • 对程序员更友好
  • FlatBuffer (平缓冲区)

    • 用于较大的消息
    • 针对高效解析进行了优化
    • 更好的内存表示
protocol-buffers flatbuffers

评论


答:

3赞 Aardappel 7/18/2023 #1

自 9 年前以来,FlatBuffers 有很多改进,但仅从该表来看,这些条目就会发生变化:

RPC 系统:FlatBuffers 具有开箱即用的 gRPC 支持(适用于多种语言)。 可用作可变状态:FlatBuffers 现在在基本 API 之上有一个类似于 Protobuf 的“对象 API”。 其他语言:很多!

对于较小的消息,它是完全可以的,只要您不期望 Protobuf 的 varints 提供的相同级别的“压缩”。

对象 API 对程序员更友好,但速度也较慢,很像 Protobuf。

评论

0赞 Jonas 9/8/2023
是这些“varints”使 Protobuf 不是“零拷贝”吗?还是更多/其他事情?
0赞 Aardappel 9/8/2023
这是相当多的事情..首先,Protobuf 中的字段不是 O(1) 可寻址的(即使它们不是 varints)
1赞 bazza 7/18/2023 #2

一如既往,对于这样的问题,答案是“视情况而定”!

就个人而言,我认为该功能列表是不完整的。我要补充一下:

  • “约束” - 能够定义字段的有效值范围和列表的有效长度
  • “多线格式” - 以不同方式对数据进行编码的能力,例如,用于通过无线电链路传输的高度打包的位优化编码(往往受到带宽限制)以及更易于程序员的格式,如XML
  • “值定义” - 不仅能够定义数据类型,而且还能够定义显示在生成的源代码中的数据类型的固定实例
  • “Constraints Definitions in Terms of Values” - 在约束规范中使用定义值的能力。这应该包括指示“小于 X 1”的语法,其中 X 是定义的值
  • “严格约定” - wireformat 在表示模式时是严格的

约束

ASN.1、XSD 和 JSON 模式等序列化模式都允许对值和长度进行约束。这非常有用,因为无界值和列表在应用程序中实际上有效的情况相当罕见。在模式中表达约束并在生成的代码中遵守约束是相对罕见的 - 一些付费的 XSD / XML 工具可以这样做,大多数 ASN.1 工具可以这样做,大多数 JSON 验证器都可以这样做。

优点是可以签订更精确的合同。

我不太确定该功能集中的“安全防止恶意输入”是什么意思。但据我所知,在 GPB 中,传达消息字段有效值的唯一方法是 1) 将其作为注释输入并希望开发人员发现它,或者 2) 使用模仿 ASN.1 约束的 GPB 第三方扩展。

多种线材格式

有时,能够将数据序列化为用于无线传输的打包二进制格式,但也能够将其序列化为可读格式(如 XML / JSON)是很有用的。GPB 可以做这种事情 (JSON),但不会达到 ASN.1 的程度(许多二进制编码,以及 JSON 和 XML wireformats)。

例如,ASN.1 使用约束来准确了解 INTEGER 字段实际需要多少位。如果它被限制为 1000 到 1015(含 1000 和 1015)之间的有效值,则它将在其未对齐的打包编码规则中仅使用 4 位。

优点是,您可以在重要的链接上获得良好的效率,但在大小不太相关的存储上也对程序员更友好。

值定义

如果使用模式来定义系统之间的接口,则很可能需要共享系统常量。将它们放在架构中非常有用。

其中,AFAIK 只有 ASN.1 在其模式语言中具有此功能。

约束值定义

这只是约束的扩展。与其用文字来表达约束,不如用值来表达它们。例如,在 ASN.1 中,您可以拥有:

listLen INTEGER ::= 10

List ::= SET
{
   list [0] SEQUENCE (SIZE(listLen)) OF REAL,
   defaultEntry [1] INTEGER (0..<listLen)
}

第一行定义值为 10 的常量 int。下一个块定义一个类,该类包含浮点值列表、listLen 条目长度,以及该列表中的索引,该索引被限制为值 0 到 9。应用程序逻辑将使用 listLen 循环访问列表,并保证 defaultEntry 为有效值。如果您需要列表长度为 11 个,只需更改第 1 行并重新构建即可。

对于通信系统来说,这可能是金粉;整个协议消息集和协议常量都可以以这种方式定义,并且它的任何调优都仅在ASN.1模式中进行;无需更改应用程序源代码(只需调整和重建即可)。

严密契约

这是有效的 wireformat 严格遵守架构的地方。GPB 在这方面非常糟糕 - 例如,它会非常高兴地默默地解析消息中的多个字段,只保留最后一个字段,这让我感到惊讶;我希望检测多个字段会引发某种错误!

整体

从本质上讲,它归结为“我非常喜欢ASN.1”,它源于构建通信系统的经验。电话行业建立在ASN.1之上也就不足为奇了。

看到那些不考虑上述方面的团队开始项目开发,只选择他们听说过的第一件事,然后当事实证明没有人真正阅读 ICD 时陷入可怕的混乱,代码库变得难以更改,等等,这真是令人着迷。

ASN.1 可能有很长的起源,但它几十年来一直在不断更新,在让系统轻松可靠地通信方面解决了很多问题。好的工具需要花钱,但我很乐意花一点钱来保护大量的时间和风险。