繁体   English   中英

通过总是添加新字段来演化序列化框架(如 ProtoBuf、Thrift 等)的数据模式有什么问题?

[英]What is the problem of evolving a data schema of a serialization framework (like ProtoBuf, Thrift, etc.) by always adding new fields?

我正在编写一个简单的序列化框架。 我的意图不是与 ProtoBuf、Thrift、Avro 等竞争,远非如此。 我的目标是学习。

我的问题与发展我的数据对象的模式有关。

假设我有两个程序 A 和 B,需要交换数据,并且我有一个由以下模式表示的数据对象:

public byte[] accountUser = new byte[8]; // first field

伟大的! 现在我想继续向我的数据对象架构添加一个 accountId 字段:

public byte[] accountUser = new byte[8]; // first field
public int accountId = -1; // second field just added (NEW FIELD)

场景一:

程序 A 具有带有 accountId 的新架构,而程序 B 没有。

程序 A 将数据对象发送给程序 B。

程序 B 将简单地读取数据到 accountUser 并完全忽略 accountId。 它对此一无所知,也没有更新为使用带有 accountId 的最新数据对象模式。

一切正常!

场景2:

程序 A 具有没有 accountId 的旧模式,程序 B 具有带有 accountId 的新模式。

程序 A 将数据对象发送给程序 B。

程序 B 将读取数据到 accountUser 并继续尝试读取新的 accountId。 但是在接收到的数据对象中没有什么可以读取的了。 accountUser 之后没有更多数据。 所以程序 B 简单地假设 accountId 的默认空值 -1 并继续它的生命。 我很可能有逻辑来处理仍然使用旧模式运行的遗留系统的 -1 accountId。

一切正常!

那么这种简单的模式演化方法的真正问题是什么? 我知道它并不完美,但它不能成功使用吗? 我只需要假设我永远不会删除任何字段,并且我永远不会弄乱字段的顺序。 我只是不断添加更多字段。

添加新字段本身不是问题,只要协议本身通过某种报头是基于字段的。 显然,如果它是基于大小/位块的,就会出现问题,因为它会读取每条记录的错误数据量。 添加字段正是大多数协议的工作方式,因此这不是问题,解码器确实需要事先知道如何忽略它不理解的字段。 它是否跳过了一些固定数量的字节? 它会寻找一些关闭哨兵吗? 还有什么? 只要您的解码器知道如何忽略它不知道的每种可能的字段:您就可以了。

您也不应该假设简单的增量字段,IMO。 我已经看到,在现实世界的场景中,一个结构由不同的团队以两种不同的方式进行分支,然后重新组合,所以每个组合

  • 一种
  • 甲、乙
  • 甲、丙
  • 甲、乙、丙

(其中 B 和 C 是不同的附加字段集)是可能的

我只需要假设我永远不会删除任何字段,并且我永远不会弄乱字段的顺序。

有时候是这样的。 你需要处理它; 或者接受你正在解决一个更简单的问题,所以你的解决方案更简单。

通过总是添加新字段来演化序列化框架的数据模式有什么问题

这是你的文件。 所有二进制数据。

+------------------+
| accountUser      | 
| accountId        | 
+------------------+
| accountUser      | 
| accountId        | 
+------------------+
| accountUser      | 
| accountId        | 
+------------------+

现在让您的老客户(不知道 accountId 的客户)阅读这些条目。

通过总是添加新字段来发展序列化框架的数据模式有什么问题?

你的基本前提是错误的。 在实践中,你也会...

  • 删除/弃用字段
  • 不要写没有值的可选字段
  • 需要跳过未知字段(如上)

这些框架解决的问题不止一个。

我看到添加字段仍然导致失败的一种情况是使用 Union。 让我们看一个例子:

Union {
  string firstName
  string lastName
}

现在假设我们添加string middleName 程序 A 是最新的并发送带有变量 middleName 的程序 B,但它会在这里失败,因为程序 B 不知道 middleName,因此当它尝试反序列化对象时,所有字段都将为空,这对于导致失败的联合对象来说是不合适的

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM