首页 > 解决方案 > 通过始终添加新字段来发展序列化框架(如 ProtoBuf、Thrift 等)的数据模式有什么问题?

问题描述

我正在编写一个简单的序列化框架。我的意图不是与 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 的最新数据对象模式。

一切正常!

场景二:

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

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

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

一切正常!

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

标签: javaserializationschemaprotocol-buffersthrift

解决方案


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

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

  • 一个
  • 甲,乙
  • A、C
  • 甲、乙、丙

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

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

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


推荐阅读