生产环境必须禁用 autoAck=true,因其导致消息未处理完即被确认而永久丢失;应设 autoAck=false 并显式 Ack/Nack,配合 QoS、持久化、幂等设计与死信队列保障可靠性。
autoAck 设为 true 是生产环境最大隐患不是功能不全,而是它会让消息在消费者崩溃瞬间永久丢失——RabbitMQ 一发出去就认为“已送达”,根本不等你业务逻辑跑完。微服务滚动更新、OOM 或 panic 都会触发这个黑洞。
autoAck: false,并在业务处理成功后显式调用 delivery.Ack(false)
delivery.Nack(false, false) 拒绝并丢弃;若可重试,用 delivery.Nack(false, true) 让消息重回队尾delivery 对象绑定到特定 amqp.Channel,跨 goroutine 传递时务必连同 ch 一起传,否则 Ack() 会 panic 报 "invalid channel"
ch.Qos(1, 0, false) 限制预取数,避免单个消费者积压几十条消息,导致其他实例“饿死”amqp.Dial() 在每
频繁 amqp.Dial() 会导致端口耗尽、TLS 握手风暴,K8s 环境下常被 NetworkPolicy 主动断连。Kratos、Gin 等框架启动即长驻,连接必须复用。
*amqp.Connection,例如 internal/mq/rabbitmq.go 中的 NewRabbitMQConn()
amqp.Config{Heartbeat: 10 * time.Second},避开默认 30 秒心跳与云网络空闲超时冲突Channel 不是线程安全的,每个 goroutine 处理消息前调用 ch, _ := conn.Channel(),用完立刻 ch.Close();切勿全局复用一个 Channel
durable: true 是底线——否则 RabbitMQ 重启,队列元数据直接消失;但光设这个不够,发送消息还得加 DeliveryMode: amqp.Persistent 才能持久化消息体message_id 做去重网络重试、消费者 crash 后重连、RabbitMQ 镜像同步延迟,都可能造成同一条消息被投递两次。仅校验 message_id 无法覆盖所有场景,尤其当消息体含时间戳或随机字段时。
{"order_id": "ORD-20260119-789", "event_type": "payment_succeeded"},而非自动生成的 UUIDorder_id + event_type 的成功记录,再执行业务逻辑;成功后立即写入状态表(task_status 表中 status = 'success')SET key value EX 3600 NX 做轻量幂等锁,失败则直接 NACK,避免阻塞主流程json.Unmarshal(),失败即 NACK 并打结构化日志,不静默跳过没有 DLQ 的 RabbitMQ 消费者,就像没有刹车的车——失败消息反复重试,最终卡死整个队列,新消息进不来,监控也只报“消费延迟高”,根本看不出哪条消息在捣鬼。
args: amqp.Table{"x-dead-letter-exchange": "dlx", "x-dead-letter-routing-key": "dlq.order"}
Expiration: "30000"),或靠消费者 NACK 触发重试计数,累计 3 次失败自动转入 DLQdurable: true,并配独立消费者——只做两件事:记录原始消息到 ES/MySQL,发告警(如企业微信机器人)RabbitMQ 在 Go 微服务里真正难的从来不是“怎么连上”,而是连接怎么不死、消息怎么不丢、重复怎么不崩、失败怎么可查——这些点没对齐,再多的 goroutine 也救不了系统稳定性。