为什么使用消息队列?
孙玉超
2021-03-23 14:21:20
0 评论
1164 浏览
0 收藏
0 赞
为什么使用消息队列
传统单体项目访问量小不能反映出问题,当业务量增长,访问量增大,系统拆分为多个子系统后。一个客户端请求涉及到的子系统链路很长,以我们公司 APP 下单为例,要经过库存、优惠券、积分等系统。如下图:
如果传统的方式,需要先创建订单、库存系统、优惠券系统、积分系统后续业务扩展可能的其他系统。假设每一个系统的调用是 200 ms,那么上述一个下单过程就要耗费 800 ms,其实真实的下单过程还有其他操作,总共下来要 1s 钟。这对于秒杀订单来说无疑是致命的。到时候用户手机上就是一个个的白屏或者服务器直接崩溃。然后绩效奖金就没了......
再看下使用消息队列之后的流程:
创建订单之后先发布本地事件(我们技术老大要我们使用 SpringCloud Bus 的模型,先创建本地事件,然后在本地事件里面发消息。关于事件:Spring 事件),然后发消息给 MQ 说我订单下单成功了,其它系统自己来订阅我的消息,自己处理自己的业务就好了。由于发送消息到 MQ 的时间几乎可以忽略不计,这样一来,整个下单的业务,就只有创建订单要耗费 200 ms,用户体验很好,是无感知的。所以就反应了消息队列的第一大优势:异步。(线程不是也能异步吗?)
由于业务不断发展,以后肯定还有其他子系统或者功能接入进来,如果是传统不使用消息队列的方式,我们每新增一个功能,就要在订单系统里面去新增或者修改代码。而使用消息队列之后,反正订单创建成功的消息发出去了,要新增什么功能,只需要自己去订阅这个消息即可,无需改动任何订单的代码。由此反应出消息队列的第二大优势:解耦。(使用线程解决了异步,但是不能解耦)
一般来说秒杀活动的特性是短时间内大量请求过来,系统请求量瞬间激增。如果不用消息队列,大量请求并发访问系统、数据库。系统或者数据库可能就直接被打宕机。使用消息队列之后,可以看成下图的模型
大量请求不直接对应下游子系统,而是发给 MQ,由于 MQ 的特性就是承载高并发的消息,所以 MQ 肯定不会被请求打挂。然后下游子系统分批或逐个从 MQ 里面消费,这样就变相的把激增的请求峰值给压低(削峰)。等高峰期过去,依然保持这个速度消费(填谷)。这就是 MQ 的第三大优势,削峰填谷。
消息队列会带来哪些问题
当我们引入消息队列之后,如果创建订单成功,扣减库存失败怎么办?比较库存系统的访问时异步的。如果由于网络延时,消费者消费完消费没有发送确认到 MQ ,MQ 再次发消息给消费者,造成重复消费怎么办?这就引入了第一个问题,使用消息队列之后,要考虑很多问题,系统复杂性提高。
还以上述下订单为例,假如扣减库存成功了,优惠券系统那边失败了,或者库存和优惠券系统都执行成功了,其他系统失败了。这种情况怎么处理?数据不一致了,这就引入了第二个问题。使用消息队列之后,如何保证数据一致性问题?