卡夫卡有许多小队列-如何保持横向扩展负载平衡?

时间:2019-05-13 10:00:53

标签: apache-kafka message-queue

我正在使用Kafka构建消息分发系统。它将每秒处理数万个事件(所有结构都是统一的),并且将有成千上万个可能的接收者。邮件将到达系统,在Kafka中排队,然后发送给收件人。要求是:

  • 必须保留特定收件人的邮件顺序,不能丢失任何邮件。
  • 每个收件人的邮件到达速率和每个收件人处理邮件的速率可能会有很大的不同,并且收件人的停机时间可能很长(例如一周),因此每个收件人都需要自己的队列才能进展(或停滞)自己的价格。
  • 停滞的收件人不应影响任何其他收件人的邮件流,也不应损害吞吐量。
  • 可以在运行时随时添加新的收件人,并且系统应在合理的时间内(但不必是立即的)开始向新的收件人发送消息。
  • 使用和处理来自Kafka的消息并将其分发给各个收件人的应用程序应该能够扩展到多个节点。每个实例都应处理工作的一部分,无论是按消息处理能力,收件人数量还是其他方式划分它,都不必达到完美的平衡,但通常应在运行时可伸缩,且无需停机,并可以恢复来自节点故障。

作为Kafka的新手,我不确定如何建模。最初,我在考虑一个每个收件人主题,每个主题一个分区。我知道Kafka 2.0可以支持无限数量的主题,所以这不是问题。

  • 您可以使用模式来订阅多个主题,这些主题会定期自动刷新。因此,任何新接收者(具有自己的主题)都将自动开始由节点使用。
  • 但是,什么机制可以在应用程序节点之间划分主题呢?必须保留处理顺序,以便每个主题只能由单个节点处理。
  • 当一个应用程序节点出现时,它将如何知道它应该消耗哪些主题?当一个节点出现故障时,如何将其主题分配给其他节点?

这听起来像是消费者群体的机制。因此,我正在研究每个收件人的分区。在Kafka中,每个分区都是它自己的队列,可以按照自己的进度前进,然后将分区分发出去,并自动将其分配给消费者组中的各个消费者。但是分区的问题在于,它们被用作一种数据流的负载平衡机制,因此存在一些局限性。

  • 分区不是完全动态的。每个收件人都有一个分区意味着每次将新收件人添加到系统时都添加一个分区。这将引发重新平衡,并且似乎以不适当的方式混合了功能性和非功能性问题,从而使业务实体与基础结构配置耦合在一起。
  • 对分区进行了编号,那么如何将收件人姓名(字符串)以1对1的方式始终映射到分区号?我想我可以使用序列生成器来为接收者编号,但这听起来像是在错误解决方案之上的黑客行为。如果我需要删除收件人,那将在编号上留下一个空白。我不希望将一个以上的收件人映射到同一分区,因为一个收件人中的停顿会影响其他收件人。
  • 我应该预先分配分区以防止重新平衡吗?如果我有5000个接收者,并且预计这个数字还会增加,那么我是否应该定义20,000个分区,而在那时只有75%未被使用?这样可以防止每次添加收件人时都进行重新平衡,但感觉就像是黑客。

我应该如何使用Kafka解决此排队问题?还是Kafka并不是适合这项工作的工具?

1 个答案:

答案 0 :(得分:1)

我认为Kafka不适合此类用例。它不是为大量队列和下游使用者设计的。它还依赖于基于时间的保留,这不适用于长时间的客户停机。

我建议您研究Cadence Workflow来实现您的应用程序。

与使用队列进行任务处理相比,Cadence具有许多其他优点。

  • 动态创建的任务队列。队列数量是无限的。
  • 构建具有无限到期间隔的指数重试
  • 故障处理。例如,它允许执行一个任务,如果在配置的时间间隔内两次更新均未成功,则该任务会通知另一服务。
  • 支持长时间运行的心跳操作
  • 能够实现复杂的任务依赖性。例如,在无法恢复的故障(SAGA)的情况下实现呼叫链或补偿逻辑的链接
  • 完全了解更新的当前状态。例如,当使用队列时,您就会知道队列中是否有某些消息,并且需要其他数据库来跟踪总体进度。使用Cadence可以记录每个事件。
  • 能够取消正在进行的更新。

请参见介绍Cadence编程模型的the presentation