Confluent SchemaRegistry如何保障读(投影)Avro schema的演进兼容性?
SchemaRegistry 可共享用于消息编码的写入端 Avro schema,供需要该写入 schema 对接收到的消息进行解码的消费者使用,另一项核心功能是辅助 schema 演进。
假设生产者 P 定义了写入端 Avro schema v1,存储在逻辑 schema S 下;消费者 C1 定义了自身的读(投影)schema v1,另有消费者 C2 定义了自己的读(投影)schema。读 schema 无需共享,由 Avro 在本地将消息从写入端 schema 转换为读取端 schema 时使用。
无破坏性变更的 schema 演进场景
- 消费者 C1 在其 schema 中新增可选字段以请求新属性,这是向后兼容变更。未携带该字段编码的消息仍可正常转换为该读 schema,此时我们得到 C1 读 schema 的 v2 版本。
- 生产者 P 在自身 schema 中新增对应字段满足 C1 的需求,该字段不必设为必填,属于向前兼容变更。消费者 C1 可读取新增字段中编码的数据,消费者 C2 作为容错读取方会直接忽略该字段,此时我们得到生产者 P 写入 schema 的 v2 版本。消费者需要知晓消息写入时使用的具体 schema,因此新版本会存储在逻辑 schema S 下。
存在破坏性变更的 schema 演进场景
- 生产者 P 决定删除一个非可选字段,可能有消费者正在使用该字段,这不属于向前兼容变更。假设主题 S 配置了
FORWARD_TRANSITIVE兼容性类型,存储新写入 schema 的请求会失败,可规避风险。 - 消费者 C2 在自身 schema 中新增字段请求新属性,由于生产者未写入该字段,这不属于向后兼容变更。
核心问题与现有方案局限
SchemaRegistry 如何帮助预防消费者侧的破坏性变更?注意读 schema 的兼容性校验需要对比所有版本的写入 schema。
现有 POST /compatibility/subjects/{subject}/versions 接口支持对比 subject 下的所有版本做兼容性校验,但问题在于它使用的是 subject 上配置的兼容性类型。存储写入 schema 版本的 subject 无法直接使用,因为它配置的是 FORWARD_TRANSITIVE 兼容性类型,而读 schema 需要满足向后兼容要求。
创建另一个配置为 BACKWARD_TRANSITIVE 兼容性类型的 subject 也不可行,因为带有向前兼容变更(比如新增非可选字段)的新版本写入 schema 无法存入该 subject。
目前想到的一个方案是使用 CompatibilityChecker 编写单元测试,但该方案并不理想,因为每个消费者都需要在本地保存所有版本的写入 schema,生产者 schema 变更时同步所有消费者的成本极高。
内容的提问来源于stack exchange,提问作者Stanislav

