模式演进

2025年5月15日 | 阅读 9 分钟
Schema Evolution

Kafka中的模式演进是什么?

Kafka中的模式演进是指多年来修改统计数据(模式)形状的方法,以确保制造商和客户端之间的兼容性。模式定义了事件的形状,包括其字段、事实和约束。

Kafka的解耦架构(其中生产者和消费者独立运行)使得模式演进尤为重要,因为它避免了数据格式更改时破坏下游系统。

为什么模式演进很重要?

  1. 适应不断变化的需求
    • 应用程序通常需要添加新字段或弃用旧字段。
    • 模式演进确保此类修改不会中断生产系统。
  2. 向后和向前兼容性
    • 新生产者可以写入旧客户仍可读取的事件(向后兼容性)。
    • 旧生产者可以写入新客户可以理解的事件(向前兼容性)。
  3. 抵御数据损坏的能力
    • 强制执行模式可以防止不匹配的事实结构和运行时错误。
  4. 启用长期数据存储
    • 即使模式随着时间的推移而演变,存储的数据也可以重新处理。

Kafka中支持模式演进的关键组件

Kafka中支持模式演进的几个重要组件。这些附加组件确保数据模式的更改顺利进行,而不会中断制造商或客户端的操作。让我们详细探讨每一个。

1. 模式定义格式

模式定义了生产者和消费者之间交换消息的结构。Kafka支持多种模式定义格式,每种格式都有独特的优点。

a. Apache Avro

概述: Avro是Kafka中最广泛使用的格式,因为它具有紧凑的二进制序列化和对模式演进的固有支持。

特点

  • 模式演进: 支持添加新字段、删除字段和更改字段类型(带规则)。
  • 紧凑序列化: 有效编码统计数据以减少存储和网络开销。
  • 自描述数据: 在序列化消息中包含模式引用。

模式示例

b. Protobuf (协议缓冲区)

概述: Protobuf是一种与语言无关、与平台无关的序列化结构化数据的机制。

特点

  • 紧凑高效的序列化。
  • 通过主题编号支持模式演进。
  • 它要求通过保持旧主题编号不变来保持向后兼容性。

模式示例

c. JSON Schema

概述: JSON Schema提供了一种人类可读、轻量级的方式来定义信息系统。

特点

  • 易于阅读和写入。
  • 与Avro和Protobuf相比,消息长度更大。
  • 适用于人类检查统计数据至关重要的系统。

模式示例

2. 模式注册表

模式注册表是存储和处理模式的关键服务。它确保生产者和消费者之间一致的模式使用。Confluent提供了一个强大的模式注册表,可与Kafka无缝集成。

a. 模式注册表的主要功能

模式注册

  • 生产者在写入事件时注册模式。
  • 每个模式都被分配一个唯一的模式ID。

模式检索

  • 消费者获取模式以使用嵌入在Kafka消息中的模式ID。

模式版本控制

  • 维护每个主题的所有模式版本的历史记录。
  • 使客户能够使用不同的模式变体。

兼容性检查

  • 强制执行策略以确保模式的调整不会破坏制造商或客户端。

b. 模式注册表REST API

模式注册表提供了一个RESTful API用于模式管理。示例操作

注册模式

按ID获取模式

3. 序列化和反序列化

序列化和反序列化是允许将某些信息写入Kafka主题并从中读取的方法,使用定义的模式。

a. 序列化

  • 生产者在将记录发送到Kafka之前对其进行序列化。
  • 序列化消息包含模式ID,允许客户端识别和检索模式。

使用Avro的示例

b. 反序列化

  • 消费者通过使用模式反序列化消息。
  • 他们从模式注册表和消息中的模式ID中获取模式。

使用Avro的示例

4. 兼容性模式

模式注册表在注册新模式时强制执行兼容性策略。兼容性模式确保无缝的模式演进。

兼容性模式类型

1. 向后兼容性

新模式可以读取用旧模式编写的信息。

示例

旧模式

新模式

2. 向前兼容性

旧模式可以读取用新模式编写的数据。

示例

新模式

旧模式

3. 完全兼容性

  • 结合向后和向前兼容性。

示例

  • 更改应同时支持旧版本和新版本。

4. none

  • 不强制执行兼容性检查。
  • 适用于改进,但在生产中存在风险。

5. 与Kafka生产者和消费者的集成

模式演进依赖于生产者和客户端遵守模式注册表中注册的模式。

生产者工作流

  1. 从模式注册表检索或注册模式。
  2. 使用模式序列化事实。
  3. 将模式ID嵌入消息中。
  4. 将消息发布到Kafka主题。

消费者工作流

  1. 从Kafka主题读取消息。
  2. 从消息中提取模式ID。
  3. 使用模式ID从模式注册表检索模式。
  4. 使用检索到的模式反序列化消息。

6. 错误处理和验证

错误场景

  • 不兼容的模式注册: 尝试检查违反兼容性模式的模式。
  • 缺少模式: 使用未知模式ID消费消息。

错误预防

  • 在注册之前仔细测试模式。
  • 在模式注册表中使用兼容性检查。
  • 监控和记录与模式相关的错误以进行调试

真实世界用例:模式演进实战

Schema Evolution

模式演进在涉及记录结构常见更新的国际系统中至关重要,尤其是在大规模分布式架构中。让我们考虑一个在电子商务软件的客户活动跟踪系统中使用模式演进的示例。

场景:电子商务订单跟踪系统

初始需求

一家电子商务公司建立了一个基于Kafka的订单监控设备。客户下的订单被流式传输到名为“订单事件”的Kafka主题。订单事件的模式包括后续字段

  • order_id (字符串): 订单的唯一标识符。
  • Customer_id (字符串): 赞助商的唯一标识符。
  • Order_status (字符串): 订单状态(例如,“已下单”、“已发货”)。
  • Timestamp (长整型): 事件时间。

初始模式

模式版本1

业务变更:新需求

随着企业的发展,新的需求不断出现

  • 添加新字段: 包含订单的送货地址。
  • 修改字段: 将order_status从字符串更改为枚举类型,以实现更好的验证。
  • 弃用字段: 删除customer_id字段以符合隐私准则。

为了实施这些调整,团队应更新模式,而不会破坏现有客户。

模式演进过程

步骤1:定义新模式

团队创建了具有所需更改的新模式版本

模式版本2

步骤2:注册新模式

新模式在模式注册表中以order-occasions-price的条件注册。兼容性测试配置为向后兼容模式,确保使用旧模式的采购商可以继续操作。

步骤3:生产者实现

生产者应用程序已更新,以在新消息中包含shipping_address字段。对于没有此信息的消息,使用默认的空值。

步骤4:消费者实现

现有客户端继续使用模式版本1。新客户端已更新以处理shipping_address字段和order_status的枚举类型。

实现的好处

  1. 向后兼容性: 现有客户端正在使用旧模式;尽管如此,这些工作没有变化。
  2. 向前兼容性: 新消费者可以利用更新的模式,其中包含已引入的字段和验证规则。
  3. 无缝集成: 生产者和消费者在处理模式更新时同时执行,确保零停机时间。
  4. 面向未来: 该设备足够灵活,可以随着新业务需求的出现而处理类似的模式调整。

模式演进中的挑战

模式演进为基于Kafka的系统带来了灵活性和适应性。但是,它也带来了挑战,需要仔细考虑以避免中断统计管道和客户操作。下面是对三个常见需求进行详细理论解释

1. 字段弃用:将字段标记为可选的风险

弃用字段时,通常将其标记为可选(例如,通过添加默认值或允许空值)。此方法可确保向后兼容性,因为现有客户端在遇到缺少此主题的消息时不会失败。

挑战

  1. 歧义: 消费者可能不明白缺少的主题是故意删除还是在某些消息中未使用。
  2. 遗留代码问题: 较旧的客户端应用程序可能仍会尝试处理或依赖已弃用的字段,这可能导致运行时错误或不正确的行为。
  3. 增加复杂性: 开发人员必须保持识别哪些字段真正在使用中,哪些字段已弃用,尤其是在具有多个模式变体的长期存在的结构中。

挑战

  1. 文档: 清晰记录弃用,包括何时弃用该字段,原因以及应更新的内容。
  2. 弃用期: 在完全删除字段之前,使用缓慢的逐步淘汰方法,将字段标记为在几个模式变体中弃用。
  3. 代码审查和审计: 定期审计客户代码,以确保其与最新的模式版本一致。

2. 兼容性故障:不正确的兼容性设置

模式注册表中的兼容性设置决定是否允许模式更改而不会破坏现有制造商或采购商。错误配置这些设置可能导致严重的运营问题。

挑战

  1. 破坏性更改: 删除所需主题或将区域类型从字符串更改为整数也可能破坏依赖于原始模式的旧客户端。
  2. 向前兼容性与向后兼容性: 误解这些模式之间的差异可能导致问题
    向后兼容性: 确保新制造商可以写入旧客户可以检查的事实。
    向前兼容性: 确保新采购商可以检查旧制造商写入的统计数据。选择不正确的模式可能导致意外故障。
  3. 跨团队不一致: 如果多个团队在相同的Kafka主题上工作,缺乏关于模式修改的沟通可能导致意外的兼容性漏洞。

最佳实践以缓解

  1. 兼容性强制: 始终在模式注册表中实施适当的兼容性模式(例如,向后、向前或完全)以与用例对齐。
  2. 自动化测试: 在CI/CD管道中包含模式兼容性评估,以在部署之前检测破坏性修改。
  3. 版本通信: 维护清晰的版本控制方法并成功地跨团队通信模式更改。

3. 性能开销:模式注册表中频繁的模式查找

消费消息时,用于序列化它们的模式通常存储在模式注册表中。在反序列化期间,客户端使用嵌入在消息中的模式ID获取模式。虽然此机制很健壮,但在高吞吐量环境中可能会引入性能瓶颈。

挑战

  1. 网络延迟: 频繁的模式查找会增加网络延迟,尤其是在模式注册表远程或负载较重的情况下。
  2. 负载增加: 随着消息量的增长,对模式注册表的频繁请求可能会给其资源带来压力,可能导致响应时间变慢。
  3. 启动开销: 当消费者应用程序启动或重新连接时,它可能需要获取它处理的所有主题的模式,从而进一步延迟其就绪时间。

最佳实践以缓解

  1. 本地缓存: 在客户端应用程序中实现本地模式缓存,以减少查找频率。大多数Kafka消费者库都支持此选项。
  2. 批量请求: 对于高吞吐量用例,批量模式查找以减少网络开销。
  3. 扩展模式注册表: 以可用的负载平衡配置部署模式注册表,以有效地处理增加的流量。
  4. 监控和警报: 设置模式注册表整体性能的监控,并配置指示器以立即识别和解决瓶颈。

结论

模式演进是可伸缩和可维护事件驱动系统的基石。通过利用Confluent模式注册表等工具并实施兼容性检查,Kafka确保无缝的模式更新,允许制造商和客户端独立演进。