跳至主要内容
版本:4.0

代理语义

这里描述了代理语义。应将其与 AMQP 规范一起阅读。

tx 的语义

AMQP 0-9-1 中定义的 AMQP 的 tx 类及其在不同版本的 RabbitMQ 服务器中的实现通常存在误解。以下是行为摘要

功能

AMQP
0-9-1

RabbitMQ
< 2.6.0

RabbitMQ
2.6.0-2.7.1

RabbitMQ
>= 2.8.0

事务性 basic.publish
事务性 basic.ack
事务性 basic.reject
事务性交换/队列/绑定创建/删除
事务性消费/获取消息
单个队列中的原子性
跨多个队列的原子性
错误检测(例如无效交换)未定义立即立即立即
发送“no_route” basic.return未定义立即在提交时在提交时
效果可见性/责任转移/持久性未定义在提交时在提交时在提交时

总体而言,AMQP tx 类的行为,尤其是其在 RabbitMQ 上的实现,更接近于提供“批处理”功能,而不是数据库世界中已知的 ACID 功能。

AMQP 事务仅适用于发布和确认。我们还将拒绝设置为事务性的。其他操作(如资源创建/删除)不是事务性的。因此,当任何涉及的交换、队列或绑定发生更改时,事务的行为是未定义的

在消费方面,确认是事务性的,而不是消息本身的消费。因此,在回滚时不会重新排队已消费的消息;客户端仍然可以在后续事务中确认/拒绝这些消息。

AMQP 仅保证当事务涉及单个队列时具有原子性,即 tx 内的所有发布都路由到单个队列,并且所有确认都与从同一队列中消费的消息相关。当涉及多个队列时,如果代理在 tx.commit 期间出现故障,则该事务的效果可能只在其中一些队列中可见。此外,RabbitMQ 即使在涉及单个队列的事务的情况下也不提供原子性保证,例如在 tx.commit 期间出现故障可能会导致代理重启后出现事务发布的子集出现在队列中。

AMQP 未指定何时应检测事务性 basic.publishbasic.ack 命令中的错误(例如,缺少权限、对未知交换的引用)。RabbitMQ 立即执行必要的检查(而不是在提交时),但请注意,basic.publishbasic.ack 都是异步命令,因此任何错误都将异步报告回客户端。

情况类似于 basic.return,不过请注意 RabbitMQ 早期版本和近期版本之间的行为略有不同。您将始终在 tx.commit-ok 之前收到任何 basic.return

AMQP 未指定 tx.commit 后事务的效果何时变得可见,例如,何时发布的消息将出现在队列中并可供其他客户端消费,何时持久消息将写入磁盘等。在 RabbitMQ 中,tx.commit-ok 表示所有事务效果均可见,并且代理已接受对事务中发布的所有消息的责任。

对于确认,收到 tx.commit-ok 表示服务器已收到确认,而不是表示已处理、持久化等。因此,后续的服务器端故障可能会“恢复”已确认的消息,并且消费客户端可能会再次收到它们。

消息排序保证

AMQP 0-9-1 核心规范的第 4.7 节解释了保证排序的条件:通过一个交换和一个队列以及一个输出通道发布在一个通道中的消息将按发送顺序接收。RabbitMQ 从 2.7.0 版本起提供了更强的保证。

可以使用具有重新排队参数的 AMQP 方法(basic.recoverbasic.rejectbasic.nack)将消息返回到队列,或者由于通道在持有未确认的消息时关闭而导致消息返回。在 2.7.0 之前的 RabbitMQ 版本中,任何这些场景都会导致消息重新排队到队列的末尾。从 RabbitMQ 2.7.0 版本起,即使在重新排队或通道关闭的情况下,消息也始终按发布顺序保存在队列中。

在 2.7.0 及更高版本中,如果队列有多个订阅者,则单个消费者可能会观察到消息乱序。这是由于其他订阅者可能重新排队消息造成的。从队列的角度来看,消息始终按发布顺序保存。

独占队列和持久性

独占队列是在声明它的连接关闭时被删除的队列。虽然 AMQP 0-9-1 允许您声明持久性独占队列,但持久性是毫无意义的,因为一旦代理停止,队列就会消失。因此,RabbitMQ 会忽略独占队列声明中的持久性标志,并创建一个独占性瞬态队列。

获取帮助并提供反馈

如果您对本指南的内容或与 RabbitMQ 相关的任何其他主题有任何疑问,请随时使用 GitHub 讨论 或我们的社区 Discord 服务器 提问。

帮助我们改进文档 <3

如果您想为网站贡献改进,其源代码在 GitHub 上可用。只需分叉存储库并提交拉取请求。谢谢!

© 2024 RabbitMQ. All rights reserved.