RabbitMQ 消息确认机制

RabbitMQ 采用"投递—确认"模型保证消息不丢:消息发给消费者后 broker 并不会立刻删除它,而是等消费者返回确认,确认成功才真正移除。理解这套机制是写出可靠消息应用的前提。

消息何时被删除

消息投递与确认流程 区别只在"确认"这一步:自动确认下,broker 把消息发出就算完成并删除;手动确认下,消费者处理完调用 ack 后 broker 才删除。若消费者在处理中途断开,未确认的消息会被重新入队,稍后再投给其它消费者。

三种确认方式

方式触发broker 行为适用
自动确认无需消费者参与,投递即算完成立即删除允许少量丢失
手动确认 basicAck处理成功后调用收到 ack 才删除需要可靠处理
否定确认 basicNack/basicReject处理失败后调用重回队列或丢弃/转死信失败重试

各客户端默认确认模式并不一致,务必按文档确认;需要手动确认时要显式开启(pika 消费时传 auto_ack=False,Spring 将确认模式设为 MANUAL)。

ack 与 requeue 语义

basicAck 只表示"这条我处理完了"。处理失败时用 basicReject 或 basicNack 告诉 broker:

  • requeue=true:消息重回队列,稍后重新投递(可能是本消费者,也可能换一个);
  • requeue=false:消息不回队列,直接被丢弃;若业务队列配置了死信交换机,则转入死信队列(见死信队列章节)。
def on_msg(ch, method, props, body):
    try:
        handle(body)                      # 业务处理
        ch.basic_ack(delivery_tag=method.delivery_tag)   # 成功确认
    except Exception:
        # 失败重回队列,注意避免"失败-重投"死循环
        ch.basic_nack(delivery_tag=method.delivery_tag, requeue=True)
ch.basic_consume("q.task", on_message_callback=on_msg, auto_ack=False)

basicReject 与 basicNack 的区别

两者语义几乎一致,唯一区别是 nack 支持 multiple 批量否定,reject 一次只能拒绝一条:

方法multiple 参数单条批量
basicReject支持不支持
basicNack支持支持(multiple=true 时否定多条未确认)

日常开发优先用 basicNack;需要否定当前信道所有未确认消息时传 multiple=true。

未确认消息积压与连接断开重投

消费端一直不 ack,消息会以 unacked 状态积压在队列中占用内存,甚至触发 broker 告警;消费者连接断开或 channel 关闭时,这些未确认消息会被 broker 重新入队并再次投递。

要警惕:慢消费者 + 大批量手动确认的场景下,未 ack 消息堆积会拖垮内存,需配合下一章的 prefetch 限流使用。

幂等性提醒(at-least-once)

手动确认保证的是"至少一次"投递(at-least-once):消息可能在处理成功但 ack 丢失时被重复投递。因此消费逻辑必须做成幂等:用业务唯一键(订单号、消息 ID)建唯一索引,重复消息直接跳过,不要指望 broker 保证"只投一次"。

小结

确认机制决定了消息何时从队列删除:自动确认快但会丢,手动确认稳但要求处理成功必须 ack、失败用 nack/reject 决定重回队列还是转死信。配合幂等消费,才能消化"至少一次"投递带来的重复风险。

笔记加载中…