上周跟一个做电商后端的朋友吃夜宵,他撸串的手都在抖。说前晚预热活动,峰值订单比预估高了三成,之前拍胸脯说靠消息队列扛住削峰,结果库存服务的消费端拉垮,队列里堆了二十万条待处理的订单消息,用户付了钱等半小时看不到订单生成,客服后台直接炸了锅。
别把消息队列当万能缓冲垫
很多刚接触分布式架构的人,第一次听到消息队列的削峰能力,眼睛都亮了。觉得只要把所有请求往队列里一扔,下游服务慢也好、崩也好,反正前端能快速返回用户请求,流量洪峰就直接被接住了。
消息队列本质是把同步阻塞的调用,改成了异步解耦的时间差,它从来不会凭空加快你的处理速度。
说实话,刚工作那会我也犯过这个错。当时给一个活动页的接口加了消息队列,用户点提交按钮的请求直接扔队列,前端等500毫秒就返回“活动参与成功”,根本不等后面的库存扣减、资格校验流程跑完。结果活动当天,消费端因为代码逻辑有问题,一半的消息处理失败,用户收到了成功的提示,实际根本没抢到资格,最后赔了小几万的优惠券。

很多团队刚上的时候,只盯着生产端的吞吐量,觉得我能一秒写几万条消息进队列就万事大吉,完全不管消费端的处理能力上限。说白了,你往队列里塞消息的速度,比下游能消化的速度快十倍,那队列就是个暂时存垃圾的仓库,等仓库堆满了,该崩还是崩。之前碰到过更离谱的团队,为了所谓的全链路解耦,连用户修改昵称的请求都要先扔队列,等异步流程跑完再更新用户信息。本来同步调用100毫秒能完成的事,现在用户改个昵称,等两秒才看到更新成功的提示,体验掉得一塌糊涂。
堆在队列里的消息都是真金白银
很多人算消息队列的使用成本时,只会算服务器的采购钱、云厂商的实例费用,根本不算堆在队列里的消息产生的隐形成本。
没有做消息过期策略的队列,堆上几个月的无效消息,光磁盘成本就能吃掉小半个运维预算。
去年帮一个做内容社区的团队排查存储成本过高的问题,翻了半天监控发现,他们的消息队列里存了快三年的用户行为消息。因为当初写代码的开发离职了,接手的人怕删了老消息影响历史数据统计,没人敢动这部分数据。光这部分占的云磁盘空间,每个月就要多花两万多,算下来三年光这堆没用的消息,就花了小七十万。

麻烦在于很多人对消息队列的可靠性有不切实际的幻想。觉得只要用了成熟的开源组件,就不会丢消息、不会重复消费。哪有那么好的事?生产端发消息的时候网络抖了一下,没收到队列的确认回执,消息直接丢了;消费端处理到一半服务被重启,没提交消费进度,重启之后又把同一条消息处理三遍。这些坑,哪个不是上线之后踩得头破血流才记住的?没人会提前告诉你这些。
真正的取舍从来不是技术选型
我见过太多团队,花了几个星期对比不同消息队列组件的参数,比来比去哪个吞吐量高、哪个延迟低、哪个社区活跃,折腾半天选型定了,落地的时候才发现,根本没想清楚自己到底要解决什么问题。
你就是个日活几千的小工具,一天的请求量加起来都撑不满一个普通服务器的性能,上消息队列纯粹是给自己加运维负担。本来两个服务直接RPC调用的链路,排查问题只要翻两个服务的日志,现在加了队列,要多翻三个组件的链路日志,出了故障排查时间直接翻三倍。
说白了,消息队列从来不是架构能力的证明。你用它扛过了真正的流量峰值,处理好了积压的消息,做好了消费的幂等逻辑,才是真的把工具用对了。之前碰到过一个工作两年的开发,在自己的技术博客里吹,说在项目里引入消息队列做全链路解耦,把原来的单体服务拆成了五个异步调用的模块,架构多么先进。结果上线之后,一次用户的操作要触发四个异步消息,任何一个环节出问题,整个流程就走不通,出故障的时间比之前单体服务的时候还长。这就不是用工具。是被工具绑着走了。
上周跟那个做电商后端的朋友吃完夜宵往回走,他说现在终于想通了。之前总觉得要把所有新潮的技术组件都堆上,才叫技术升级。现在才知道,能让用户少等两秒,能让出问题的时候十分钟内定位到根源,比什么花里胡哨的组件都强。他现在给消息队列加了消费速率的硬上限,超过阈值就直接给前端返回“当前下单人数过多,请稍后再试”,再也不硬往队列里塞消息堆着了。