Kafka 中的许多小队列 - 如何维护横向扩展负载平衡?
Many small queues in Kafka - how to maintain scale-out load-balancing?
我正在使用 Kafka 构建消息分发系统。它将每秒处理数万个事件(所有事件都是统一的结构),并将有数千个可能的接收者。消息将到达系统,在 Kafka 中排队,然后发送给接收者。要求是:
- 必须保留特定收件人的消息顺序,不允许丢失消息。
- 每个收件人的消息到达速度和每个收件人处理消息的速度可能大不相同,并且收件人可能有很长的停机时间(例如一周),因此每个收件人都需要自己的队列来进行(或停顿)以自己的速度。
- 停滞的收件人不应影响任何其他收件人的邮件流,也不应影响吞吐量。
- 可以在运行时随时添加新收件人,系统应在合理的时间内开始向新收件人发送消息(但不必立即)。
- 使用和处理来自 Kafka 的消息并将它们分派给各个接收者的应用程序应该能够扩展到多个节点。每个实例都应该处理一部分工作,无论是按消息处理能力、收件人数量还是其他方式来划分,它都不必完美平衡,但它应该在运行时通常是可扩展的,没有停机时间,并且可以恢复来自节点故障。
作为 Kafka 的新手,我不确定如何对其建模。起初我想每个收件人 一个主题 ,每个主题一个分区。我知道 Kafka 2.0 可以支持无限数量的主题,所以这不是问题。
- 您可以使用模式订阅多个主题,这些主题会定期自动刷新。因此,任何新的接收者(拥有自己的主题)都会自动开始被节点消费。
- 但是什么机制会在应用程序节点之间分配主题?必须保留处理顺序,因此每个主题只能由一个节点处理。
- 当应用程序节点出现时,它如何知道它应该消费哪些主题?当一个节点宕机时,它的主题将如何分发到其他节点?
这听起来像是消费者群体的机制。所以我正在研究每个收件人一个分区。在 Kafka 中,每个分区都是它自己的队列,可以按照自己的节奏进行,分区会自动分发并在消费者组中的消费者之间分配,这正是我所需要的!但分区的问题在于它们是一种数据流的负载平衡机制,因此它们有一些限制。
- 分区不完全是动态的。每个收件人都有一个分区意味着每次将新收件人添加到系统时都会添加一个分区。这将触发重新平衡,并且似乎以不恰当的方式混合了功能性和非功能性问题,将业务实体与基础设施配置相结合。
- 分区已编号,那么我如何以一对一的方式一致地将收件人姓名(字符串)映射到分区编号?我想我可以使用序列生成器来为我的收件人编号,但这感觉就像是在错误的解决方案之上进行黑客攻击。如果我需要删除收件人,那会在编号中留下一个空洞。我不希望将多个收件人映射到同一分区,因为一个收件人的停顿会影响其他收件人。
- 我应该预先分配分区以防止重新平衡吗?如果我有 5000 个收件人并且这个数字预计会增长,我是否应该定义 20,000 个分区并且在那个时间点只保留其中的 75% 未使用?这将阻止每次添加收件人时重新平衡,但感觉就像一个 hack。
这个排队问题应该怎么用Kafka解决?或者也许 Kafka 不是这项工作的正确工具?
我认为 Kafka 不适合此类用例。它不是为大量队列和下游消费者设计的。它还依赖于基于时间的保留,这在消费者长时间停机时效果不佳。
我建议研究 Cadence Workflow 来实施您的应用程序。
与使用队列进行任务处理相比,Cadence 提供了许多其他优势。
- 动态创建的任务队列。排队人数不限
- 构建了具有无限到期间隔的指数重试
- 故障处理。例如,如果在配置的时间间隔内两次更新均未成功,它允许执行通知另一项服务的任务。
- 支持长运行心跳操作
- 能够实现复杂的任务依赖关系。例如,在发生不可恢复的故障时实现调用链或补偿逻辑 (SAGA)
- 提供对当前更新状态的完整可见性。例如,当使用队列时,您知道队列中是否有一些消息,并且您需要额外的数据库来跟踪整体进度。使用 Cadence,每个事件都会被记录下来。
- 能够在飞行中取消更新。
参见 the presentation 介绍 Cadence 编程模型。
我正在使用 Kafka 构建消息分发系统。它将每秒处理数万个事件(所有事件都是统一的结构),并将有数千个可能的接收者。消息将到达系统,在 Kafka 中排队,然后发送给接收者。要求是:
- 必须保留特定收件人的消息顺序,不允许丢失消息。
- 每个收件人的消息到达速度和每个收件人处理消息的速度可能大不相同,并且收件人可能有很长的停机时间(例如一周),因此每个收件人都需要自己的队列来进行(或停顿)以自己的速度。
- 停滞的收件人不应影响任何其他收件人的邮件流,也不应影响吞吐量。
- 可以在运行时随时添加新收件人,系统应在合理的时间内开始向新收件人发送消息(但不必立即)。
- 使用和处理来自 Kafka 的消息并将它们分派给各个接收者的应用程序应该能够扩展到多个节点。每个实例都应该处理一部分工作,无论是按消息处理能力、收件人数量还是其他方式来划分,它都不必完美平衡,但它应该在运行时通常是可扩展的,没有停机时间,并且可以恢复来自节点故障。
作为 Kafka 的新手,我不确定如何对其建模。起初我想每个收件人 一个主题 ,每个主题一个分区。我知道 Kafka 2.0 可以支持无限数量的主题,所以这不是问题。
- 您可以使用模式订阅多个主题,这些主题会定期自动刷新。因此,任何新的接收者(拥有自己的主题)都会自动开始被节点消费。
- 但是什么机制会在应用程序节点之间分配主题?必须保留处理顺序,因此每个主题只能由一个节点处理。
- 当应用程序节点出现时,它如何知道它应该消费哪些主题?当一个节点宕机时,它的主题将如何分发到其他节点?
这听起来像是消费者群体的机制。所以我正在研究每个收件人一个分区。在 Kafka 中,每个分区都是它自己的队列,可以按照自己的节奏进行,分区会自动分发并在消费者组中的消费者之间分配,这正是我所需要的!但分区的问题在于它们是一种数据流的负载平衡机制,因此它们有一些限制。
- 分区不完全是动态的。每个收件人都有一个分区意味着每次将新收件人添加到系统时都会添加一个分区。这将触发重新平衡,并且似乎以不恰当的方式混合了功能性和非功能性问题,将业务实体与基础设施配置相结合。
- 分区已编号,那么我如何以一对一的方式一致地将收件人姓名(字符串)映射到分区编号?我想我可以使用序列生成器来为我的收件人编号,但这感觉就像是在错误的解决方案之上进行黑客攻击。如果我需要删除收件人,那会在编号中留下一个空洞。我不希望将多个收件人映射到同一分区,因为一个收件人的停顿会影响其他收件人。
- 我应该预先分配分区以防止重新平衡吗?如果我有 5000 个收件人并且这个数字预计会增长,我是否应该定义 20,000 个分区并且在那个时间点只保留其中的 75% 未使用?这将阻止每次添加收件人时重新平衡,但感觉就像一个 hack。
这个排队问题应该怎么用Kafka解决?或者也许 Kafka 不是这项工作的正确工具?
我认为 Kafka 不适合此类用例。它不是为大量队列和下游消费者设计的。它还依赖于基于时间的保留,这在消费者长时间停机时效果不佳。
我建议研究 Cadence Workflow 来实施您的应用程序。
与使用队列进行任务处理相比,Cadence 提供了许多其他优势。
- 动态创建的任务队列。排队人数不限
- 构建了具有无限到期间隔的指数重试
- 故障处理。例如,如果在配置的时间间隔内两次更新均未成功,它允许执行通知另一项服务的任务。
- 支持长运行心跳操作
- 能够实现复杂的任务依赖关系。例如,在发生不可恢复的故障时实现调用链或补偿逻辑 (SAGA)
- 提供对当前更新状态的完整可见性。例如,当使用队列时,您知道队列中是否有一些消息,并且您需要额外的数据库来跟踪整体进度。使用 Cadence,每个事件都会被记录下来。
- 能够在飞行中取消更新。
参见 the presentation 介绍 Cadence 编程模型。