连上 rabbitmq 需用标准 amqp uri 格式如 "amqp://guest:guest@localhost:5672/%2f",注意 vhost 必须编码;云环境需开放 5672 端口;推荐使用新 sdk github.com/rabbitmq/amqp091-go。

怎么连上 RabbitMQ?先看 amqp.Dial 的 URL 格式和常见报错
连不上是最常卡住的第一步,错误通常不是代码写错,而是 URL 拼错或权限/网络没开。amqp.Dial 接收的是标准 AMQP URI,形如 "amqp://user:pass@host:port/vhost",不是 HTTP 地址,也不能漏掉 vhost(默认是 /,但必须编码为 %2F)。
- 本地默认连接应写成
"amqp://guest:guest@localhost:5672/%2F",写成"/"或空字符串会报"channel error: 403 ACCESS_REFUSED" - 云环境(如腾讯云)必须确认安全组放行了
5672(AMQP)和15672(管理界面),否则dial tcp: i/o timeout是网络层拒绝,不是密码错 - Go 官方推荐用新 SDK
github.com/rabbitmq/amqp091-go,旧库streadway/amqp已归档,新库对 context 取消、TLS 配置更清晰,但 API 几乎一致,迁移成本低
ch.Publish 发不出消息?检查 exchange、routing key 和队列是否真正绑定
发消息返回 nil 错误不代表成功——RabbitMQ 默认是“发完即忘”,不校验目标是否存在。消息丢了,往往是因为 exchange 名字为空(用了默认 direct exchange)、routing key 不匹配,或者队列根本没声明/没绑定。
- 简单队列模式下,
exchange参数传空字符串"",routing key必须等于队列名,否则消息进不了队列 - 如果想确保消息至少被路由一次,加上
mandatory: true,这样当无队列匹配时会触发Return通道回调(需提前用ch.NotifyReturn注册) - 队列必须由消费者或生产者显式
QueueDeclare,不能只靠Consume自动创建——后者只在 auto-delete 队列且无其他绑定时才生效,不可靠
消费者收不到消息?重点查 autoAck、Qos 和 channel 复用问题
最典型的假象是:程序没报错、ch.Consume 返回了 msgs 通道,但一直阻塞——其实消息早到了,只是被 Go 协程卡在 channel 缓冲区里,或者被 QoS 限流锁死了。
-
autoAck: false时,必须调用msg.Ack(false)手动确认,否则 RabbitMQ 认为消息还在处理中,不会再推新消息(尤其多个消费者时,你会看到消息堆积在 ready 状态) - 务必设置
ch.Qos(1, 0, false),限制每个 channel 最多一个未确认消息。不设的话,默认无上限,大量消息涌入可能压垮消费者内存,或导致超时重发混乱 - 不要跨 goroutine 复用同一个
*amqp.Channel——它不是并发安全的。每个消费者协程应独占一个 channel,连接(*amqp.Connection)才可复用
消息丢失怎么办?持久化不是开关,得三处都配对
标了 DeliveryMode: amqp.Persistent ≠ 消息一定不丢。RabbitMQ 的持久化是端到端链条:生产者发、交换机存、队列存、消费者确认,缺一不可。
- 队列声明必须设
durable: true,否则重启后队列消失,即使消息标了持久也没地方存 - exchange 也得是 durable 类型(默认直连 exchange 就是 durable,但自定义 exchange 声明时要显式传
true) - 消费者手动确认(
autoAck: false)后,再做业务处理;若处理失败,调msg.Nack(true, false)重新入队,而不是直接 panic 或忽略
最容易被忽略的是:哪怕全配了持久化,如果 RabbitMQ 服务本身没开启 disk_failure 保护或磁盘满,消息照样静默丢弃——上线前一定要跑一次断电测试。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











