AVRO Schema新增可选字段遇40403错误及配置适配问题
两种AVRO Schema写法是否均有效?
两种写法都是合法有效的AVRO Schema:
- 第一种是AVRO的简洁语法,直接使用基本类型名称(
"string")定义字段类型,完全符合AVRO官方规范。 - 第二种是展开式语法,显式声明类型结构,并添加了Java特定的注解属性
avro.java.string: "String"——这个属性的作用是告诉AVRO Java序列化器,将该字符串类型映射为java.lang.String,而非默认的org.apache.avro.util.Utf8类型。
第一种写法触发40403错误的原因及解决方法
错误原因
Schema Registry的schema匹配是完全结构化匹配,会校验schema的所有细节,包括语言特定的自定义属性。如果你的Kafka Topic对应的Registry中,已存在的schema是第二种带avro.java.string属性的版本,那么第一种不带该属性的schema会被视为完全不同的schema,自然会返回40403(Schema未找到)。
让第一种写法生效的配置修改
有两种可行方案:
统一序列化器的字符串类型映射配置
对于Java生产者,在Kafka生产者配置中,为AVRO序列化器添加avro.java.string: String参数。这样即使你的.avsc文件用的是简洁的"string"写法,序列化器在生成schema时会自动带上avro.java.string: "String"属性,与Registry中已存在的schema完全匹配,避免40403错误。
示例配置(YAML):producer: value.serializer: io.confluent.kafka.serializers.KafkaAvroSerializer properties: schema.registry.url: "your-schema-registry-url" avro.java.string: "String"重新注册不带注解属性的schema版本
如果Registry中现有的schema是带avro.java.string的版本,你可以注册一个不带该属性的新schema版本(因为该注解不影响数据结构,属于向前兼容的修改)。之后确保所有生产者和消费者都使用这个无注解的schema版本即可。但此方案需要确认所有消费者能兼容默认的Utf8类型,若消费者依赖java.lang.String,则不推荐。
AVRO可选字段的生产者推荐配置(兼容新旧生产者)
针对你提到的渐进式更新需求(无法一次性修改所有.avsc文件),推荐以下配置组合:
- 开启自动注册schema:设置
auto.register.schemas: true。新生产者使用的schema会自动注册到Registry(前提是符合Topic的向前兼容规则),旧生产者使用的旧schema也能正常匹配已存在的版本,实现新旧生产者共存。 - 保持向前兼容配置:确保Topic的
schema.compatibility.level为forward(你已配置),保证新注册的schema版本不会破坏旧消费者的兼容性。 - 禁用强制使用最新版本:保持
use.latest.version: false(默认值),让生产者使用自身.avsc文件对应的schema版本,而非强制拉取最新版,避免旧生产者因schema不匹配报错。 - 统一字符串类型映射:如前文所述,为所有生产者配置
avro.java.string: String,确保不同写法的schema最终生成的结构化定义一致,避免因注解属性差异导致的schema匹配失败。
为什么use.latest.version: true能让第一种写法生效?
当开启该配置时,生产者会直接拉取Registry中该Topic的最新schema版本,而不是用自身.avsc文件的schema去匹配。如果最新版本是带avro.java.string属性的,生产者会自动适配这个版本,所以不会报错。但如你所说,该配置要求所有生产者同步更新.avsc,无法支持渐进式更新,因此不适合你的场景。
内容的提问来源于stack exchange,提问作者davidleongz

