4. Schema Registry 核心概念:Subject、Schema ID、兼容性类型
好,咱们进入 Schema Registry 最核心的几个概念。说实话,很多初学者一开始就被 Subject、Schema ID、兼容性这些术语搞晕了。我当年第一次接触时也差不多——文档翻了好几遍,总觉得隔着一层纱。后来在项目里真正踩过坑,才把这些东西串起来。
今天咱们就把它们一个一个拆开,讲明白。
4.1 Subject:数据的“身份证”
先问一个问题:Kafka 里一条消息,怎么知道该用哪个 Schema 来校验?
答案就是 Subject。
Subject 说白了就是一个名字,用来关联一组 Schema 版本。在 Schema Registry 里,每个 Subject 下面可以注册多个版本的 Schema。你发消息时带上 Subject 名称,Registry 就知道该用哪个 Schema 来校验。
我习惯把 Subject 理解成“数据的身份证号”。它唯一标识了一类数据。比如订单事件,你可以用 order-value 作为 Subject,所有订单的 Avro Schema 都注册在这个 Subject 下。
<topic-name>-<type>,其中 type 可以是 value 或 key。比如 orders-value、orders-key。
嗯,这里要注意:同一个 Topic 的 Key 和 Value 要用不同的 Subject。为什么呢?因为它们的 Schema 结构完全不同。Key 通常只包含业务主键,Value 才是完整的业务数据。混在一起会出大问题。
4.2 Schema ID:版本号的“数字指纹”
有了 Subject,那怎么快速找到某个 Schema 呢?
靠 Schema ID。它是 Schema Registry 为每个注册的 Schema 自动分配的唯一整数 ID。注意,是全局唯一的,不是 Subject 内唯一。
我举个例子:
- Subject A 注册了 Schema v1,Registry 分配 ID = 1
- Subject B 注册了 Schema v1,Registry 分配 ID = 2
- Subject A 注册了 Schema v2,Registry 分配 ID = 3
你看,ID 是递增的,跟 Subject 无关。这样做的好处是:消息里只需要带一个 4 字节的 ID,就能唯一确定 Schema。相比把整个 Schema 塞进消息,这能省下大量带宽。
4.3 兼容性类型:Schema 演进的“交通规则”
好了,现在有了 Subject 和 Schema ID,数据能正常序列化反序列化了。但问题来了:业务总会变,Schema 也会变。今天加个字段,明天删个字段,后天改个类型。怎么保证新老版本能和平共处?
这就是 兼容性类型 要解决的问题。
Schema Registry 支持四种兼容性类型。我直接上表格,对比着看更清楚:
| 兼容性类型 | 规则 | 典型场景 |
|---|---|---|
| BACKWARD | 新 Schema 能读旧 Schema 写的数据 | 消费者先升级,生产者后升级 |
| FORWARD | 旧 Schema 能读新 Schema 写的数据 | 生产者先升级,消费者后升级 |
| FULL | 同时满足 BACKWARD 和 FORWARD | 生产者和消费者同时升级,但不确定顺序 |
| NONE | 不检查兼容性,随便改 | 开发环境、快速原型 |
我一个个说。
4.3.1 BACKWARD 兼容性
这是最常用的类型。规则是:新 Schema 必须能读取旧 Schema 写入的数据。
怎么做到?说白了就是:新 Schema 只能添加有默认值的字段,或者删除没有默认值的字段。这样旧数据反序列化时,新 Schema 能补上默认值,不会报错。
我在项目中遇到过一个问题:有个团队把 BACKWARD 理解反了,以为新 Schema 能写、旧 Schema 能读就行。结果消费者先升级后,读不到生产者旧版本写的数据,线上直接报错。嗯,那场面……
4.3.2 FORWARD 兼容性
FORWARD 正好反过来:旧 Schema 必须能读取新 Schema 写入的数据。
这通常用在生产者先升级的场景。比如你改了数据格式,但消费者还没升级,旧消费者还得能读新数据。
实现方式:新 Schema 只能删除字段,不能新增。因为旧 Schema 不认识新字段,遇到未知字段直接忽略就行。
4.3.3 FULL 兼容性
FULL 就是 BACKWARD + FORWARD 的合体。新 Schema 既能读旧数据,旧 Schema 也能读新数据。
说白了,你只能做两件事:
- 添加有默认值的字段
- 删除有默认值的字段
其他操作都不行。这要求最严格,但也是最安全的。我一般建议生产环境用 FULL,除非你有明确的升级顺序控制。
4.3.4 NONE 兼容性
这个最简单——不检查。你想怎么改就怎么改。但后果自负。
我个人的习惯是:开发环境用 NONE,方便快速迭代。但一旦上了测试环境,立刻切到 BACKWARD 或 FULL。否则线上出问题,排查起来很痛苦。
4.4 核心概念关系图
说了这么多,咱们用一张图把这三个概念串起来:
4.5 实战中的选择建议
最后,我根据实际经验给点建议:
- 生产环境:优先用 FULL 或 BACKWARD。如果你能控制升级顺序,BACKWARD 就够了;如果不能,直接上 FULL。
- 测试环境:用 BACKWARD,模拟生产行为。
- 开发环境:用 NONE,别让兼容性检查拖慢你的迭代速度。
- 跨团队协作:一定要统一兼容性策略。我见过两个团队一个用 BACKWARD、一个用 FORWARD,结果 Schema 注册时互相冲突,排查了半天。
好了,Subject、Schema ID、兼容性类型这三个核心概念,咱们就讲到这里。记住它们的关系:Subject 是门牌号,Schema ID 是身份证号,兼容性类型是交通规则。三者配合,才能让数据在演进中保持一致性。