先讲个真实场景。很多团队把 RabbitMQ 引入 Spring Boot 项目,是因为某个活动流量把数据库打满,或是链路太长、一个下游服务抖动就把整条链路拖垮。我接手过一个订单系统,线上半夜报警,慢 SQL 把连接池耗尽,加了两台机器也只是把问题往后延了几分钟。后来排查发现,下单成功后要同步调用积分、短信、库存三个服务,其中一个服务响应慢,其他调用全部排队,数据库连接被这些等锁的线程占着不放。
当时大家的第一反应是“上 RabbitMQ”。结果又踩了一圈坑:有人把队列声明写在 @RabbitListener 注解里,有人消息发出去没有确认回调,有人消费端用了默认自动确认,失败也不重试,更没想过死信队列兜底。这篇文章我想顺着一条完整链路讲:什么场景值得上 RabbitMQ、环境怎么装、Spring Boot 集成时要避哪些坑、ACK 重试和死信怎么配、最后聊一聊和其他消息中间件怎么选。内容不算入门科普,更像是我自己在生产环境折腾过之后整理的一份工程笔记。
1. 别急着写代码:先把 RabbitMQ 该解决什么问题想清楚
很多初学者把 RabbitMQ 当成“高端项目的装饰品”,项目里没有消息队列也要硬塞一个。结果消息发了没人消费、消费失败没人管、队列里消息越堆越多,最后反而比不用 MQ 还累。所以第一件事不是写配置,而是判断你的系统是不是真的需要它。
1.1 三种真正适合用 MQ 的业务形态
第一种是异步解耦。下单完成后要通知积分服务、短信服务、会员服务,如果这些调用全放在下单接口里同步做,接口响应时间就是所有下游响应时间之和。更麻烦的是,某个下游服务一旦不可用,你还要决定是让整个下单失败还是吞掉异常。用 MQ 之后逻辑变成:订单主流程只把“订单已创建”这个事实发布到 RabbitMQ,谁关心这个消息谁自己去订阅。积分服务挂了不影响下单,它恢复后继续消费积压消息就行。
第二种是削峰填谷。秒杀、抢券、预约这类场景,瞬时流量可能达到平时的几十倍,但数据库连接池、外部接口的处理能力是固定的。暴增的流量如果直接打到数据库,结果就是连接池被打满、慢 SQL 堆积、服务雪崩。加了 MQ 之后,前端请求先转化成一条消息快速返回“已收到”,后端消费者按照自己能承受的速率去处理,把瞬时高峰拉平。注意,所谓“快速返回”不等于业务已经完成,前端通常通过轮询订单状态来感知最终结果。
第三种是延迟任务与最终一致性。订单 30 分钟未支付要自动关闭、收货后 15 天自动确认打款,这类需求如果靠定时任务每分钟扫一次数据库,数据量大了以后对库的压力非常明显。RabbitMQ 里的死信队列、延迟消息插件就是为这种场景设计的,让消息在队列里躺到指定时间再被消费,比分布式定时任务扫库优雅得多。
1.2 判断该不该上 MQ:一句话原则和两个反例
如果你说不清楚自己要用 MQ 解决什么问题,那大概率不应该上。一句话版本是:当“生产者产生消息的速度”和“多个消费者处理消息的能力”不匹配,或者“一个事件需要被多个独立系统感知”时,MQ 才是合适的中间层。
反例也要说清楚。第一个反例是日均请求量只有几千、数据库 CPU 常年不超过 10% 的业务