目录
一、什么是消息队列?
二、消息队列的作用
1.解耦
2.削峰
3.异步
三、消息队列的使用场景
1.传统设计
2.加入消息队列后的优化
四、常见的消息队列
一、什么是消息队列?
从名称上,我们就可以得到两个关键信息,即“消息”和“队列”,也就是存放消息的队列。队列这种数据结构我们非常熟悉,是一种先进先出的数据结构。
回想一下,我们熟悉的数据库,常见的有MySQL、Redis等数据库,MySQL是一种关系型数据库,更多的是存储关系,有特定结构的数据,并且表和表之间通常会有很强的关联,要求强一致性,例如学校有哪些学院,有哪些专业,每个专业又都属于那个学院这种关系。
而Redis是一种存储在内存中的非关系型数据库,他对数据并没有那么强的一致性要求,存储的数据也是非特定结构的,即非关系型数据库中的数据之间可以是不同结构的,这种数据库的水平拓展能力比较强。由于又是存储在内存中,所以,其读写速度很快。
如果我们对数据通常是随机读取的话,那么用内存存储会比用磁盘存储会快很多。但是,如果我们是顺序存储的话,那么两者的速度差别就不是很大了。而消息队列就是基于顺序增量存储的特点来存储数据的。
消息队列:一般我们会简称它为MQ(Message Queue)。他是一种基于顺序增量存储的特点的数据存储区。对于消息队列,可以举一个场景,“接收快递”是我们生活中再正常不过的事情了。但是,通常情况下,我们并不是直接从快递员手中取走快递,而是让快递员暂时将快递存储在“菜鸟驿站”的一些地方,然后我们就可以在空闲时间去驿站取走自己的快递。而驿站便是起到一个消息队列的作用,快递员(生成者)将快递(数据或者消息)存放在驿站(消息队列)中,我们(消费者)根据自身情况去驿站(消息队列)取走快递(数据或者消息)。这样,我们就不用适时地去响应快递员取走快递。对于生产者来说,我们是顺序增量存储在驿站中的,消费者是从驿站中取走消息的。
二、消息队列的作用
1.解耦
首先,我们要搞清楚“解耦”是什么意思?
解耦是指通过降低代码之间的依赖性,减少模块或组件之间的耦合程度。在软件开发中,解耦是一种良好的设计原则,它可以提高代码的可维护性、可测试性和可扩展性。
当两个模块或组件之间高度耦合时,它们的改动往往会相互影响,一个模块的修改可能会导致其他模块的变动,这增加了系统的复杂性和风险。
还是上述的快递例子,对于快递员来说,他只要将快递放置在驿站即可,而不需要将快递亲手交给用户。快递员和用户之间不再存在直接联系,而是通过驿站进行较弱的联系,快递员的相关操作发生改变的时候,并不会直接影响到用户。
通过解耦,可以使系统更加灵活、可扩展和可维护。当一个模块需要修改或替换时,对其他模块的影响将最小化,使系统更具弹性和可扩展性。
2.削峰
削峰的意思,就是削减峰值,来降低压力。
当快递员(生成者)对于一个用户(消费者)来说,该用户(消费者)有大量的快递(消息),如果没有消息队列,那么,当快递员发送大量数据成功后,用户需要适时去接受数据,此时对于用户来说,压力是比较大,而且需要适时去响应快递员,否则快递员会一直的等待,进而严重影响效率。
引入驿站(消息队列)后,如果快递员有大量快递,只需要将快递存在驿站中即可,然后快递员就可以进行下一个操作,用户也不需要适时,或者突然接受大量快递,而是等自身空闲时,从驿站取出即可,减少了用户压力。
3.异步
异步也就是不一定要按照一定的顺序执行,而是可以一起执行。
与异步相对的就是同步,同步就是要求必须按照一定的顺序执行。
应用于“发取快递”的场景,也就是用户和快递员前往驿站并不是有一定顺序的,也就是,并不是快递员前往驿站以后用户才可以去,或者相反。用户和快递员之间互不影响。
三、消息队列的使用场景
1.传统设计
如果说业务体量小,并发不大,那么,我们可以采用服务模块相互联系,按顺序的同步执行,进而完成请求。
对于上面的设计,属于典型的串行化调用,这种设计模式有一个很大的优势,就是代码简单,出现问题很容易定位到问题。但是也有很多劣势:
高可用:这些服务假如有一个服务挂掉(宕机或者网络波动),就意味着我这个请求失败了,这样用户体验会极差,用户会频繁看到支付失败。
高并发:因为这些操作都是由一个线程(主线程)去执行这些操作,所以当我们的QPS如果很高的话,很容易造成超时。
QPS:系统每秒钟收到的请求。
高性能:因为上面这种设计模式是串行的,假设我的每次网络传输耗时200ms,业务处理需要20ms,完成上面那些操作需要耗时2s,这样用户体验也会很差(想象一下每次下单都需要等2s),如果用户下单后的操作越来越多,耗时只会越来越高。
所以在一个大型的互联网项目中,以上设计是完全不可取的(非核心模块除外)。
2.加入消息队列后的优化
通过上述的“快递”的例子,我们就可以很容易理解下面这个图的流程。只是在联系的时候加上了一个属性topic,具有相同topic的请求才会被对应的微服务调用。
微服务是什么?
可以参考本人的这篇博客:微服务基础
对于这种设计可以继续用高可用、 高并发、高性能三个方面来分析:
高可用:当我系统里的一个模块宕机了,不会影响到我其他服务(可以通过数据补偿或者分布式事务来保证数据最终一致性),并且分布式架构会有其他相同的业务模块来进行替补,进而完成任务。
高并发:高性能:用户下单,将下单所需要的数据都放到消息队列里,就直接返回了,所有耗时相当于就是网络传输所耗时。用户只要下单就可以得到响应,即只交给了消息队列,然后消息队列和微服务之间来合理完成服务。
高性能:由于消息队列不处理任何业务上的逻辑,所有他支持的并发是百万级别的。假如有100万个用户下单,100万的数据放到消息队列里,连接消息队列的服务慢慢消费即可,也不至于造成瞬间有百万请求进来,将我的服务压垮。
但是,这种设计也是有缺点的,也就是对中心消息队列的依赖高,如果消息队列崩溃,整个系统便不能运行。并且增加了系统复杂性。如果说你的业务量不大,并发也不高,就没必要使用消息队列。并且,时效性也不强,因为是消息队列慢慢消化执行的。
为了保证可用性,我们可以采用消息队列集群,前端流量限流等。