ChatGPT解决这个技术问题 Extra ChatGPT

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

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

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

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

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

附带说明:您的问题可以使用具有共享主题消费者订阅的 Apache Pulsar 来解决。请参阅pulsar.apache.org/docs/latest/getting-started/…

O
Ofer Eliassaf

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

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

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

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

所以底线 - 改用 RabbitMQ 或其他队列。

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

编辑:规模考虑:我忘了提到 Kakfa 是一个大数据/大规模工具。如果你的工作量很大,那么尽管我之前写过一些东西,但 Kafka 对你来说可能是一个不错的选择,因为处理大规模是非常具有挑战性的,而 Kafka 在这方面做得非常好。如果我们谈论的是较小的规模(例如,每秒最多几个 dosens/数百个作业),那么与 RabbitMQ 相比,Kafka 也是一个糟糕的选择。


可能还值得一提的是,提交偏移量很快变得复杂,无法处理需要重试的失败任务。
“在Kafka中完全实现你必须只有一个消费者和一个分区”是不正确的。根据分区键为主题中的每个分区保证顺序。因此,如果顺序很重要,您需要按顺序重要的值进行分区。这实际上是比rabbitmq更强的订购保证,可能只有一个消费者来保证订购。
每个分区一个消费者,而不是每个主题。问题也在rabbitmq中。如果您希望以有保证的顺序处理消息,则该队列只能有一个使用者。您不能使用并行消费者按顺序处理工作。
Kafka 的主要优势在于大量数据的流式传输。如果您没有流式传输大量数据 - Kafka 可能是一个糟糕的选择
当您以任何有意义的方式拥有多个消费者时,无法保证订单。如果一个消费者失败并且任务被重新排队怎么办?如果消费者 A 在消费者 B 之前完成任务,即使他们以相反的顺序收到任务怎么办?卡夫卡有铁定的订购保证。绝大多数消息队列都没有,包括rabbit mq,除非你有一个生产者和一个消费者。
M
Marko Bonaci

我会说这取决于规模。你预计单位时间内有多少任务?

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


感谢您的回答 Marko,也许我们可以通过一个例子来深入了解这一点。假设我们有 20 个分区和 2 个工作人员,并且有 100 个新工作进来。使用轮询,工作消息被分发到每个分区 5,然后每个消费者得到 10 个分区,即 50 个工作。假设一个消费者的 50 个工作需要 100 毫秒(所有这些工作的总和),但另一个消费者的 50 个工作需要 2 分钟。提早结束的消费者能否帮助超负荷的消费者?卡夫卡是否对同等工作困难做出某种假设?
嘿,Marko,我认为我在该评论中的最后一个问题在这里触及了问题的核心,如果您可以为此添加更多细节,那么我一定会接受您的回答!
这 100 条消息中的任何一条都将进入一个随机分区,并被这两个(即随机)消费者中的一个接收,然后是第二条消息,然后是第三条消息,......所以并不是每个消费者都会获得大量50 条消息,即他们“互相帮助”。但是你为什么要把自己限制在只有 2 个消费者线程?此外,您将仅在处理每条消息后提交偏移量,以确保在处理不成功时不会丢失任何消息。
R
Rodney P. Barbati

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

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

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

工作队列绝不应该实际订购它的任何工作——下一个可用的处理器应该总是接受下一个任务,而不考虑任务完成之前或之后发生的事情。

我也将 kafka 视为工作队列的基础,但我研究得越多,它看起来就越不像所需的平台。

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

我认为在工作队列中重要的另一个领域是支持任务优先级。例如,如果队列中有 20 个任务,并且有一个具有更高优先级的新任务到达,我希望该任务跳到行首以由下一个可用的工作人员接手。卡夫卡不允许这样做。


a
adamw

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

如 Ofer 的回答中所述,您只能从单个消费者使用单个分区,并且仅在分区内保证处理顺序。因此,如果您不能在分区之间公平地分配任务,默认情况下这可能是一个问题,您只能确认所有消息的处理直到给定点(偏移量)。与传统消息队列不同,您不能进行选择性确认,并且在失败的情况下,选择性重试。这可以通过使用 kmq 来解决,它在附加主题的帮助下添加了单独的 ack 功能(免责声明:我是 kmq 的作者)。

RabbitMQ 当然是一种替代方案,但它也提供了不同的(较低的)性能和复制保证。简而言之,RabbitMQ 文档声明代理 is not partition tolerant。另请参阅我们对消息队列与数据复制的比较mqperf


J
Jing is coding

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