4. Schema Registry与数据契约
在跨团队数据共享场景中,Kafka 主题本身只负责搬运字节流,它并不理解消息体里到底有哪些字段、字段是什么类型、哪些字段可以为空。如果生产团队悄悄把 order_id 从 string 改成 long,或者删掉一个下游正在使用的字段,消费方往往要等到反序列化抛异常或业务逻辑出错时才发现问题。Schema Registry 的作用,就是把“消息长什么样”这件事从口头约定变成可注册、可校验、可版本化的数据契约。
Schema Registry 是一个独立于 Broker 的 HTTP 服务,通常与 Kafka 集群配套部署。生产者发送消息前,把消息使用的 Schema 注册到 Registry,拿到一个全局唯一的 Schema ID;实际写入 Kafka 的消息体采用“Magic Byte + Schema ID + 序列化数据”的格式,消费方读取时先取出 Schema ID,再向 Registry 拉取对应 Schema 完成反序列化。这样,Schema 本身不必随每条消息重复传输,既节省带宽,又保证收发双方对同一份契约达成一致。
Schema Registry 支持三种主流格式,它们的表达能力与演进特性差异明显,选型时不能只看“哪个流行”。
- Avro:以 JSON 描述 Schema,支持丰富的基本类型、
record、enum、array、map、union,并可为字段设置default。它是三者中与兼容性检查配合最成熟的格式,适合字段频繁增删、需要严格演进控制的场景。 - Protobuf:使用
.proto文件定义消息,字段以编号标识,天然支持向前向后兼容,序列化体积小、性能好,适合跨语言、高吞吐的服务间通信。但字段编号一旦分配就不应复用,删除字段需用reserved标记。 - JSON Schema:以 JSON 描述 JSON 文档结构,人类可读性最好,适合已有 JSON 生态、对性能不敏感的场景。但它对默认值和可选字段的演进约束相对宽松,容易在“看起来没变”的情况下破坏兼容性。
注册 Schema 时,Registry 会先做兼容性检查,再决定是否接受新版本。兼容性策略决定了“新 Schema 能否替换旧 Schema”,常见的有以下几种:
| 策略 | 含义 | 典型适用场景 |
|---|---|---|
| BACKWARD | 新 Schema 可读旧数据,消费者先升级 | 默认策略,消费方主导演进 |
| FORWARD | 旧 Schema 可读新数据,生产者先升级 | 生产方先发布新字段 |
| FULL | 双向兼容,新旧互读 | 要求最严格,升级顺序自由 |
| NONE | 不做兼容性检查 | 仅限实验或完全受控场景 |
以 Avro 为例,BACKWARD 兼容允许“新增带默认值的字段”和“删除字段”,但不允许“新增无默认值字段”或“修改字段类型”。FULL 兼容则要求新增字段必须带默认值,且删除字段也必须谨慎,因为旧消费者可能仍依赖它。理解这些规则,才能在设计契约时预判哪些改动会被 Registry 拒绝。
下面这张图展示了 Schema Registry 在生产者、Broker、消费者之间的位置,以及 Schema ID 如何贯穿消息的序列化与反序列化过程。
跨团队演进时,最稳妥的做法是“先约定兼容策略,再设计 Schema,最后才写代码”。例如,订单团队要新增 coupon_code 字段,若主题采用 BACKWARD 策略,则新字段必须带默认值 "",这样旧消费者读到新消息时,缺失字段会回退到默认值,不会报错。若采用 FORWARD 策略,则旧消费者无法读取新字段,但新消费者可以读取旧消息,适合生产方先升级、消费方后跟进的节奏。
实际注册时,可以通过 REST API 直接操作。以下示例把一份 Avro Schema 注册到 orders-value 主题,并指定 BACKWARD 兼容:
curl -X POST http://registry:8081/subjects/orders-value/versions \
-H "Content-Type: application/vnd.schemaregistry.v1+json" \
-d '{
"schema": "{\"type\":\"record\",\"name\":\"Order\",\"fields\":[{\"name\":\"order_id\",\"type\":\"string\"},{\"name\":\"amount\",\"type\":\"double\"},{\"name\":\"coupon_code\",\"type\":\"string\",\"default\":\"\"}]}"
}'
# 返回示例
{"id": 12}
如果新 Schema 违反兼容策略,Registry 会返回 409 错误,并附带不兼容的具体原因,例如“新增字段 coupon_code 没有默认值”。这时生产者必须调整 Schema,而不是绕过检查。对于已经上线的主题,建议把兼容策略设置为 FULL,并在 CI 中把 Schema 文件纳入版本控制,每次变更都先跑一次兼容性校验,再合并发布。
三种格式的选型可以归纳为:需要严格演进控制、字段增删频繁,优先 Avro;需要跨语言、高性能、字段编号稳定,优先 Protobuf;已有 JSON 生态、对可读性要求高,可选 JSON Schema。无论选哪种,核心原则一致:Schema 是团队之间的数据契约,注册是契约生效的入口,兼容性策略是契约演进的护栏。把这三件事固定下来,跨团队的数据共享才能从“靠默契”走向“靠机制”。