为什么静态类型语言需要 Avro Schema Registry?

Why is an Avro Schema Registry needed with statically typed languages?

我一直想知道在使用静态类型语言(如 Java)从 Kafka 主题消费消息时是否需要 Avro Schema Registry。我正在使用来自 Kafka 主题设置的消息,如下所示:

    Properties props = new Properties();
    props.setProperty(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, String.join(",", kafkaProperties.getServers()));
    props.setProperty(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, ByteArrayDeserializer.class.getName());
    props.setProperty(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, KafkaAvroDeserializer.class.getName());

    props.setProperty(KafkaAvroDeserializerConfig.SCHEMA_REGISTRY_URL_CONFIG, kafkaProperties.getSchemaRegistryUrl());
KafkaConsumer<byte[], FooClass> kafkaConsumer = new KafkaConsumer<>(props);;

在我的项目中,我有 .avsc 个定义 FooClass class 架构的文件。我还配置了 avro-maven-plugin 以在构建时为我生成 class FooClass

为什么我还需要指定架构注册表URL?我的消费者是否无法使用我项目中的 .avsc 文件反序列化我的 Kafka 消息的值?

Schema Registry 的目的是让 所有 生产者和消费者都可以使用模式,而不需要像 .avsc 文件。像这样的文件在独立项目中很好,但 Kafka 经常被多个应用程序使用,可能跨团队甚至跨组织单元 - 因此能够更松散地耦合模式的共享方式很重要。

参考:https://docs.confluent.io/current/schema-registry/index.html

您正在使用 Confluent 库(io.confluent.kafka.serializers.KafkaAvroDeserializer) which define their own Confluent Avro format 并强制使用 Confluent Schema Registry。

从技术上讲,您不需要 Apache Avro 的注册表。

Avro 需要 writers 模式来解码消息,虽然这包含在 Avro 文件中,使它们能够自我描述,但它不包含在 the streaming format or Confluent Avro.

因此,客户端需要某种方式来查找架构。这可以通过 Confluent Avro 格式的 Confluent Schema Registry 解决,也可以通过您自己的 org.apache.avro.message.SchemaStore. See this example, where I use a SchemaStore.Cache 预填充已知模式来解决。

请注意,该示例使用 Apache Avro format, which is incompatible with Confluent Avro

Confluent Avro 反序列化器需要一个 Confluent Schema Registry,并且没有 API 用于“运行 with known schemata”。

在详细了解 avro 格式和模式注册表的作用之后,我意识到为什么即使对于像 java 这样的 statically-typed 语言,也需要模式注册表。简短的回答是“模式演变”。

假设您今天构建了一个应用程序,该应用程序使用类型 A 的消息,使用模式 SA 编写。在构建应用程序时,您可能有一个“a.avsc”文件,用于生成 classes 以将消息反序列化到。到目前为止,您不会认为需要联系架构注册表来获取 SA,将反序列化器 class 指向您构建应用程序所用的“a.avsc”文件是有意义的.但是使用 avro 解串器你不能这样做(即它需要一个注册表)。这让你想知道,为什么?

一周后,生成 A 类型消息的生产者决定向 A 添加一个新字段。发生这种情况时,您的 avro 反序列化器 class,使用您构建应用程序所用的架构(如果是可能的),如果遇到新消息,将无法反序列化这些新消息。同时,使用旧模式生成的代码仍然有效(如果模式更改向后兼容)。但是为了让您的反序列化器能够读取使用新模式编写的消息,它需要新模式。

这实际上意味着您的 Java 使用旧模式生成的应用程序代码仍将适用于使用改进模式编写的消息。但是如果没有新模式(由注册表提供),您的 avro 反序列化器将无法反序列化新消息。

因此,理论上,如果模式没有改变,您将能够在构建时提供模式。