【发布时间】:2019-05-04 22:11:29
【问题描述】:
消息队列服务(包括 RabbitMQ)的主要特征之一是保持消息发布顺序。这在RabbitMQ documentation 中得到了证实:
[QUOTE 1] AMQP 0-9-1 核心规范的第 4.7 节解释了 保证排序的条件:发布的消息 一个通道,经过一个交换和一个队列和一个 传出通道将按照与它们相同的顺序被接收 发送。自 2.7.0 版以来,RabbitMQ 提供了更强大的保证。
让我们在下面假设没有活跃的消费者,以简化事情。我们通过一个渠道发布。
到目前为止,一切都很好。
RabbitMQ 还提供了通知发布者某个发布已被完全正确处理的可能性[*]。这解释了here。基本上,代理将发送basic.ack 或basic.nack 消息。文档还说:
[QUOTE 2]
basic.ack用于路由到持久队列的持久消息将是 将消息持久化到磁盘后发送。在大多数情况下,RabbitMQ 会向发布者确认消息 它们发布的顺序相同(这适用于发布的消息 单通道)。但是,会发出发布者确认 异步,可以确认单个消息或一组消息 消息。发出确认的确切时间取决于 消息的传递模式(持久与瞬态)和 消息路由到的队列的属性(见上文)。 也就是说,可以认为不同的消息已经准备好 不同时期的认可。这意味着致谢 与它们各自的消息相比,它们可以以不同的顺序到达。 应用程序不应依赖于确认的顺序 可能。
乍一看,这是有道理的:持久化消息比仅仅将其存储在内存中要花费更多的时间,因此很可能稍后的临时消息的确认将在较早的持久消息的确认之前到达。
但是,如果我们重新阅读上面关于消息顺序 [QUOTE 1] 的第一条引文,就会感到困惑。我会解释的。假设我们向同一个交换器发送两条消息:首先是持久消息,然后是瞬态消息。既然 RabbitMQ 声称要保留消息顺序,那么它如何在知道第一条/持久消息确实已完全写入磁盘之前发送对第二条/临时消息的确认?
换句话说,上面关于不合逻辑的确认顺序 [QUOTE 2] 的评论是否仅适用于两条消息各自路由到完全不同的目标队列的情况(如果例如,它们有不同的路由键)?在这种情况下,我们不必保证 [QUOTE 1] 中所做的任何事情。
[*] 在大多数情况下,这意味着“排队”。但是,如果没有适用的路由规则,则无法将其排入目标队列。但是,这对于发表确认来说仍然是一个积极的结果。
更新
我在一个类似的问题上阅读了这个answer。这基本上说没有任何保证。即使是最幼稚的实现,我们将消息 2 的发布延迟到我们得到消息 1 的确认之后,也可能不会产生所需的消息顺序。基本上,[QUOTE 1]不满足。
这是正确的吗?
【问题讨论】:
-
我正要参考我在邮件列表中的帖子,谢谢 Luke。如果迈克尔/您也想在此处提供关于 SO 的答案,请随时这样做。如果没有,我将在本周晚些时候在此处复制/粘贴迈克尔的答案(附上推荐信/名单)。