随着应用及其数据要求的变化,Kafka 消息的结构也需要随之调整。有效的架构生命周期管理对于顺利处理这些更改和维护数据完整性至关重要。 此过程不仅涉及更改架构,还涉及系统地控制对于依赖于这些架构的应用而言安全或足够兼容的更改类型。
Managed Service for Apache Kafka 架构注册表支持架构管理的完整生命周期,并包含以下功能:
定义并强制执行兼容性规则(兼容性类型),以便在引入新的架构版本时管理架构演变。这些规则可确保生产者和消费者继续正常运行。
配置操作控制(架构模式),以在不同层级管理架构的可变性,从而保护数据处理流水线。
管理架构引用,以提高架构的重用性和一致性。
架构演变的工作原理
修改架构定义。例如,向
.proto或.avsc文件添加可选字段。配置了
auto.register.schemas=true的生产者使用新架构发送消息,或者您使用 API 或客户端库显式尝试注册新架构。当新版本的注册请求到达架构注册表时,架构注册表会检索目标主题的已配置兼容性规则。它会根据该规则将提议的新架构与所需的先前版本进行比较。
如果架构版本兼容,则新架构会成功注册为主题下的下一个版本,并分配一个新版本号,如果定义是唯一的,还可能会分配一个新的
schema_id。生产者(如果适用)会收到
schema_id以包含在消息中。如果架构版本不兼容,注册尝试会失败,并返回错误。
兼容性类型简介
通过架构兼容性,您可以定义架构注册表如何处理不同架构版本之间的兼容性检查。您可以在架构注册表层次结构中的各个级别应用这些配置,如下面的资源模式选项所示:
注册表级:为整个架构注册表设置默认配置。
- 路径:
projects/project/locations/location/schemaRegistries/schema_registry/config
- 路径:
默认上下文中的主题级:为注册表默认上下文中的主题设置特定配置。
- 路径:
projects/project/locations/location/schemaRegistries/schema_registry/config/subject
- 路径:
特定上下文中的主题级:为命名上下文中的主题设置特定配置。
- 路径:
projects/project/locations/location/schemaRegistries/schema_registry/contexts/context/config/subject
- 路径:
在主题级设置的配置会覆盖在注册表级设置的配置。
如果未在主题级别指定设置,则会从注册表级别继承相应值。如果未在注册表级别明确设置,则默认值为 Backward。
以下可用类型决定了架构注册表如何将新的架构版本与之前的版本进行比较:
None:不执行任何兼容性检查。允许任何更改,但存在导致客户端中断的高风险。Backward(默认):使用新架构的消费者应用可以解码仅使用之前注册的架构生成的数据。这样便可添加选填字段和删除字段。必须先升级消费者,然后再升级生产者。Backward_transitive:使用新架构的消费者应用可以解码使用相应主题中的所有先前架构版本生成的数据。此设置比Backward更严格。Forward:使用新架构生成的数据必须可供使用之前注册的架构的客户端读取。生产者必须先升级,但使用新架构的消费者可能无法读取使用更旧架构生成的数据。此设置允许删除选填字段和添加字段。Forward_transitive:使用新架构生成的数据必须能够通过所有之前的架构版本读取。此设置比Forward更严格。Full:新架构与之前注册的架构版本在向后和向前兼容性方面均保持一致。客户端可以按照相对于使用新架构的提供方的任意顺序进行升级。允许添加或删除选填字段。Full_transitive:新架构与相应主题中的所有先前架构版本都向后兼容和向前兼容。此设置比Full更严格。
兼容性类型示例
假设您有一个兼容性类型为 Backward 的架构注册表。您还可以在此注册表中创建多个主题,这些主题会继承注册表的 Backward 兼容性。
对于名为 user-events 的特定主题,您需要更严格的兼容性规则。您将 user-events 主题的架构兼容性级别更新为 Full。
在这种情况下,以下规则适用:
在
user-events主题下注册的任何新架构版本都必须与之前为该主题注册的架构版本向后兼容和向前兼容。除非已明确配置,否则架构注册表中的其他主题仍会遵循注册表级
Backward兼容性设置。
如果您之后将架构注册表的兼容性级别更改为 Forward,此更改会影响在注册表中创建的任何新主题的默认兼容性。不过,user-events 主题会保留其明确设置的 Full 兼容性,因为主题级配置会覆盖注册表级配置。
这展示了如何为整个注册表设置默认兼容性级别,同时还可灵活地根据应用需求为各个主题定义具体的兼容性要求。
如需了解详情,请参阅更新兼容性类型。
兼容模式最佳实践
请勿使用
None作为兼容性类型策略,因为您可能会因架构更改而导致客户端中断。如果您想先更新生产者,请选择基于正向的策略,例如
Forward或Forward-transitive。如果您想先更新消费者,请选择基于向后的策略,例如Backward或Backward-transitive。如果您想保持与多个先前架构版本的兼容性,请选择传递性策略。如果您希望最大限度地提高兼容性,并最大限度地降低在更新架构版本时破坏客户端的风险,请使用
Full-transitive策略。
架构参考简介
借助架构引用,您可以定义一次通用结构,并在多个架构中引用该结构。例如,Address 架构可同时用作 Customer 和 Supplier 架构的一部分。
这种方法有助于提高架构的重用性和一致性。此外,使用架构引用可创建明确的依赖关系,从而明确跟踪哪些架构依赖于其他架构。这有助于提高架构的可维护性。
当一个架构需要使用另一个通用架构时,它会包含对该通用架构的引用。此关系由 SchemaReference 结构正式定义。
SchemaReference 包含以下组件:
name(字符串):Avro 格式所引用架构的完全限定名称,或 Protobuf 格式所引用导入类型的文件名(如架构定义本身所用)。subject(字符串):相应架构在架构注册表中注册的主题的名称。version(int32):所引用架构的特定版本号。
使用其他架构的架构会在 references 字段中声明这些依赖项。此字段包含 SchemaReference 对象的列表。
架构参考示例
假设您需要为 Customer 数据和 Supplier 数据定义架构,并且两者都需要包含地址。借助架构引用,您可以定义一次地址结构并重复使用。
如需按照此示例操作,请参阅创建主题。
创建名为
address_schema的主题,并注册标准地址的定义。首次创建主题时,您还会创建该主题的架构版本 1。Avro
创建并将其存储为主题
address_schema_avro版本 1。{ "type": "record", "name": "Address", "namespace": "com.example.common", "fields": [ {"name": "street", "type": "string"}, {"name": "city", "type": "string"}, {"name": "zipCode", "type": "string"}, {"name": "country", "type": "string", "default": "USA"} ] }Protobuf
创建并将其存储为主题
address_schema_proto版本 1。syntax = "proto3"; package com.example.common; message Address { string street = 1; string city = 2; string zip_code = 3; string country = 4; }创建
customer_schema架构。您只需引用address_schema架构,而无需重复地址字段。Avro
billingAddress字段的类型com.example.common.Address是指在上一步中定义的Address架构。{ "type": "record", "name": "Customer", "namespace": "com.example.crm", "fields": [ {"name": "customerId", "type": "long"}, {"name": "customerName", "type": "string"}, // This field's type refers to the Address schema {"name": "billingAddress", "type": "com.example.common.Address"} ] }注册
customer_schema_avro时,其元数据将包含架构引用:// Conceptual metadata for customer_schema_avro "references": [ { "name": "com.example.common.Address", "subject": "address_schema_avro", "version": 1 } ]Protobuf
customer.proto文件导入address.proto并使用com.example.common.Address作为billing_address字段的值。syntax = "proto3"; package com.example.crm; import "address.proto"; message Customer { int64 customer_id = 1; string customer_name = 2; // This field's type refers to the imported Address message com.example.common.Address billing_address = 3; }注册
customer_schema_proto时,其元数据将包含架构引用:// Conceptual metadata for customer_schema_proto "references": [ { "name": "address.proto", "subject": "address_schema_proto", "version": 1 } ]同样,对于
Supplier架构,您需要添加指向同一通用Address架构的架构引用。
架构模式简介
架构模式定义了架构注册表或特定主题的运行状态,并控制允许的修改类型。架构模式可以应用于注册表或架构注册表中的特定主题。以下是架构模式资源的路径:
注册表级模式:适用于整个架构注册表。
- 路径:
projects/project/locations/location/schemaRegistry/schema_registry/mode
- 路径:
注册表级主题模式:适用于整个架构注册表中的特定主题。
- 路径:
projects/project/locations/location/schemaRegistries/schema_registry/mode/subject
- 路径:
支持以下模式:
Readonly:在此模式下,无法更新架构注册表或指定的主题。系统会阻止修改,例如更新配置或添加新的架构版本。Readwrite:此模式允许对架构注册表或指定的主题执行有限的写入操作。它支持修改,例如更新配置和添加新的架构版本。对于新的架构注册表和新的主题,这是默认模式。
在确定是否允许对特定主题进行修改时,主题级设置的模式优先于架构注册表级设置的模式。
例如,如果架构注册表处于 Readonly 模式,但其中的特定主题处于 Readwrite 模式,则允许修改该特定主题。不过,新主题的创建受注册机构级 Readonly 模式的限制。
架构模式示例
假设某个架构注册表的模式设置为 Readwrite。此配置意味着您可以向注册表添加新主题,并向现有主题添加新架构版本。
假设您有一个名为 production-config 的主题,您希望防止该主题被意外更改。您将 production-config 主题的模式设置为 Readonly。因此,以下条件适用于 production-config 主题:
您无法向主题添加新的架构版本。
您无法更新主题的配置(例如兼容性类型)。
注册表中的其他主题(未明确设置自己的模式)仍处于
Readwrite模式,因此您仍然可以修改它们。您可以继续在注册表中创建主题,因为注册表本身仍处于
Readwrite模式。
之后,您可能会决定将整个架构注册表置于维护状态,方法是将注册表级模式设置为 Readonly。不过,您还有另一个主题 staging-config,需要保持可修改状态以进行持续测试。您明确将 staging-config 主题的模式设置为 Readwrite。因此,以下条件适用于staging-config主题:
架构注册表现在为
Readonly。您无法创建新主题。大多数现有主题(例如没有特定模式替换的主题)也会通过继承成为
Readonly。您无法向其添加新的架构版本或更新其配置。production-config主题保持为明确设置的Readonly。staging-config正文仍处于Readwrite模式,因为其正文级设置会替换注册表级Readonly模式。您可以继续为staging-config添加架构版本和更新配置。
这种分层方法可灵活地管理不同粒度级别的架构修改。
如需详细了解如何更新架构模式,请参阅更新架构模式。
建议在生产环境中使用架构注册表的配置
如需在生产环境中保护架构,请应用以下配置:
通过为整个架构注册表或特定生产主题设置
mode=READONLY,防止注册新架构。通过确保 Kafka 客户端缺少
create version权限,防止它们创建新的架构版本。在 Kafka 客户端序列化程序中,设置
auto.register.schemas=false。对于 Kafka Connect,请根据需要为键和值序列化程序配置此设置:key.serializer.auto.register.schemas=falsevalue.serializer.auto.register.schemas=false
(可选)如需强制客户端使用主题的最新架构,请在序列化程序或反序列化程序中设置
use.latest.version=true。此设置指示客户端使用为主题注册的最新架构版本,而不是与特定消息匹配的版本。