Apache Kafka 是否适合用作无序任务队列?

Is Apache Kafka appropriate for use as an unordered task queue?

Kafka 根据生产者分配的分区将传入消息分成多个分区。来自分区的消息然后被不同消费者组中的消费者消费。

这种架构让我对将 Kafka 用作 work/task 队列持谨慎态度,因为我必须在生产时指定分区,这间接限制了哪些消费者可以使用它,因为分区仅发送到消费者组中的一个消费者。我宁愿不提前指定分区,以便任何可以执行该任务的消费者都可以这样做。有没有一种方法可以在 Kafka 体系结构中构造 partitions/producers,其中任务可以由下一个可用的消费者拉取,而不必在工作产生时通过选择分区来提前拆分工作?

为这个主题只使用一个分区会将所有任务放在同一个队列中,但是每个消费者组的消费者数量限制为 1 个,因此每个消费者都必须在不同的组中。然后所有的任务都分配给每个消费者组,不过,这不是我正在寻找的那种工作队列。

Apache Kafka 适合用作任务队列吗?

我会说这取决于规模。您预计在单位时间内完成多少任务?

您所说的最终目标基本上是 Kafka 默认情况下的工作方式。 当您生成消息时,默认(最广泛使用的)选项是使用随机分区程序,它以循环方式选择分区,保持分区均匀使用(因此可以避免指定分区)。
分区的主要目的是并行处理消息,所以你应该这样使用它。
分区用于的其他常用 "thing" 确保某些消息以与生成它们相同的顺序使用(然后您以所有此类消息最终在同一分区中的方式指定分区键。例如使用 userId 作为键将确保所有用户都以这种方式处理)。

将 Kafka 用于任务队列不是一个好主意。 改用 RabbitMQ,它做得更好更优雅。

虽然您可以将 Kafka 用于任务队列 - 但您会遇到一些问题: Kafka 不允许多个消费者(按设计)使用单个分区,因此如果例如单个分区充满许多任务并且拥有该分区的消费者很忙,则该分区中的任务将得到 "starvation". 这也意味着主题中任务的消费顺序将与任务产生的顺序不同,如果需要以特定顺序消费任务,可能会导致严重问题(在 Kafka 中要完全实现这一点,您必须只有一个消费者和一个分区 - 这意味着只有一个节点的串行消费。如果您有多个消费者和多个分区,则主题级别的任务消费顺序将无法保证。

事实上 - Kafka 主题不是计算机科学方式中的队列。队列意味着先进先出 - 这不是您在主题级别的 Kafka 中得到的。

另一个问题是很难动态更改分区数。添加或删除新工人应该是动态的。如果你想确保新工人能在 Kakfa 中获得任务,你必须将分区数设置为最大可能的工人数。这样不够优雅。

所以最重要的是——改用 RabbitMQ 或其他队列。

说了这么多 - Samza(通过 linkedin)正在使用 kafka 作为某种基于流的任务队列: Samza

编辑: 缩放注意事项:我忘了说 Kakfa 是一个很大的 data/big 缩放工具。如果你的工作率很高,那么 Kafka 可能是你的好选择,尽管我之前写过一些东西,因为处理巨大的规模是非常具有挑战性的,而 Kafka 在这方面非常擅长。如果我们谈论的是更小的规模(例如,每秒最多 dosens/hundreds 个作业),那么与 RabbitMQ 相比,Kafka 又是一个糟糕的选择。

尝试使用 Kafka 作为消息队列有两个主要障碍:

  1. 所述,您只能从单个消费者消费单个分区,并且仅在分区内保证处理顺序。所以如果你不能在分区之间公平地分配任务,这可能是个问题

  2. 默认情况下,您只能确认处理到给定点(偏移量)的所有消息。与传统的消息队列不同,您不能进行选择性确认,并且在失败的情况下也不能进行选择性重试。这可以通过使用 kmq 来解决,它在附加主题的帮助下添加了单独的 acks 功能(免责声明:我是 kmq 的作者)。

RabbitMQ 当然是另一种选择,但它也提供了不同的(较低的)性能和复制保证。简而言之,RabbitMQ 文档声明代理 is not partition tolerant. See also our comparison of message queues with data replication, mqperf.

此主题中有很多讨论围绕工作或任务队列中任务的执行顺序展开。我会提出执行顺序不应该是工作队列的一个特征的概念。

工作队列是一种控制资源使用的方法,它通过应用可控数量的工作线程来完成不同的任务。对队列中的任务执行处理顺序意味着您也在对队列中的任务执行完成顺序,这实际上意味着队列中的任务将始终按顺序处理,下一个任务仅在前一个任务结束后才处理。这实际上意味着您有一个单线程任务队列。

如果执行顺序在您的某些任务中很重要,那么这些任务应在完成后将顺序中的下一个任务添加到工作队列中。或者您支持顺序作业类型,该类型在处理时实际上会在一个工人上按顺序处理一系列作业。

工作队列决不应该实际排序它的任何工作 - 下一个可用的处理器应该总是处理下一个任务,而不管任务完成之前或之后发生了什么。

我也曾考虑将 kafka 作为工作队列的基础,但我研究得越多,它就越不像我想要的平台。

我认为它主要用作同步不同资源的手段,而不是执行不同作业请求的手段。

我认为工作队列中的另一个重要方面是支持任务优先级排序。例如,如果我在队列中有 20 个任务,并且一个新任务以更高的优先级到达,我希望该任务跳到队列的开头,由下一个可用的工作人员接走。 Kafka 不允许这样做。

我正在开发一个在 kafka 之上实现作业队列的库,https://github.com/JingIsCoding/kafka-job-queue我正在使用多个队列来维护准备好处理的任务、未来任务和死任务,欢迎贡献