RabbitMQ 发送方确认机制

消费者有确认,生产者同样需要确认:消息发出去后,broker 到底收没收到?Publisher Confirm(发送方确认)让生产者在消息被 broker 正确接收后得到通知,是可靠投递链路的第一环。

confirm 机制原理

Publisher Confirm 时序 生产者先把信道切到确认模式(confirm.select),之后该信道上每一条消息 broker 都会回一个结果:正常时回 Basic.Ack(带自增的 delivery tag),无法处理时回 Basic.Nack 或直接断开连接。生产端据此判断"这条要不要重发"。

Java 客户端开启并同步等待确认:

// 以下片段需放进使用 RabbitMQ Java 客户端的方法中运行
Channel ch = conn.createChannel();
ch.confirmSelect();                       // 开启发送方确认
ch.basicPublish("", "q.demo", null, "hello".getBytes());
if (ch.waitForConfirms(5000)) {           // 同步等待最多 5 秒
    System.out.println("发送成功");        // 输出:发送成功
} else {
    System.out.println("收到 nack,需要重发");   // 输出:收到 nack,需要重发
}

waitForConfirms 会阻塞到该信道所有待确认消息出结果:全部 ack 返回 true,出现 nack 返回 false,超时或连接断开抛异常。异常时消息状态未知,重发前要做好幂等防重复。

异步 confirm(高吞吐推荐)

逐条同步等待只适合消息量小的场景。吞吐要求高时应注册监听器,由 broker 异步回调:

// 以下片段需放进使用 RabbitMQ Java 客户端的方法中运行
ch.addConfirmListener(
    (tag, multiple) -> System.out.println("已确认: " + tag),   // ack 回调
    (tag, multiple) -> System.out.println("未确认: " + tag));  // nack 回调

ack 的 delivery tag 是单调递增的序号,配合 multiple 参数可以判断"这条之前是否已全部确认",用于设计批量重发窗口。

与事务(txSelect)对比

RabbitMQ 也支持 AMQP 事务:txSelect 开启、txCommit 提交、txRollback 回滚,同样能保证消息被接收,但每次提交都涉及多轮同步往返,吞吐明显低于 confirm:

方案保证性能推荐度
事务 txSelect/txCommit/txRollback低(多次同步往返)不推荐
Publisher Confirm高(可异步批量确认)推荐

mandatory 与 returned message

confirm 只能证明 broker"接收"了消息,证明不了"路由到了队列"。若发布时设 mandatory=true 而消息不可路由(交换机没有匹配绑定),broker 会通过 basic.return 把消息退回生产者,生产端要在 return 回调里记录或补偿:

// 以下片段需放进使用 RabbitMQ Java 客户端的方法中运行
ch.addReturnListener((replyCode, replyText, exchange, routingKey,
    props, body) -> System.out.println("消息被退回: " + new String(body)));

不带 mandatory 的不可路由消息会被 broker 静默丢弃。因此"不丢消息"要同时做三件事:mandatory 捕获不可路由、confirm 捕获未接收、队列与消息持久化防宕机。

可靠投递全链路清单

一条消息从生产到消费,可靠投递由三层确认拼接而成:

环节手段防止的问题
生产者 → brokerconfirm(+mandatory)发送失败、不可路由
broker 存储队列 durable + 消息持久化节点宕机丢消息
broker → 消费者手动 ack处理失败丢消息

任一环节缺位,整条链路都可能"看似成功实则丢失"。

小结

Publisher Confirm 是生产端可靠投递的基石:confirmSelect 开启后按 ack/nack 判断发送结果,高吞吐用异步监听;它比事务性能好,配合 mandatory、持久化与消费者手动 ack,才能拼出全链路不丢。

笔记加载中…