![MQ 聊聊消息队列那些事](http://img.zhejianglong.com/231019/23311UV6-0.jpg)
文章插图
每年的双十一期间,各大电商平台流量暴增 , 同时,电商平台系统的负载压力也会很大 。譬如订单支付的场景,每个订单支付成功后,服务器可能要完成扣减积分、扣减优惠券、扣减商品库存、发短信等一系列操作 。单个用户请求,服务器处理起来并没有什么问题,但是,瞬时并发的多个请求到了服务器,数据库压力上来了,导致请求响应慢,甚至宕机 。
为了解决这个问题 , 我们可能会想到,让数据库处理完一个请求后再处理下一个请求不就好了么 。就这样,消息队列出来了 。消息队列,又称为MQ(Message Queue),它实现了让多个请求以消息的形式排好队,让消息处理程序一个一个的处理 , 有效防止了高并发给服务器带来的压力 。
消息队列应用场景MQ应用的典型场景有异步、削峰、解耦三种 。
异步譬如说一个系统A,它有一个操作处理完自己的逻辑以后需要调用其他系统的接口 , 如下图:
![MQ 聊聊消息队列那些事](http://img.zhejianglong.com/231019/23311V511-1.png)
文章插图
这时候,代码是这样:
public class SystemA { @Resource SystemBapi systemBapi; @Resource SystemCapi systemCapi; @Resource SystemDapi systemDapi; public void doSomething() {//产生一个idlong id = doSomethingAction();//调用其他系统接口systemBapi.doSomething(id);systemCapi.doSomething(id);systemDapi.doSomething(id); }}
上面的代码,系统A产生id的逻辑需要50ms,调用系统B的接口需要300ms,调用系统C的接口需要300ms , 调用系统D的接口需要300ms 。一个这样的操作就需要50+300+300+300=950ms 。如果后面还要对接其他系统,这个操作的时间会更长 。如果调用其他系统接口实时性要求不高,那么,为了提高用户体验和吞吐量,调用其他系统接口的操作就可以交给MQ实现异步操作 。如下图:
![MQ 聊聊消息队列那些事](http://img.zhejianglong.com/231019/23311VQ9-2.png)
文章插图
系统A执行完了以后,将id给到消息队列中,然后就直接返回了 。
削峰譬如有3台服务器组成集群 , 每台服务器的处理能力是1000个QPS/S,合起来就是3000个QPS/S 。遇上了流量高峰,达到了5000个QPS/S , 请求数量已经超过所有服务器总的处理能力,这时候就可以考虑利用MQ来控制并发数,以免服务器崩溃 。
具体做法是所有请求先进入到MQ,然后每个服务器根据自己的能够处理的请求数去消费消息,也就是无论每秒多个QPS,系统只处理能力范围内的请求数,剩下的请求等有资源再去处理 , 这就是“削峰填谷”,如下图:
![MQ 聊聊消息队列那些事](http://img.zhejianglong.com/231019/23311W4F-3.png)
文章插图
解耦解耦就是降低了消息生产者与消费者的耦合度 。耦合度高,程序维护起来就会很麻烦 。譬如,系统A产生了一个id后,需要把id交给系统B、系统C、系统D去处理 。如果由系统A直接去调用其他系统接口 , 系统A的程序代码需要写上调用系统B、系统C、系统D接口的代码 。如果某一天系统C说不需要处理系统A的id了,让系统A不要调用系统C的接口,那系统A要改代码 。又某一天系统E说我要处理系统A的id,让系统A调用系统E的接口 , 系统A又得改代码 。系统A的程序员这样子搞烦不烦?
系统A程序员有一天开窍了,把程序里所有调用外部系统的代码都屏蔽,弄了个MQ中间件,让系统A产生id以后就给到MQ 。然后发个公告告诉所有其他系统的程序员,你们谁想要我这边产生的id你们自己去MQ拿 , 别来烦我 。
![MQ 聊聊消息队列那些事](http://img.zhejianglong.com/231019/23311S061-4.jpg)
文章插图
这样一来,系统A跟其他系统就解耦了,代码也不用改来改去 。
消息队列要注意的问题问题一:可用性MQ作为整个整个分布式架构的重要部件,如果MQ服务不可用,那整个系统都挂了 。因此,MQ必须要支持集群 。当下主流的MQ中间件都能够不同程度的支持集群 , 实现了MQ服务的高可用 。
问题二:消息丢失消息丢失有可能发生在生产者丢失消息、MQ本身丢失消息、消费者丢失消息3个方面 。
- 生产者丢失消息生产者丢失消息一般是在发送消息的时候出现异常(譬如网络异常),导致MQ无法接收到消息 。这个问题可以采用本地消息表+回调通知+定时任务的方式解决 。?就以系统A发送消息,系统B消费消息为例,具体解决方案如下:1、系统A执行本地事务业务逻辑,并且往本地消息表插入一条数据(代表准备要发送的消息),消息状态为“未发送” 。本地事务成功,提交保存本地数据 , 失败则回滚 。2、本地事务成功后,发送消息给MQ 。3、MQ接收到消息后,回调通知系统A , 系统A把本地消息表对应的消息记录状态变为“已发送” 。4、定时任务轮询本地消息表,超过一定时间状态为“未发送”的消息重新发送给MQ 。5、定时任务处理超过一定次数一直发送不成功的消息告警,人工介入 。?
推荐阅读
- iqoo7有pro吗_iqoo7pro最新消息
- 三星TabS8最新消息_三星TabS8刘海屏幕曝光
- 苹果13官方消息_苹果13升级了什么
- 三星zflip3最新消息_三星zflip3最新消息曝光
- Go实现栈与队列基本操作
- rabbitmq docker安装消息队列及数据库(mongo、mysql)
- realme笔记本最新消息_realme笔记本即将发布
- JS数据结构与算法-队列结构
- Dubbo-聊聊通信模块设计
- 荣耀Magic3最新消息_荣耀Magic3配置消息