什么是消息中间件,或者说什么是中间件?或许还有不少初学者对中间件这一词感到困惑。在参考了维基百科后,个人总结出的理解是:
所有不直接调用本系统而接受的服务都可以叫做中间件。
所以说只要是第三方服务都可以叫做中间件,包括数据库中间件、消息中间件、搜索引擎中间件等等。
而RabbitMq作为一款相对主流的消息中间件,其核心功能当然是对我们的系统发送消息,而我们的系统可以被动的接收消息。
对系统发送消息有什么用?最核心的功能就是使系统变得耦合性降低、拥有异步处理能力以及削峰能力。
耦合性降低:也就是解耦。想象一个场景:在某平台中,存在A、B、C三个系统,假如A系统中一个比较关键的数据发生修改,B、C系统需要马上感知,我们可以在A系统中分别发送请求到B、C系统中通知。那么问题来了,加入有一天,A系统突然挂了,在修改数据后没有及时通知到该怎么办?或者说又新增了一个系统,也需要这个修改的数据,A系统是不是又得重新通知一下新增的系统?
显然,这些系统都强依赖于A系统,这就是强耦合。我们可以通过引入消息中间件来实现解耦:每次我们修改数据后,发送一个消息到消息中间件,而B、C系统只需要监听并且接收这个消息即可,倘若再新增一个系统也需要这个数据,只需要也接收这个消息就行,这样就实现了各个系统之间的解耦了。
异步:异步的标准定义是一个完整操作(通常指业务上的一个完整操作)不会由一个线程线性的执行下去,它会同时调用其他线程并行执行,并且主线程不会等待其他线程执行完成再返回结果,通常会立即返回一个结果。这样可以有效提升系统的并发。
举个例子,一个业务场景,对于用户来说是直接调用的A系统,但由于内部业务比较复杂,A系统需要调用B系统、C系统以及D系统...。如果我们等待整个流程执行完再返回结果,那么操作的相应时间将会每个系统处理的时间总和....(这明显太糟糕了!)。
倘若我们使用消息中间件进行异步处理,A系统不直接调用B、C、D系统,而是发送消息到MQ,B、C、D系统在接收到后再处理,这就实现了异步,可以让三个系统基本同时处理业务。
削峰:想象一个场景,在凌晨时,系统基本没啥人用,每秒请求只在个位数。而一到中午高峰期,大量的请求到达系统中,每秒达到了上千!这其实对系统本身来讲还不至于直接导致崩溃,最多只是效应慢一些,但是这些请求最后通通会直接操作数据库!这种高i并发对Mysql来说几乎是致命了,可以轻易使其崩溃,也进而导致我们的系统无法正常使用。
同样的,我们可以使用MQ来解决上述问题:在高峰期,我们可以不直接将请求直接操作数据库,而是发送到MQ,然后再从MQ中慢慢拉取请求,从而降低数据库的压力,使系统不再崩溃。
最后,这就是MQ最大的核心三个用途,其实根据MQ的一些特性,我们还可以进行更丰富的应用,当然本文也会一一讲出。
学习一个全新的服务,我们肯定得先简单了解它的主要构成吧。
图
如上图所示,首先我们一个RabbitMq服务中可以又不同的虚拟机, 你可以简单理解为它可以多开。而一个虚拟机又存在着交换机概念,并且交换机可以有多个。而通常生产者通过通道发送消息到交换机,交换机再发送到队列里面,然后消费者通过通道消费队列里面的消息。
名词解释
虚拟机:相当于一个独立的rabbitmq服务。
交换机:负责发送消息。(注:在同一个虚拟机中,交换机名不可重复)
生产者:消息发送者。
队列:用来存储消息。(注:在同一个虚拟机中,队列名不可重复)
消费者:接收消息。
通道:用来连接生产者、消费者与rabbitmq服务。
Binding:用来绑定交换机与队列的关系。
ps:一个交换机可以绑定多个队列,每个虚拟机都有多个默认交换机(通常有6个,分别对应6种工作模式)和一个默认队列。
rabbitmq官方提供了6种交换机工作模式。
简单模式(点对点)
这种模式下,交换机可以无需绑定队列(但还是会用默认队列),有点类似于对讲机,生产者与消费者一一对应,每当生产者发送消息,都会直接发送到消费者。
work工作模式(类似于资源竞争)
简单来说,在这种模式下,消费者可以有多个,但是生产者发送的消息只能有一个消费者消费到(看谁能先抢到咯)。
ps:在高并发场景下,这种模式并不能保证一个消息只能有一个消费者消费,可以通过加锁控制
发布订阅模式
相当于广播,交换机会将一个消息同时发布到所有与之相绑定的队列中去,当不同消费者监听不同队列时,会同时收到到消息。
ps:关于消费者与队列的关系,一个消费者只能绑定一个列队,并且一旦绑定,这个队列将不再可以绑定其他消费者。而一个交换机可以绑定多个队列,且一个队列也可以绑定多个交换机
关系图:
路由模式
相当于一个交换机可以选择特定的条件来发送消息到指定队列中。通常用key来配置,只有与之绑定的队列名称为key就会发送消息到队列。
图:
主题模式(可以看作路由模式的一种)
相当于在路由模式进行了扩展,如果说路由模式是数据库的=查询,那么主题模式有点像数据库的like查询,它可以通过key.#的形式来配置发送消息到以key开头的队列名
RCP模式(一般不常用)
这种模式一般不会使用,因为毕竟有专门的rpc框架。但还是得了解其过程。
相当于利用rabbitmq来实现rcp功能。大致流程如下:
1、当客户端启动的时候,作为生产者的客户端将创建一个匿名独享的回调队列。
2、在 RPC 请求中,客户端(生产者)将带有两个属性的消息(一个是设置回调队列的 reply_to 属性,另一个是设置唯一值的 correlation_id 属性)发送到一个RPC_QUEUE队列中。
3、服务器(此时服务器端是消费者)监听这个RPC_QUEUE队列。当这个队列中有请求(消息)出现的时候,服务器将接收并处理完这个请求(消息),并且将处理结果扔进 reply_to 字段指定的队列。
4、客户端(这时候客户端就是消费者了)监听回调队列里的数据。当有消息出现的时候,它会检查 correlation_id 属性。如果此属性的值与请求匹配,则作为一次正常的服务器响应去处理了。