go连rabbitmq关键在连接复用、队列声明语义、ack机制三处:amqp.dial()须单例带心跳,queuedeclare必须durable:true且autodelete:false,消费者必须autoack:false并显式ack/nack,缺一则丢消息或卡死。

Go 连 RabbitMQ 不是“连上就行”,关键在连接复用、队列声明语义、ACK 机制三处——错一个,线上就丢消息或卡死。
amqp.Dial() 必须只调一次,且带心跳配置
反复调用 amqp.Dial() 会导致连接泄漏、端口耗尽,RabbitMQ 主动断连后你的 ch.Publish() 会 panic:Exception (504) Reason: "channel/connection is not open"。
- 连接必须全局单例,封装成
*amqp.Connection字段,启动时初始化一次 - 务必传
amqp.Config{Heartbeat: 10 * time.Second},否则 K8s 或云 LB 空闲 30 秒后静默断开 - URL 必须是标准 AMQP 格式:
"amqp://myapp:pass123@localhost:5672/%2F",%2F是 vhost/的 URL 编码,写成/或空字符串直接报ACCESS_REFUSED - 别用
guest:guest:RabbitMQ 3.3+ 默认禁止远程登录,Docker 或集群环境必挂
QueueDeclare 的 durable 和 autoDelete 参数不能乱设
队列不持久,RabbitMQ 一重启,队列消失,哪怕消息标了 Persistent 也无处可存;autoDelete 开着,最后一个消费者断开,队列就被删,新实例启动直接 NOT_FOUND。
使用 uber-go/dig 在 Golang 中实现依赖注入——基于反射容器,提供 Provide/Invoke、dig.In/dig.Out 参数与结果对象,支持命名依赖等
-
durable: true→ 必须设,队列元数据落盘,服务重启不丢失 -
autoDelete: false→ 必须关,否则消费者断开即删队列 -
exclusive: false→ 必须关,排他队列只允许一个连接,多实例部署直接失败 - 已存在的非持久化队列无法通过
QueueDeclare改成持久化,得手动rabbitmqctl delete_queue后重建
消费者必须禁用 autoAck 并配 Qos,否则消息秒丢
默认 autoAck: true 下,RabbitMQ 把消息发出去就立刻从队列删掉——你程序 panic、网络中断、甚至只是 time.Sleep(10 * time.Second) 没执行完,消息永久蒸发。
-
autoAck: false→ 第三个参数必须为false,如ch.Consume("q", "", false, false, false, false, nil) -
ch.Qos(1, 0, false)→ 限流防积压,避免单个 goroutine 堆满未确认消息,其他消费者饿死 -
msg.Ack(false)或msg.Nack(false, true)必须在接收该msg的同一个ch上调用,跨 goroutine 传msg时别漏传ch -
msg结构体不是线程安全的,别在多个 goroutine 里并发调Ack/Nack
publish 时 deliveryMode 和 exchange 要匹配业务语义
填错 deliveryMode 或 exchange 名,等于发了一张无效支票:不报错,但消息进不了队列,查日志全是静默失败。
- 核心消息(如订单创建)必须设
DeliveryMode: amqp.Persistent,否则内存 crash 后全丢 - 直连模式下,
exchange填空字符串"",则routingKey必须严格等于队列名;若填自定义 exchange 名,必须先ch.ExchangeDeclare+ch.QueueBind - 想确保消息至少被路由一次,加
mandatory: true并提前ch.NotifyReturn注册回调,否则无匹配队列时消息直接丢弃 -
ch.Publish()返回nil错误 ≠ 消息成功投递,它只是表示“发出去了”,后续路由是否成功要靠mandatory或监控插件验证
最易被忽略的是:队列和交换机的 durable 属性必须同时开启,消息的 Persistent 才真正生效;而生产者、Broker、消费者三方的 ACK 链路缺一不可——这三处没对齐,谈不上“可靠消息”。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










