AMQP连接需全局复用Connection、按需创建Channel;消息持久化须队列durable、DeliveryMode=Persistent、mandatory=true;消费者必须autoAck=false且业务成功后显式Ack;Confirm模式需监听NotifyPublish并处理超时重试。

amqp.Dial 不能写在发消息函数里
每调用一次 amqp.Dial 就建一个 TCP 连接,短连接高频调用会迅速耗尽本地端口,出现 connect: cannot assign requested address。这不是 RabbitMQ 拒绝你,是操作系统扛不住了。
- Connection 是重量级资源,必须全局复用(比如用
sync.Once初始化单例) - Channel 才是轻量级的,每个 goroutine 发/收消息前调
conn.Channel(),用完立刻ch.Close() - 连接字符串建议加超时参数:
"amqp://guest:guest@localhost:5672/?connect_timeout=5",避免 DNS 卡死整个 goroutine
发消息不持久 = 重启就丢
默认 amqp.Publishing{Body: []byte("x")} 是内存消息,Broker 崩溃或重启后全消失。生产环境必须显式配齐三要素:
- 队列声明时设
durable: true(否则即使消息落盘也无处可存) - 发送时设
DeliveryMode: amqp.Persistent - 加
mandatory: true,让路由失败(比如 exchange 不存在)时立即报错,而不是静默吞掉
漏掉任意一项,都可能在压测或发布后突然发现“消息凭空消失”。
消费者不手动 Ack = 消息可能被跳过
RabbitMQ 默认是 auto-ack 模式(autoAck: true),一旦投递就立刻从队列删掉。业务 panic、DB 写失败、甚至 just forget to delivery.Ack(false),都会导致消息永久丢失。
使用 uber-go/dig 在 Golang 中实现依赖注入——基于反射容器,提供 Provide/Invoke、dig.In/dig.Out 参数与结果对象,支持命名依赖等
立即学习“go语言免费学习笔记(深入)”;
- 务必设
autoAck: false - Ack 必须放在业务成功之后,且顺序是:幂等校验 → 执行逻辑 → 成功再
delivery.Ack(false) - 别在 defer 里 Ack —— defer 在函数退出时才执行,panic 后照样触发
channel.Confirm() 不等于消息已送达
调 ch.Confirm() 只是开启 publisher confirm 模式,不代表后续 ch.PublishWithContext 会等 Broker 确认。不监听 ch.NotifyPublish(),就等于没开确认。
- 要真正实现可靠投递,得配合
select+ch.NotifyPublish()监听 confirm 或 nack - 别用同步阻塞方式等每条确认,会严重拖慢吞吐;建议批量发 + 异步回调 + 超时重试
- 注意:confirm 模式下 channel 关闭前必须等所有未确认消息完成,否则可能漏通知
持久化、Ack、Confirm 这三层不是选做题,是生产环境的入场券。少配一个,问题往往不在日志里,而在凌晨三点的告警电话里。

















