可以从 protobuf/thrift 消息中删除字段标签吗?

Can field tags be dropped from protobuf/thrift messages?

我知道 protobuf/thrift 需要唯一的数字字段标签来提供版本兼容性。它们通过以这种方式(某种程度上)序列化消息来提供版本兼容性:

<tag1> <value1> ... <tagN> <valueN>

在反序列化时,他们获取标签值,查找消息模式,并知道将值填充到哪个字段。这样,只要我们添加不同标签值的新字段,消息就会兼容。

但我认为这不是一个很好的设计:

  1. 标签值必须在消息中进行编码。这有一些开销。

    例如。当客户端多次调用远程服务器上的RPC方法时,每次request/response中的tag值都是相同的。最好只发送一次<tag1> <value1> ... <tagN> <valueN>,然后只发送<value1> ... <valueN>.

  2. 在更改字段类型时,我们还需要更改标签值。忘记这样做会导致错误。

  3. 开发人员必须确保标记值是唯一的。通常人们会跟踪最后使用的标签 ID 并在添加新字段时增加它。但是当两个人在不同的分支中添加字段并进行合并时,很难解决冲突。

我认为更好的设计可能是:

为每种消息类型创建一个紧凑的模式,如下所示:

<field_name_1> <field_type_1> ... <field_name_N> <field_type_N>(按照field_name排序)

要解决问题 1,请在执行任何操作之前交换消息架构。对于 RPC 示例,客户端将在发送第一个 RPC 之前发送其消息模式,然后在接下来的 RPC 中,它只发送 <value_1> ... <value_N>。当请求到达时,服务器将具有消息模式,并且知道如何反序列化它。

为了解决问题 2,当字段类型更改时,紧凑消息架构也将更改。程序将能够找出新旧模式不匹配,并报告错误。

为了解决问题 3,开发人员不再需要负责分配唯一标记值。他们仍然需要注意分配唯一的字段名称,但这应该更容易,并且不太可能导致合并冲突。

这可能是一个可用的设计吗?又会有什么问题呢?

我相信 Apache Avro 的工作方式与您描述的一样,所以也许您应该尝试一下。

但是,我认为前期模式协商给协议增加了大量的复杂性,这超过了任何好处。在简单的情况下,这似乎很容易,但在大型系统中,您有代理(不知道它们在代理什么)、专用存储服务器、由从具有不同协议版本的多个发件人接收的片段组成的消息等,跟踪架构版本的复杂性成为一个巨大的负担。