RabbitMQ-消息可靠性-publisher-confirm持久化与手动ack

RabbitMQ 消息可靠性:publisher confirm、持久化与手动 ack

消息发出去不代表到了。本文梳理 RabbitMQ 消息丢失的三个环节(发布端、Broker、消费端),并给出 publisher confirm、持久化和手动 ack 的完整可靠性方案。

一、问题案例

订单服务通过 RabbitMQ 发「下单成功」消息给下游,偶尔下游说没收到,订单状态对不上。查日志,发布端明明「发送成功」了,消费者却没消费。

java 复制代码
rabbitTemplate.convertAndSend("order.exchange", "order.create", msg);
// 返回了,就以为发出去了

二、原理详解:消息丢失的三个环节

消息丢失可能发生在三个环节:

  1. 发布端 → Broker :没开 publisher confirm,convertAndSend 只是「发出去就返回」,不保证 Broker 真的收到。exchange 名字写错、路由不到队列,消息直接丢,发布端无感。
  2. Broker 内部:exchange / 队列没有持久化,Broker 重启后消息丢失。
  3. Broker → 消费者:没有手动 ack,消费者拿到消息就丢;或者 ack 策略不对,导致重复投递混乱。

三、实战代码:可靠性三件套

发布端开 confirm + return:

yaml 复制代码
spring.rabbitmq.publisher-confirm-type: correlated
spring.rabbitmq.publisher-returns: true

队列和消息持久化:

java 复制代码
// 声明持久化队列
new Queue("order.queue", true);

// 发送时消息持久化
Message message = MessageBuilder.withBody(payload)
        .setDeliveryMode(MessageDeliveryMode.PERSISTENT)
        .build();

消费者手动 ack:

yaml 复制代码
spring.rabbitmq.listener.simple.acknowledge-mode: manual
java 复制代码
@RabbitListener(queues = "order.queue")
public void onMessage(Message message, Channel channel) throws IOException {
    try {
        // 处理业务
        channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
    } catch (Exception e) {
        channel.basicNack(message.getMessageProperties().getDeliveryTag(), false, true);
    }
}

四、常见踩坑

  • confirm 后仍可能重复投递:确认只保证「Broker 收到了」,不保证「只投递一次」,消费端要做幂等。
  • 可靠性是组合拳:发送确认 + 持久化 + 手动 ack + 幂等,缺一环就可能丢消息或重复消费。

五、总结

  • 消息丢失有三环:发布端、Broker、消费端,都要防。
  • confirm + 持久化 + 手动 ack,三件套缺一不可。
  • 消费端幂等,兜底重复投递。

我是无羡(小剑),全栈偏后端的独立开发者。

作品集:无羡 · 独立开发者作品集

如果对你有帮助,欢迎点赞、收藏、关注。

相关推荐
xxwl5851 天前
RabbitMQ 学习笔记
笔记·学习·rabbitmq
zhangzeyuaaa2 天前
深入 Ruby:Block、Proc、Lambda 核心区别与最佳实践
开发语言·前端·ruby
ly76892 天前
Redis 分布式锁的边界条件:Redlock 争议、锁续期与客户端崩溃后的互斥失效
数据库·redis·分布式·分布式锁·watchdog·redlock
灯澜忆梦2 天前
【minio】#5 | MinIO 分布式部署 + HTTPS 部署
分布式·网络协议·https·对象存储·minio
谢亮_vipxieliang3 天前
Spring Cloud 服务治理入门:注册发现、配置中心、网关限流、熔断降级与分布式一致性方案
分布式·spring·spring cloud
zhangzeyuaaa3 天前
深入理解 Ruby 运算符:本质、分类、坑点与重载实战
开发语言·前端·ruby
樱花落木兰3 天前
分布式登录实战:Session 会话共享改造,Redis 存储用户登录状态
java·javascript·数据库·redis·分布式·缓存
ShineWinsu3 天前
对于Redis:Steam、Geospatial、Hyperloglog、Bitmap、Bitfield类型的解析
数据库·c++·redis·分布式·缓存·面试·zset
zhangzeyuaaa3 天前
Ruby 方法参数完全指南:默认值、可变参数与关键字参数
前端·python·ruby