【问题标题】:How to use kafka schema management and Avro for breaking changes如何使用 kafka 模式管理和 Avro 进行重大更改
【发布时间】:2019-10-19 07:02:26
【问题描述】:

使用 avro 的 kafka 模式管理为我们提供了向后兼容的灵活性,但我们如何处理方案中的重大更改?

假设生产者A向消费者C发布消息M

假设消息 M 的方案发生了重大变化(例如,名称字段现在分为名字和姓氏),我们有新的方案 M-New

现在我们正在部署生产者 A-New 和消费者 C-New

问题是,在我们的部署过程完成之前,我们可以让生产者 A-new 发布消息 M-new,而消费者 C(旧的)将收到 M-new,因此我们可能会丢失消息。

因此,这样做的唯一方法是同步新生产者和消费者的部署,这会增加大量开销

任何建议如何处理?

【问题讨论】:

  • 您在使用模式注册表吗?默认情况下,它不允许非向后兼容的破坏性更改。如果您对主题有重大更改,您可以将所有消费者移动到最新的偏移量(例如最新架构)或新主题

标签: java apache-kafka avro


【解决方案1】:

一种简单的方法是为您的主题设置较长的保留期。然后,您只需为重大更改创建一个新主题。所有消费者都可以在保留期内移动到新主题而不会丢失消息。

【讨论】:

  • 随着时间的推移,消费者组的订阅列表会变得相当大,如果你继续这样做的话
  • @cricket_007 消费组的订阅列表对系统有多大影响?
  • @rayman 假设你的订阅模式是topic.v\d+,那么你有数百个关于这些主题的分区,最终你会得到topic.v10。然后,您有一个消费者组尝试从数千个分区中读取数据,每当只有一个分区出现故障时,整个组就会重新平衡,而重新平衡的成本很高
【解决方案2】:

例如,名称字段现在分为名字和姓氏

“向后兼容”模式的 Avro 定义不允许您添加这些新字段,除非 1) 保留旧名称字段 2) 为新字段添加默认值 - https://docs.confluent.io/current/schema-registry/avro.html

如果您的消费者首先升级其架构,他们会看到旧名称字段,继续由旧生产者发送,并解释新字段的默认值,直到生产者升级并开始发送新字段

如果生产者首先升级,那么消费者将永远看不到新字段,因此生产者仍应发送名称字段,或者选择发送一些会开始故意破坏消费者的垃圾值(例如,使该字段可以为空开始但从未真正发送空值,然后开始发送空值,而消费者认为它不能为空)

无论哪种情况,我都觉得您的记录处理逻辑必须检测哪些字段可用,而不是 null 或其默认值。

但是,将其与 JSON 或任何纯字符串(如 CSV)进行比较,您无法保证应该存在哪些字段,是否可以为空,或者它们是什么类型(是日期是字符串还是长字符串?),因此您无法保证您的客户端将在内部将消息映射到哪些对象以进行处理...我发现这是 Avro 比兼容性规则更大的优势

就我个人而言,当您的 Kafka 用户之间几乎没有交流时,我发现在注册表上强制执行 FULL_TRANSITIVE 兼容性最有效

【讨论】:

  • 如果我们改变消息对象的结构怎么办?您建议我们保留旧结构并添加新结构?
  • 如前所述,模式注册表不允许这样做。您是说您没有使用它并使用自己的模式对每条消息进行编码吗?在这种情况下,消费者可以只使用该模式,并且永远不会反序列化消息,只是之后的逻辑会出错
  • 但是当新方案落到老消费者手中时会发生什么?消息会丢失吗?我们的业务无法承受丢失的消息。
  • 如果您遇到处理错误,则不会提交偏移量,因此不会丢失任何数据。如果不能处理一条记录,那么就需要更新消费者逻辑,然后弹跳应用,然后从最后一个消费者组offset commit开始继续处理……
  • “它存储在Kafka中”之间有一个非常重要的区别,因此它不会丢失,然后“我们已经处理了那个消息,但是结果是错误的”,然后是“我们无法处理”那个事件,因为它很糟糕”,在这种情况下,您的生产者未能传达更改并给消费者足够的时间进行升级
猜你喜欢
  • 2021-04-26
  • 1970-01-01
  • 1970-01-01
  • 2018-01-26
  • 1970-01-01
  • 2019-03-15
  • 2017-05-17
  • 2018-03-23
  • 2022-11-10
相关资源
最近更新 更多