java - 通过始终添加新字段来发展序列化框架(如 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。
一切正常!
那么这种简单的模式演化方法的真正问题是什么?我知道它并不完美,但它不能成功使用吗?我只需要假设我永远不会删除任何字段,并且我永远不会弄乱字段的顺序。我只是不断添加更多字段。
解决方案
自己添加新字段不是问题,只要协议本身是通过某种标头基于字段的。显然,如果它是基于大小/位的,则会出现问题,因为它会读取每条记录的错误数据量。添加字段正是大多数协议的工作方式,因此这不是问题,但解码器确实需要提前知道如何忽略它不理解的字段。它会跳过一些固定数量的字节吗?它会寻找一些关闭哨兵吗?还有什么?只要你的解码器知道如何忽略它不知道的每一种可能的字段:你很好。
您也不应该假设简单的增量字段,IMO。我已经看到,在现实世界的场景中,一个结构由不同的团队以两种不同的方式分支,然后重新组合,所以每一个组合
- 一个
- 甲,乙
- A、C
- 甲、乙、丙
(其中 B 和 C 是不同的附加字段集)是可能的
我只需要假设我永远不会删除任何字段,并且我永远不会弄乱字段的顺序。
有时候是这样的。你需要处理它;或接受您正在解决一个更简单的问题,因此您的解决方案更简单。
推荐阅读
- javascript - js中的复选框 - 验证
- angular - Ngrx 重置商店后,组件调度一个动作
- node.js - TypeError:无法读取 null 的属性“_id”
- r - 为什么超级任务不适用于 r 中的小标题?
- google-apps-script - OnEdit 脚本到自动增量单元格 - 如果用户同时勾选复选框,则几乎没有冲突
- r - 难以渲染 gganimate 地图
- python - 尝试在 Django 中迁移模型时出现值错误
- c# - 如何统一创造高分?
- twitter - Tweepy 不返回所有推文?
- git - 为什么当我使用 WSL git 变基时所有提交的哈希值都发生了变化?