You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

已指定枚举默认值,Avro为何仍无法读取含新枚举值的消息?

问题描述

我有一个基础Avro Schema,其中包含如下枚举:

enum ColorType {
    BLUE,
    YELLOW,
    GREEN,
    UNKNOWN
} = UNKNOWN;

根据Avro规范,遇到未知枚举值时应使用UNKNOWN值。

我还有一个更新后的Avro Schema,该枚举新增了BLACK值:

enum ColorType {
    BLUE,
    YELLOW,
    GREEN,
    BLACK,
    UNKNOWN
} = UNKNOWN;

现在我尝试用基础Schema的读取器,读取由更新后Schema写入的JSON序列化Avro消息,Java代码如下:

var jsonDecoder = DecoderFactory.get().jsonDecoder(TreeRecord.SCHEMA$, resourceAsStream);
return new SpecificDatumReader<CategoryTreeRecord>(TreeRecord.SCHEMA$).read(null, jsonDecoder);

但出现如下错误:

org.apache.avro.AvroTypeException: Unknown symbol in enum BLACK
    at org.apache.avro.io.JsonDecoder.readEnum(JsonDecoder.java:331)
    at org.apache.avro.io.ResolvingDecoder.readEnum(ResolvingDecoder.java:261)
    at org.apache.avro.generic.GenericDatumReader.readEnum(GenericDatumReader.java:268)
    at org.apache.avro.generic.GenericDatumReader.readWithoutConversion(GenericDatumReader.java:182)

请问:

  1. 为何已指定枚举默认值,Avro仍无法通过基础Schema反序列化更新后的消息?
  2. 如何实现Avro Schema的完全兼容性?

问题解答

一、默认值未生效的原因

Avro枚举的默认值UNKNOWN仅在字段缺失时生效,而非遇到读取器Schema中不存在的枚举符号时触发。当JSON序列化消息中明确包含BLACK这个读取器Schema未定义的枚举值时,JsonDecoder会直接抛出未知符号异常,不会自动回退到默认值。

另外,你当前的代码仅传入读取器Schema到SpecificDatumReader,未启用Avro的Schema解析(resolution)机制。Avro的兼容性处理需要同时知晓写入器Schema和读取器Schema,通过解析两者差异完成兼容转换,单一Schema无法触发该逻辑。

二、实现完全兼容性的解决方案

1. 启用Schema解析机制

修改SpecificDatumReader初始化逻辑,同时传入写入器Schema和读取器Schema,让Avro自动处理兼容转换:

// 示例:获取更新后的写入器Schema(生产环境可从Schema Registry拉取)
Schema writerSchema = new Schema.Parser().parse("{\"type\":\"enum\",\"name\":\"ColorType\",\"symbols\":[\"BLUE\",\"YELLOW\",\"GREEN\",\"BLACK\",\"UNKNOWN\"],\"default\":\"UNKNOWN\"}");
Schema readerSchema = TreeRecord.SCHEMA$;

var jsonDecoder = DecoderFactory.get().jsonDecoder(writerSchema, resourceAsStream);
SpecificDatumReader<CategoryTreeRecord> datumReader = new SpecificDatumReader<>(writerSchema, readerSchema);
return datumReader.read(null, jsonDecoder);

当读取器检测到写入器Schema存在新枚举值时,会自动将无法识别的符号映射到读取器枚举的默认值UNKNOWN。

2. 确保枚举默认值定义合规

确认基础Schema中枚举的默认值符号存在于枚举列表中——你的现有定义符合要求,这是实现兼容的前提。

3. 生产环境推荐使用Schema Registry

在分布式系统中,通过Schema Registry管理Schema版本:

  • 写入端将消息与对应Schema版本绑定
  • 读取端从Registry拉取写入器Schema,再与本地读取器Schema做解析
  • 该方式可自动处理Schema演进和兼容性验证,无需手动管理Schema字符串

内容的提问来源于stack exchange,提问作者Harold L. Brown

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 21:32:41