2. Schema版本管理:版本号策略、向后兼容性、向前兼容性、破坏性变更管理

版本管理这事儿,说白了就是给Schema上个“身份证”。没有版本号,你根本不知道线上跑的是哪一套规则。我见过太多团队因为版本混乱,生产事故一查就是半天——最后发现是消费方还在用老版本的Schema解析新数据。

这一节,我们聊聊版本号怎么定、兼容性怎么判断、破坏性变更怎么管。嗯,都是实战里踩过的坑。

2.1 版本号策略:语义化版本

我个人习惯用语义化版本(SemVer)。格式很简单:MAJOR.MINOR.PATCH。

位段 含义 触发条件
MAJOR 主版本号 做了破坏性变更,不兼容旧版本
MINOR 次版本号 新增字段/功能,但向后兼容
PATCH 修订号 修复文档、注释、非功能性调整

举个例子:v2.3.1 表示主版本2,次版本3,修订1。每次发布新Schema,必须更新版本号。不能手改,要自动化。

我的习惯:版本号写在Schema文件的注释里,或者用独立的version字段。我一般用schema_version字段,避免和业务数据混淆。

2.2 向后兼容性

向后兼容,说白了就是新Schema能读旧数据。这是最基础的要求。你想想看,如果升级Schema后,历史数据全废了,那谁还敢升级?

我在项目中遇到过这种情况:某团队给用户表加了个phone字段,但没设默认值。结果老数据反序列化时直接报错——因为新代码要求phone非空。这就是典型的向后不兼容。

向后兼容的几条铁律:

  • 只能加字段,不能删字段。删了,老数据就缺字段。
  • 新增字段必须有默认值。要么是null,要么是空字符串,要么是0。
  • 不能改字段类型。比如int改成string,老数据解析会崩。
  • 不能改字段语义。比如原来存手机号,现在存邮箱,消费方会懵。

核心原则:向后兼容 = 老数据在新Schema下能正常反序列化,不丢字段,不报错。

2.3 向前兼容性

向前兼容,很多人不重视。它的意思是老代码能读新数据。你想想,如果消费方没升级,但生产方已经发了新Schema的数据,老代码能不能处理?

我曾经踩过一个坑:某服务升级了Schema,加了几个字段,但消费方没同步升级。结果消费方反序列化时,遇到不认识的新字段直接抛异常。嗯,这就是向前不兼容。

向前兼容的要点:

  • 消费方要忽略不认识的新字段。Avro、Protobuf、JSON Schema都支持这种“宽松解析”。
  • 不能删除消费方依赖的字段。删了,老代码就找不到数据了。
  • 不能改变字段顺序(对于位置敏感的格式,比如Avro)。
注意:向前兼容不是所有场景都要求。如果消费方升级节奏很快,可以放宽。但如果是跨团队、跨部门,我建议必须保证向前兼容。

2.4 破坏性变更管理

破坏性变更,就是改了之后,新旧版本不兼容。比如删字段、改类型、改语义。这类变更不能偷偷摸摸做,必须走流程。

我一般把破坏性变更分成三类:

类型 举例 影响
删除字段 去掉age字段 消费方读不到数据
修改类型 int改成string 反序列化失败
修改约束 非空改成必填 老数据校验不通过

管理破坏性变更,我建议走这几步:

  1. 提前通知。至少提前一个发布周期,邮件或IM群告知所有消费方。
  2. 提供迁移窗口。新旧版本同时存在一段时间,让消费方逐步升级。
  3. 版本号升MAJOR。明确告诉所有人:这是大版本更新。
  4. 自动化检查。CI/CD里加兼容性检查,发现破坏性变更直接阻断发布。
避坑指南:我曾经遇到过团队把破坏性变更藏在MINOR版本里,结果消费方没注意,线上出了P0事故。从那以后,我强制要求所有Schema变更必须经过兼容性检查工具(比如Avro的CompatibilityChecker),不通过就不让合并。

2.5 兼容性矩阵与决策流程

下面这张图,是我自己总结的兼容性决策流程。每次改Schema,我都会过一遍。

Schema兼容性决策流程 Schema兼容性决策流程 收到Schema变更请求 是否破坏性变更? 是 升MAJOR版本号 否 升MINOR版本号 通知所有消费方 CI/CD兼容性检查通过? 是 发布新Schema 否 驳回,修复后重提 说明:破坏性变更必须升MAJOR,非破坏性升MINOR,所有变更必须通过CI/CD兼容性检查

这个流程我用了好几年,基本没出过岔子。核心就两点:先判断是否破坏性,再决定版本号怎么升。最后一定要过CI/CD检查,不能靠人工拍脑袋。

2.6 工具推荐

光靠人盯,迟早出事。我建议用工具自动化:

  • Avro:官方提供CompatibilityChecker,支持BACKWARD、FORWARD、FULL等模式。
  • Protobuf:用buf工具做breaking change检测。
  • JSON Schema:可以用ajv配合自定义规则做兼容性校验。
  • Schema Registry:Confluent Schema Registry自带兼容性检查,集成CI很方便。

一句话总结:版本号是Schema的身份证,兼容性是Schema的通行证。破坏性变更必须走流程,不能偷偷改。