Skip to content

概念卡片:RabbitMQ 消息可靠性

一句话机制:消息从发送到消费要经历「Producer → Exchange → Queue → Consumer」多跳,每一跳都可能丢消息;可靠性靠四件事兜底——生产者 confirm/return 确认、MQ 持久化、消费者 ack、失败重试 + 死信,再配合幂等防重复消费。

消息丢失的三个环节与对策

环节丢失原因对策
发送时消息未达 Exchange / 未达 Queue生产者确认:confirm(到 Exchange)/ return(到 Queue 失败退回)
MQ 宕机Queue 未持久化持久化:queue + message 都设持久化
消费时消费者收到后未处理就宕机消费者 ack:处理成功才 ack,否则重试

可靠性四件套

yaml
spring:
  rabbitmq:
    publisher-confirm-type: correlated   # 生产者确认(producer→exchange)
    publisher-returns: true              # 退回模式(exchange→queue 失败)
    listener:
      simple:
        acknowledge-mode: auto           # 消费者自动 ack(处理成功后确认)
        retry:
          enabled: true                  # 失败重试
          max-attempts: 3

重试仍失败 → 投递到死信交换机(Dead Letter Exchange),由 MessageRecoverer 转人工处理,避免无限重试。

三个进阶难题

难题解法
重复消费幂等:业务侧唯一 ID(如订单号)去重,或用消息去重表
顺序性同一业务 key 的消息路由到同一个队列(单消费者消费),或多消费者用「分区」保证局部有序
消息积压临时扩容消费者、批量消费、降级非核心消息,积压严重时直接扩容消费者实例

不变量(必须成立的约束)

  • 可靠性三件套(confirm + 持久化 + ack)缺一环都会丢消息,必须全部开启。
  • ack 是「处理成功才确认」,配 auto 模式由 Spring 在方法正常返回后 ack,异常则不 ack 触发重试。
  • 消息队列本身不保证顺序,要顺序必须「同 key 进同队列 + 单消费者」。
  • 幂等是消费端的责任(RabbitMQ 不保证 exactly-once),靠业务唯一 ID 去重。

踩坑案例

  • 现象:消费者处理失败,消息被无限重试打爆日志。 原因:没配死信交换机/重试上限。解决:配 retry.max-attempts + 死信队列,重试耗尽后转人工。

常见误解

  • 以为「消息不丢」只靠持久化 → 持久化只防「MQ 宕机丢失」,发送丢失靠 confirm、消费丢失靠 ack,是三件事。
  • 以为 MQ 保证消息不重复 → MQ 是「至少一次投递」,可能重复,去重靠消费端幂等。

关联

最近更新