Docker容器内连接RabbitMQ时出现“lookup rabbitmq on 127.0.0.11:53: no such host”是典型DNS解析失败,根本原因在于容器内localhost不指向宿主机、跨容器通信需用服务名且确保同网络,连接字符串须为amqp://guest:guest@rabbitmq:5672/%2F。

connect时panic: dial tcp: lookup rabbitmq on 127.0.0.11:53: no such host
这是 Docker 容器内连接 RabbitMQ 最常见的 DNS 解析失败,不是代码问题,而是网络配置没对上。localhost 或 127.0.0.1 在容器里指向自己,根本连不到宿主机或另一个容器里的 RabbitMQ。
- 用 Docker Compose 时,直接写服务名(如
rabbitmq),确保在同一个 network 中 - 单独运行 Go 程序容器时,加
--network host或用--add-host=rabbitmq:172.17.0.2手动映射 IP - 连接字符串必须带端口和 vhost,例如
amqp://guest:guest@rabbitmq:5672/%2F(%2F是 URL 编码后的/) - 别漏掉
amqp://前缀,否则amqp.Dial会静默失败或 panic
channel.Publish 返回 nil error,但消息没进队列
Go 的 amqp.Publishing 默认是异步发包,不等 broker 确认就返回。如果 RabbitMQ 拒绝(比如队列不存在、权限不足、disk space alarm 触发),你根本收不到错误。
- 启用 publisher confirms:调用
ch.Confirm(false),然后用ch.NotifyPublish监听确认事件 - 检查
mandatory和immediate参数(后者已废弃,忽略;前者设为true可让 broker 在路由失败时退回消息) - 用
amqp.Table{"x-dead-letter-exchange": "dlx"}做兜底,避免消息静默丢失 - 不要依赖
err == nil就认为消息已落盘——RabbitMQ 的“成功发送”只代表进了 TCP buffer
consumer 处理崩溃后消息重复或丢失
默认 auto-ack 模式下,只要 Delivery.Ack 调用前进程挂了,消息就永久丢失;而手动 ack 时若忘记调用或 panic,消息会不断重投。
- 永远用
autoAck: false,并在处理逻辑完成后显式调用d.Ack(false) - 用
defer d.Nack(true, false)+recover()捕获 panic,避免未 ack 的消息卡住 - 消费端做幂等:用消息的
Delivery.Headers["x-death"]判断是否重试过,或用外部存储(如 Redis)记录已处理的deliveryTag或业务 ID -
qosPrefetchCount设太小(如 1)会导致吞吐骤降;设太大(如 1000)可能让单个 consumer 积压太多未 ack 消息,影响集群负载均衡
如何安全关闭 connection/channel
Go 程序退出时直接 os.Exit(0) 或 main 函数返回,会跳过 defer,导致 connection 没 close,RabbitMQ 侧残留 unclean shutdown 连接,积累多了触发 connection limit。
立即学习“go语言免费学习笔记(深入)”;
- 用
signal.Notify捕获os.Interrupt和syscall.SIGTERM - 在 shutdown 流程中先
ch.Close(),再conn.Close(),顺序不能反 - 给
conn.Close()加超时控制(如用context.WithTimeout包一层),防止卡死在 TCP FIN 等待 - 注意:
ch.Cancel只取消 consumer,不影响 channel 生命周期;真正释放资源靠ch.Close()


















