🌈个人主页:一条泥憨鱼(欢迎各位大佬莅临)

❄️《数据结构》 ❄️《AI与Agent那些事》
❄️《从0开始学计算机网络》 ❄️《后端开发》

这篇整理 RabbitMQ 入门部分的三块内容:同步调用在微服务链路里暴露的问题、异步调用怎么用消息代理改写链路、四款主流 MQ 该怎么选。三块都落在余额支付这一条链路上,串起来回答同一个问题:一条调用链什么时候值得引入消息队列,引入之后又该选哪个。
一、同步调用:余额支付这条链路长什么样
拿黑马商城的余额支付来说。用户在前端点支付,请求打到支付服务,支付服务往下调一串服务:用户服务扣减余额,自己更新支付状态,交易服务更新订单状态,通知服务发短信,积分服务加积分。图上的编号 1 到 5 就是执行顺序。

同步的意思是每一步都要等对方返回,五步全部跑完,支付服务才把响应还给用户。每个下游处理一次大约 50ms,单看哪个都不慢,可它们被串成了一根绳:250ms 花在五个下游上,再加支付服务自己的开销,对外就是图上标的 300ms。用户等到的这 300ms 里,真正属于支付服务自己的计算只占一小截。
业务上再加一件事,比如支付成功后给用户推一张优惠券,这根绳子就更长。
二、同步调用的三个问题
拓展性差。 每加一个下游动作,改的都是支付服务,测试和发布也要跟着走一遍。支付是所有业务都要依赖的服务,改动风险都压在这里。
性能下降。 耗时是累加的。链路里每多一个环节,用户就多等一次,而支付服务自己的处理时间并没有变长。
级联失败。下游任意一个不可用,失败会顺着调用链往回传。用户服务超时,支付就超时;积分服务挂了,支付也跟着失败。一个下游的小故障,被放大成主链路的故障。
三、异步调用:把关联度低的服务挪到 Broker 后面
异步调用基于消息通知,链路里有三个角色。消息发送者负责投递消息,也就是原来的调用方;消息代理负责管理、暂存、转发消息,拿微信服务器打比方很贴切,你发消息给服务器就返回,不用等对方在线;消息接收者接收并处理消息,就是原来的服务提供方。

落到支付链路上,关键在哪些服务该挪到代理后面。图上的划分是:扣减余额和更新支付状态这两件和支付本身关联度高,留在同步链路里;交易、通知、积分这三件关联度低,改成向消息代理投一条订单 xx 支付了的通知,由代理转发给各自的订阅方。

耗时随之变化。支付服务对外的响应从 300ms 降到 100ms,剩下的正好是那两步各 50ms。它只要把款扣完、把消息投出去就能返回,不用站在原地等下游算完积分、发完短信。
图下方的 QPS 曲线是另一个变化。左边那条随流量起伏,尖峰扎得很高;右边那条接近平直。突发的消息先被代理攒在队列里,下游按自己的节奏消费,峰值摊到了后面的时间上。
同步和异步的差别,可以借一个日常比方记住。同步通讯像打电话,双方得同时在线,说话要等对方回应;异步通讯像发微信,消息扔出去就能干别的,对方什么时候看到不影响你手上的事。

四、两种方式各自的取舍
同步调用换来的是时效性,等结果返回,成功还是失败当场就知道。代价就是前面那三条。
异步调用把耦合度降了下来,链路可以随便加下游,上游不用改;性能上不用等;下游服务挂了也不影响上游业务的返回,故障被隔离开;再加一个削峰填谷。代价同样是三条:拿不到立即的调用结果,时效性差;下游有没有处理成功,调用方不知道;还有一条最需要提前想清楚。
业务安全依赖于 Broker 的可靠性
Broker 一旦丢消息,故障是静默的。支付服务已经告诉用户支付成功,积分没加上,短信也没发出去,日志里没有任何报错。这就决定了引入 MQ 之后必须配套解决可靠性问题:消息丢了怎么办,重复了怎么办。后面要花大力气的地方都在这里。
五、MQ 技术选型
MQ 是 MessageQueue 的缩写,中文是消息队列,字面意思就是存放消息的队列。放到异步调用的结构里,它对应的正是前面那个消息代理,也就是 Broker。

把四款摆在一起,差距集中在延迟、吞吐量、可靠性这三项上。
RabbitMQ 用 Erlang 编写,支持的协议最多,可用性和消息可靠性都标为高,消息延迟是微秒级。短板在单机吞吐量,标的是一般。Kafka 正好相反,单机吞吐量非常高,延迟在毫秒以内,可靠性和可用性一般,协议是自定义的。RocketMQ 落在中间,吞吐量高、可靠性高、延迟毫秒级。ActiveMQ 的可用性、吞吐量、消息可靠性三项都偏一般或差,是这四款里最弱的。
选型的落点是这条链路的主要矛盾在哪一项。订单、支付这类业务对延迟敏感,又不能丢消息,同时对单机吞吐量没有极端要求,RabbitMQ 的微秒级延迟和高可靠性更合适;日志采集、埋点上报这种量级大、偶尔丢一两条可以接受的场景,Kafka 的吞吐优势更值钱。
六、总结
这篇要解决的是判断一条调用链该不该引入消息队列。可以看三个信号:下游服务和变更在变多、链路耗时被下游累加、下游故障会传导回主链路。出现其中任意一个,异步调用和 MQ 就有讨论的价值。
引入之前还有一件事要提前想清楚。消息交给 Broker 之后,调用方不再掌握下游的执行结果,可靠性责任跟着转移。这一点接受了再引入,后面才不会在消息到底丢没丢上反复踩坑。
转载自 CSDN-专业IT技术社区
原文链接:https://blog.csdn.net/2503_94545876/article/details/167494761




