说说 RabbitMQ 的事务机制?

#中间件#面试八股

说说 RabbitMQ 的事务机制?

结论:AMQP 协议提供 txSelect / txCommit / txRollback 三个命令,能保证"一批发布要么全部进入 Broker、要么全部不进入"。但它是同步阻塞的,每条消息都要等一次往返,吞吐会掉一到两个数量级;而且它管不了路由失败、Broker 宕机、消费端处理失败。所以生产环境用发布确认(Publisher Confirm)+ 手动 ack 替代它。

一、事务的执行过程

Producer                      Broker
   │  txSelect                  │  开启事务模式(信道级)
   ├───────────────────────────>│
   │  basicPublish(msg1)        │  暂存,不投递
   ├───────────────────────────>│
   │  basicPublish(msg2)        │
   ├───────────────────────────>│
   │  txCommit                  │  原子提交,两条一起入队
   ├───────────────────────────>│
   │  <──── tx.commit-ok ───────┤  同步等待,期间信道阻塞
   │
   │  若任一步失败 → txRollback → 全部丢弃
   └───────────────────────────>│

事务是信道级的:txSelect 之后这个 Channel 上的所有发布都在事务里,直到 commit 或 rollback。事务与 confirm 模式互斥,同一个 Channel 不能同时开启。

二、三种可靠性机制的分工

机制保证什么同步/异步相对吞吐生产是否使用
事务 tx一批发布原子入 Broker同步,每步等响应很低(基准的几十分之一)基本不用
发布确认 confirm消息被交换机/队列接收异步回调高常用
消费手动 ack业务处理成功后才确认异步高必用

三者解决的是不同环节:tx/confirm 管"发出去没有",ack 管"消费成功没有"。事务并不能替代另外两个。

三、代码对比

// 事务写法:同步、阻塞
channel.txSelect();
try {
    channel.basicPublish("order.ex", "order.created", null, body1);
    channel.basicPublish("order.ex", "order.created", null, body2);
    channel.txCommit();          // 两次发布一起生效
} catch (IOException e) {
    channel.txRollback();        // 一起失效
}
// confirm 写法:异步批量,吞吐高
channel.confirmSelect();
channel.addConfirmListener(
        (seq, multiple) -> markDone(seq, multiple),        // 成功
        (seq, multiple) -> retryLater(seq, multiple));     // 失败,走补偿
for (byte[] body : batch) {
    channel.basicPublish("order.ex", "order.created",
            MessageProperties.PERSISTENT_TEXT_PLAIN, body);
}

confirm 的关键差异是"不等结果就继续发",结果通过回调汇总;tx 则是"发一条等一条",网络往返次数与消息数成正比。

四、事务的三个局限

局限说明
管不到路由消息成功进入 Broker 但没有队列匹配,事务照样提交成功,消息被丢弃
管不到存储Broker 收到并提交后宕机,若消息未持久化、队列无副本,依然会丢
管不到消费消费端的失败与重复,事务机制完全不参与

所以"用事务保证不丢消息"是伪命题:它只把"发送失败"这一种情况排除掉了,其余环节仍要 confirm 的 mandatory/return、持久化、手动 ack 来守。

五、常见追问

  • 事务为什么这么慢? 每个命令都要同步等 Broker 的 tx.commit-ok,且事务期间信道被独占,无法流水线发送;Broker 侧还要为事务维护状态。
  • 事务能和 confirm 一起用吗? 不能。两者都改变信道的确认模式,同时开启会报错。
  • 消费端有事务吗? AMQP 的 tx 只作用于发布与确认,消费端没有"处理事务"的概念;业务要么手动 ack,要么用数据库事务 + 幂等来保证。
  • 什么场景还值得用事务? 极低频、强一致、消息量很小的管理类操作,比如一次只发一条配置变更;高吞吐业务没有理由用它。

小结

  • RabbitMQ 事务保证的是"一批发布原子进入 Broker",能力边界很窄。
  • 同步阻塞导致吞吐骤降,是它被 confirm 取代的根本原因。
  • 路由失败、存储丢失、消费失败都不在事务覆盖范围内。
  • 生产标配是 confirm + mandatory + 持久化 + 手动 ack + 幂等。
笔记加载中…