消息队列用久了才懂的那些账

上周帮一个创业团队排障,线上告警炸了半小时。
用户支付成功,订单页跳不出来。
查了一圈,是他们半年前图方便接的消息队列,攒了300万条没消费。
其实这不是个例。太多团队刚接触分布式的时候,第一反应就是上个消息队列,好像不上就不算做过分布式架构。
这事没那么玄。

最先要算的不是性能账

很多人接消息队列的初衷,是听别人说能扛高并发,能削峰,能解耦。
上来就照着网上的教程配集群,开分区,加副本,根本没先问自己一句:你是不是真的需要异步?
异步的核心前提是,你能接受这段时间内的状态不一致。
用户付完款,晚两秒收到支付成功的通知,没问题。
用户提交订单,晚一秒扣完库存,要是刚好碰到两个人抢最后一件商品,你敢赌吗?
我见过太多团队,把所有同步调用全换成了消息队列,连核心的库存扣减都走异步,结果大促当天超卖了几千单,赔的钱够养三年的MQ集群。
更有意思的是,很多人连自己每天的消息量都算不清。
日均10万条消息的业务,峰值每秒也就几十条,非要配5个分区,3个副本,集群资源利用率连5%都不到,纯纯浪费钱。
Kafka消息队列分区分配实际示意图
Kafka消息队列分区分配实际示意图

你要是真的算过账,就会发现大部分中小团队的消息量,根本撑不起分布式MQ的成本。
哪怕是用托管的云服务,每个月的费用也够多雇一个初级后端了。
哦对,还有人说消息队列能解耦。
说白了,就是你不用等下游服务响应了,发完消息就能走。
但是耦合从来不是消失了,只是从同步的调用依赖,变成了异步的消息依赖。
下游服务要是崩了,消息堆在队列里,最终还是会炸到你自己头上。

堆积不是最可怕的事

第一次碰到消息队列堆积的人,第一反应都是慌。
赶紧加消费者。
赶紧扩容集群。
往往越急越容易出问题。
我之前碰到过一个团队,消费端的逻辑没做幂等,碰到堆积之后疯狂加消费者,结果重复消费了几十万条消息,给每个用户发了十几次优惠券,光资损就十几万。
说真的,90%的堆积事故,根本不是队列本身扛不住。
要么是生产端突然刷量,要么是消费端的依赖接口超时,要么是消费逻辑本身写的就有问题。
之前有个做电商的朋友,消费端处理一条消息要调三个第三方接口,其中一个短信接口的超时时间设成了5秒,平时还好,一到高峰期接口响应变慢,所有消费线程全堵在等待上,消息堆得飞快。
他们一开始以为是队列的问题,换了个MQ,结果堆得更快。
最后改了超时时间,把非核心的调用挪到异步任务里,十分钟就把堆积清完了。
消息队列堆积故障排查步骤流程图
消息队列堆积故障排查步骤流程图

很多人不知道,消息队列的稳定性,从来不是靠集群本身扛出来的。
消费端的超时、重试、死信队列配置,才是消息队列能不能用稳的核心。
你要是没配死信队列,消费失败的消息就会无限重试,把本来就堵的消费端压得更死。
你要是没做幂等,重试一次就可能出一次资损。
这些事,网上的教程不会跟你说这么细,总有人告诉你”用了MQ就能高并发”,没人告诉你背后要填多少坑。

没人告诉你的隐形成本

很多人算成本的时候,只算买集群的钱,算云服务的钱。
不算排障的时间成本,不算一致性改造的工作量,不算额外的运维成本。
之前是同步调用,出了问题直接看接口日志,顺着链路查就行。
现在走了消息队列,你得搞清楚:消息发出去了吗?到队列了吗?被哪个消费者拉走了?处理成功了吗?
这些都得搭一套链路追踪的系统,不然出了问题就是一笔糊涂账。
还有一致性的问题。
你数据库提交成功了,消息没发出去,怎么办?
消息发出去了,数据库提交失败了,怎么办?
要么搞本地消息表,要么搞事务消息,要么搞定时任务对账,每一样都是额外的工作量。
我见过太多团队,业务还没到日活十万,就先上了一套Kafka,结果光维护这个集群就占了半个后端的精力。
最后业务没做起来,集群先成了累赘。
说白了,消息队列不是给你减复杂度的,是给你换一种复杂度。
之前是同步链路长,但是好排查,好调试。
现在是链路解耦了,但是你得花更多精力去保证消息不丢、不重、不堵。
要是你的业务每秒处理量还不到100条,真的没必要折腾分布式MQ。
用个本地内存队列,甚至数据库的任务表,都能搞定大部分场景。
别上来就堆技术栈。
适合自己的,才是对的。
免责声明:市场有风险,选择需谨慎!此文仅供参考,不作买卖依据。如有侵权请联系删除。
文章名称:消息队列用久了才懂的那些账
文章链接:https://m.itcdj.com/it/166.html