rabbitmq消息不丢失需主动配置:消费端必须设autoack=false并手动调用ack/nack,生产端启用confirm机制、消息与队列均持久化,且以业务幂等键(如order_id)替代deliverytag做去重。

消息不丢失不是默认行为,而是必须主动配置的链路状态。RabbitMQ 在 Go 中不会自动帮你保消息——autoAck=true 是默认值,它意味着“发完就删”,业务还没跑,消息已经没了。
ch.Consume() 的 autoAck 参数必须设为 false
这是消费端防丢的第一道铁闸。设成 true,RabbitMQ 一推送就从队列里物理删除消息;哪怕 processMessage() 第一行就 panic,消息也永远不重试。
-
ch.Consume(queueName, "", false, false, false, false, nil)—— 第三个参数false表示禁用 autoAck - 忘记改这个参数,管理界面看到的
Unacked永远是 0,容易误判“一切正常” - 只适用于埋点、日志等允许丢失的场景;订单、支付、通知类业务必须关掉
msg.Ack() 和 msg.Nack() 必须在业务成功/失败后显式调用
手动确认不是锦上添花,而是唯一能绑定“业务处理完成”和“消息删除”的机制。调用时机、参数组合、调用次数都直接影响消息流向。
使用 uber-go/dig 在 Golang 中实现依赖注入——基于反射容器,提供 Provide/Invoke、dig.In/dig.Out 参数与结果对象,支持命名依赖等
- 每条
msg收到后,必须且只能调用一次msg.Ack(false)或msg.Nack(true, false) - 别在
defer里调msg.Ack()—— 它会在 for 循环外提前执行,把整批消息全确认掉 - panic 时必须
recover()并显式msg.Nack(true, false),否则该deliveryTag会卡死后续消息 -
msg.Nack(true, false):拒绝当前消息并重新入队(推荐用于临时错误);msg.Nack(false, false):直接丢弃(除非配了 DLX,否则进黑洞)
生产端必须启用 channel.Confirm() 并监听 Ack/Nack
只靠消费者端 ACK 不够。如果消息根本没进 RabbitMQ,或者 Broker 重启导致落盘失败,消费者连见都见不到它。
- 调用
ch.Confirm(false)必须在第一次ch.Publish()之前,且不可逆 - 用
ch.NotifyPublish()监听amqp.Confirmation,不能只看publish返回的err(网络成功 ≠ 消息落盘) - 收到
Nack或超时未确认,必须触发重试逻辑——静默忽略等于接受丢失 - 消息体要设
DeliveryMode: amqp.Persistent,但仅此不够:队列、Exchange 也得声明durable: true
deliveryTag 不是全局 ID,幂等 key 才是去重依据
deliveryTag 是 per-channel 单调递增的整数,只在当前 TCP 连接的 channel 内有效。它不能跨连接复用,也不能存进数据库做状态追踪。
- channel 关闭或连接断开后,所有未确认的
deliveryTag自动失效,RabbitMQ 可能重发对应消息 - 常见错误:把
deliveryTag当作幂等键记录到 DB,重启后无法对齐,导致重复处理或漏处理 - 真正该用的是业务层唯一标识,比如
order_id + event_type或 UUID 字段,配合数据库唯一索引或 Redis SETNX 做幂等判断
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










