rabbitmq 和 kafka 在 go 微服务中不可简单互换,选错会导致消息丢失、重复、乱序或消费者卡死;rabbitmq 需显式 ack、qos 控制与延迟插件支持,kafka 需监听 errors、设置 waitforall 确认、避免跨分区乱序,强一致场景优先 rabbitmq。

RabbitMQ 和 Kafka 在 Go 微服务中不是“换库就能跑”的平替,选错会直接导致消息丢失、重复消费、顺序错乱或消费者卡死——尤其在订单、支付、库存等强一致性场景下。
Go 里发一条 RabbitMQ 消息,为什么 ACK 总是漏掉?
RabbitMQ 的可靠性依赖显式 ACK,而 streadway/amqp 默认不自动确认,业务 panic 或提前 return 时极易遗漏 channel.Ack() 或 channel.Nack(),导致消息长期滞留在 unacked 状态,最终阻塞整个 queue。
- 必须用 defer 包裹
Ack()或Nack(),且确保在所有分支路径(包括 error 和 panic)都执行 - 不要依赖
autoAck: true,它绕过可靠性保障,只适合日志类非关键消息 - 消费者启动时务必设置
channel.Qos(1, 0, false)控制预取数,否则高并发下 unacked 消息堆积更快 - 若用延迟队列,需安装
rabbitmq-delayed-message-exchange插件,并在headers中显式传"x-delay",不是调用某个 delay 函数
Kafka 生产者用 sarama 写入,为什么消息总“消失”?
sarama.AsyncProducer 默认静默丢弃错误,Errors() channel 不监听就等于没开监控,网络抖动或 broker 不可用时消息直接蒸发。
- 必须启动 goroutine 持续读取
producer.Errors(),否则失败无感知 -
RequiredAcks: sarama.WaitForAll是强一致性前提,设成sarama.NoResponse或sarama.WaitForLocal会丢消息 - 批量发送时注意
ChannelBufferSize和Retry.Max,默认重试次数少,瞬时故障易失败 - Go 客户端不支持事务消息的完整两阶段提交语义,跨服务事务需靠外部补偿,别指望
BeginTxn能兜底
微服务间传递订单状态,该用 RabbitMQ 还是 Kafka?
订单创建 → 支付成功 → 库存扣减 → 发货通知,这条链路要求严格顺序和至少一次投递。RabbitMQ 单 queue + 单 consumer 天然保序;Kafka 必须限定单 partition + 单 consumer 实例,但一旦扩容或 rebalance 就破序。
- RabbitMQ 更适合:需要死信路由(如支付超时自动关单)、复杂交换机规则(按订单类型分发到不同库存服务)、手动重试控制
- Kafka 更适合:用户行为日志广播给多个下游(风控、推荐、BI),且允许少量重复或短暂延迟
- 混合用法常见:订单主流程走 RabbitMQ,用户埋点日志走 Kafka,两者通过 bridge service 同步关键事件
- 别强行用 Kafka 做事务消息——它的 offset 提交机制和 consumer group rebalance 行为,在短链路强一致场景下比 RabbitMQ 更难控制
真正难的不是写几行 Produce() 或 Consume(),而是理解每种消息模型背后的状态机约束:RabbitMQ 的 channel 生命周期、Kafka 的 offset 提交时机、以及 Go runtime 在高并发下对连接/协程的调度影响。这些细节不厘清,上线后积压、重复、丢消息都是必然结果。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











