消息队列服务(包括RabbitMQ)的主要特性之一是保留消息发布顺序。这在RabbitMQ文档中得到了证实:
**[QUOTE 1]**AMQP 0-9-1核心规范的第4.7节解释了保证排序的条件:在一个通道中发布、通过一个交换机和一个队列以及一个输出通道的消息将按照它们发送的相同顺序被接收。RabbitMQ自2.7.0版本以来提供了更强的保证。
让我们假设在下面没有消费者活动,以简化事情。我们通过一个渠道发布。
到目前为止,一切顺利。
RabbitMQ还提供了通知发布者某个发布已经完全正确处理的可能性**[*]**。这在这里解释。基本上,代理将发送basic.ack
或basic.nack
消息。文档还说:
[QUOTE 2]basic.ack
对于路由到持久队列的持久消息,将在将消息持久化到磁盘后发送。
在大多数情况下,RabbitMQ将以发布的顺序向发布者确认消息(这适用于在单个通道上发布的消息)。但是,发布者确认是异步发出的,可以确认单个消息或一组消息。发出确认消息的确切时间取决于消息的传递模式(持久与transient)和消息路由到的队列的属性(见上文)。也就是说,不同的消息可以被认为在不同的时间准备好确认。这意味着,与它们各自的消息相比,确认可以以不同的顺序到达。如果可能的话,应用程序不应该依赖于确认的顺序。
乍一看,这是有道理的:持久化一条消息所花费的时间比仅仅将其存储在内存中要多得多,因此,很有可能对稍后的瞬时消息的确认将在对较早的持久化消息的确认之前到达。
但是,如果我们重新阅读上面关于消息顺序的第一句话**[QUOTE 1],它会变得令人困惑。我会解释的假设我们向同一个交换机发送两条消息:首先是持久消息,然后是瞬时消息。由于RabbitMQ声称保留消息顺序,那么在它知道第一条/持久化消息确实完全写入磁盘之前,它如何发送第二条/临时消息的确认呢?
换句话说,上面关于不合逻辑的确认顺序[QUOTE 2]的评论是否仅适用于两个消息各自被路由到完全不同的目标队列的情况(例如,如果它们具有不同的路由键,则可能发生这种情况)?在这种情况下,我们不需要像[QUOTE 1]**中所做的任何保证。
**[*]**在大多数情况下,这意味着“已删除”。但是,如果没有适用的路由规则,则无法将其加入目标队列。然而,这仍然是关于出版物确认的积极结果。
更新
我读了这个answer关于类似的问题。这基本上是说,没有任何保证。即使是最简单的实现,也就是我们将消息2的发布延迟到我们得到消息1的确认之后,也可能不会产生所需的消息顺序。基本上,**[QUOTE 1]**不满足。
是这样吗?
1条答案
按热度按时间piwo6bdm1#
从
rabbitmq-users
上的响应来看:RabbitMQ知道消息在队列中的位置,不管它是否是 transient 的。
我的猜测(我没有写那部分文档)ack排序部分主要试图传达,如果两条消息被路由到两个不同的队列,这些队列将同时处理/复制/持久化它们。关于在 * 多个 * 队列中排序的推理是相当困难的。一条消息也可以进入多个队列。
尽管如此,RabbitMQ队列知道消息在什么队列中的位置。一旦处理发布的通道接收到所有路由/传递通知,它就会被添加到要发送的通知列表中。请注意,该列表可能会或可能不会以与原始发布相同的方式进行排序,担心这一点是不切实际的,原因有很多,最重要的是:用户通常主要关心队列中的排序。