Udemy在Apache Kafka上引入热重试和冷重试


Udemy Payments Team中关于如何使用 Apache Kafka  的非阻塞重试来构建容错事件传递系统的概述
Udemy 平台上有超过 4600 万学生和 64400 万课程注册,每天都有许多用户通过结帐流程来访问内容。这会产生大量流量,同时也会导致许多支付交易。至于集成方法,我们通过将购买转发给第三方支付处理供应商(如 Stripe 或 Adyen)来完成购买。在收到这些供应商的成功回复后,我们将课程交付给学生。这是从结帐的角度对用户体验的简短总结。另一方面,我们听取供应商通知以跟踪这些交易的状态变化并了解它们的更新。我们需要确认以下有关任何通知(又名 webhook)的项目:

  • 接收供应商的通知
  • 处理它们并在接收器服务中运行必要的业务逻辑
  • 将它们转换为 Udemy 生态系统中与供应商无关的消息
  • 将它们发送到下游系统而不会丢失或丢失任何一个

鉴于上述要求和挑战,我们选择使用Apache Kafka 将我们的消息发送到下游系统。Kafka 提供了一个高吞吐量、可扩展和高可用的消息传递平台。然而,仍然几乎不可能预见任何未来的事件。我们需要保证供应商发起的 webhook 将到达下游系统。并且他们将能够以容错的方式运行各自的业务逻辑。由于代码中的异常或可能持续数小时的事件,您的 Kafka 使用者可能会失败。您能做的最好的事情就是采取必要的措施来防止此类情况,并使您的系统自行恢复。为了应对这些挑战,我们通过向消费者添加重试逻辑来提出有效的解决方案。

在这篇文章中,我将解释如何以非阻塞方式在事件传递生态系统中引入这种冷热重试。最重要的是,我还将描述如何根据 Kotlin 中使用 Spring 框架的特定用例来调整它以适应不同的配置。

一些术语
让我们从定义一些术语开始讨论。我们将在接下来的部分中大量提及它们,最好事先澄清它们。

  1. 热重试:这是一种在使用消息时遇到错误后立即重试消息的策略。例如,您可以考虑这样一种场景,即您的消费者由于套接字超时而无法连接到您的数据存储。或者,您执行了 API 调用来获取一些资源。但是,该资源丢失了,您只需要一些额外的时间来引用该资源。这可能是大多数最终一致的分布式系统的常见原因。如您所见,由于立即重试,您的消费者可以从这些类型的错误中恢复过来。
  2. 冷重试:这种类型的重试策略是指您需要一些时间(可能超过几秒钟)才能解决根本原因的方式。例如,假设您的 MySQL 集群中有很高的复制延迟。您的消费者无法从副本中获取必要的记录。因此,您的消费者将失败,直到复制完成。在这种情况下,您将需要一个冷重试机制并以某种方式延迟您的主题以在解决时刻重试它。

现在,我们准备好进行下一步了。首先,我将通过高级流程图来定义我们最终要实现的目标。之后,我们将介绍配置模式、这些配置参数的用法、冷重试的主题转发策略以及示例消费者实现。
流动

如下图所示,我们的旅程从我们的生产者开始。它在目标主题上发布消息,消费者开始处理。在happy path中消费不会有任何问题,消费者就能对消息进行处理。

但是,如果消费者遇到异常,它会首先检查是否定义了任何热重试。如果是这样,我们将尝试消息消费直到最大热重试尝试或成功消费消息。如果失败并达到最大阈值,则检查是否定义了冷重试配置。在我们没有配置任何冷重试的最坏情况下,消息会进入死信队列(DLQ)。否则,我们会将消息转发到冷重试主题,并使其延迟处理。这就是为什么这类主题被称为延迟主题的原因。
请注意,延迟主题在拓扑方面与正常主题没有区别,但在术语方面。您会看到他们也可以在其中定义热重试,或者甚至在另一个延迟主题旁边链接另一个冷重试主题。

现在,我们已将消息转发到冷重试主题。这里的主要目标之一是将延迟主题与它们自己或其他主题链接起来,而不会阻塞同一分区中的其他消息。为此,我们将为冷重试实现主题转发逻辑。因此,冷重试主题的失败将导致再次将相同的消息发布到相同的主题并跳过当前偏移量。此外,为了设置重试阈值,我们将自定义标头放在主题上,并在下一次消费中检查尝试值。通过这样做,当前偏移量的消息不会阻塞下一个偏移量,并且当前失败的消息将在增加尝试计数后在同一分区的末尾获得它的新偏移量(耶!). 尽管如此,我们还是有可能达到冷重试的最大尝试次数限制。结果,这将导致将消息发布到下一个冷重试主题(如果已定义)或死信队列作为接收点。
从整体流程中可以看出,消费者会将每条转发的消息都当作一条新消息处理,并在失败的情况下一次又一次地对其进行冷热重试。

配置架构
如以下代码块所示,我选择构建配置以支持热重试和冷重试。在拓扑中,我们有主题部分来参考每个主题的配置。在这里,每个主题都有其限定符(将在代码库中用作参考)和配置详细信息。

  • 主题名称:通过 Kafka 模板发送消息的主题名称
  • 消费者计数:消费者计数决定并发消费者的数量
  • 热重试- 计数:继续冷重试主题之前的尝试次数- 间隔:每次热重试之间的持续时间间隔(以毫秒为单位)
  • 冷重试- 计数:继续下一个冷重试主题之前的尝试次数- 间隔:同一主题的每次冷重试之间的持续时间间隔(以毫秒为单位) - 下一个主题:如果存在,则下一个要转发的主题限定符
  • Manually acknowledgment flag : 布尔标志,用于决定消息是否需要手动确认

开源存储库
一个演示项目,用于详细说明如何在 Apache Kafka 中应用热重试和冷重试。
包括:

  • 应用程序配置和配置类读取它
  • 消费者工厂创建必要的侦听器容器 bean 和死信队列转发器
  • 记录即将到来的消息并创建错误案例的简单服务层
  • 这些策略中的主题转发策略和标头利用示例
  • 冷热重试的消费者示例

实用程序:
  • 此外,您可以在运行应用程序之前找到一个简单的 Kafka 集群来创建自己的 Playground

详细教程说明点击标题