【问题标题】:Avro deserialization error on schema evolution架构演变上的 Avro 反序列化错误
【发布时间】:2021-03-07 09:52:15
【问题描述】:

我有 2 个架构:

schema1(旧模式):

{
    "namespace": "com.org.package",
    "type": "record",
    "name": "EventModel",
    "fields": [
                    {
                        "name":"name",
                        "type":"string"
                    },
                    {
                        "name":"id",
                        "type":"long"
                    }
]
}

我用布尔字段更新了架构:

schema2(新架构):

{
    "namespace": "com.org.package",
    "type": "record",
    "name": "EventModel",
    "fields": [
                    {
                        "name":"name",
                        "type":"string"
                    },
                    {
                        "name":"id",
                        "type":"long"
                    },
                    {
                        "name":"isActive",
                        "type":"boolean",
                        "default":false
                    }
]
}

kafka 主题包含属于旧模式(模式 1)的消息。更新消费者架构后,即使更新字段中存在默认值,消费者也无法反序列化较旧的架构消息。

根据 Avro 文档:

if the reader's record schema has a field that contains a default value, and writer's schema does not have a field with the same name, then the reader should use the default value from its field.
if the reader's record schema has a field with no default value, and writer's schema does not have a field with the same name, an error is signalled.

Avro doc

反序列化时出现以下错误:

java.io.EOFException: null
    at org.apache.avro.io.BinaryDecoder.readBoolean(BinaryDecoder.java:140) ~[avro-1.9.1.jar!/:1.9.1]
    at org.apache.avro.io.ValidatingDecoder.readBoolean(ValidatingDecoder.java:77) ~[avro-1.9.1.jar!/:1.9.1]
    at org.apache.avro.generic.GenericDatumReader.readWithoutConversion(GenericDatumReader.java:194) ~[avro-1.9.1.jar!/:1.9.1]
    at org.apache.avro.specific.SpecificDatumReader.readField(SpecificDatumReader.java:136) ~[avro-1.9.1.jar!/:1.9.1]
    at org.apache.avro.generic.GenericDatumReader.readRecord(GenericDatumReader.java:237) ~[avro-1.9.1.jar!/:1.9.1]
    at org.apache.avro.specific.SpecificDatumReader.readRecord(SpecificDatumReader.java:123) ~[avro-1.9.1.jar!/:1.9.1]
    at org.apache.avro.generic.GenericDatumReader.readWithoutConversion(GenericDatumReader.java:170) ~[avro-1.9.1.jar!/:1.9.1]
    at org.apache.avro.generic.GenericDatumReader.read(GenericDatumReader.java:151) ~[avro-1.9.1.jar!/:1.9.1]
    at org.apache.avro.generic.GenericDatumReader.read(GenericDatumReader.java:144) ~[avro-1.9.1.jar!/:1.9.1]

为什么当记录缺少字段时,默认值不应用于消费者? 非常感谢任何帮助。提前致谢!

【问题讨论】:

    标签: java deserialization avro spring-kafka


    【解决方案1】:

    尝试将isActive 的类型更改为booleannull,而不仅仅是boolean。比如:

    {
        "name": "isActive",
        "type": ["boolean", "null"],
        "default": false
    }
    

    这将使架构向后兼容。

    【讨论】:

    • 您好!只是一个小问题——默认值应该匹配联合中的 first 类型。 Java SDK (错误地)接受了此模式,并在较新的版本中中断。快速解决方法是在列表中的“null”之前放置“boolean”。
    • 好点,更新了答案@RyanSkraba
    猜你喜欢
    • 1970-01-01
    • 2021-06-26
    • 2018-10-25
    • 2020-09-21
    • 1970-01-01
    • 2019-11-19
    • 2020-03-04
    • 1970-01-01
    • 2018-03-23
    相关资源
    最近更新 更多