RabbitMQ
1.简介
RabbitMQ是实现了高级消息队列协议的开源消息代理软件。RabbitMQ服务器是用Erlang语言编写的,而集群和故障时构建在开放电信平台框架上的。
2.RabbitMQ处理流程
1.首先有一个生产者(Publisher),他会跟消息中间件建立一条长链接,这条链接会有很多的通信,生产者发送一条消息必须带上一个route-key路由键,然后通过route-key绑定到对应的交互机(Exchange)上,然后交互机会绑定(Binding)对应的队列上(Queue),然后消费者(Consumer)也会跟中间件建立一条通信(Connection),通过各种信道(channal)来消费对应队列(Queue)的信息。
3.使用场景
在项目中,将一些无需即时返回且耗时的操作提取出来,进行了异步处理,而这种异步处理方式大大的节省了服务器的请求响应时间,从而提高了系统的吞吐量。
4.相关名称介绍
1、ConnectionFactory(制造工厂)、Connection(rabbitmq的链接)、Channel(rabbitmq接触接口)
ConnectionFactory、Connection、Channel都是RabbitMQ对外提供的API中最基本的对象。
Connection是RabbitMQ的socke链接,它封装了socket协议相关部分逻辑。
ConnectionFactory为Connection的制造工厂。
Channel是我们与RabbitMQ打交道的最重要的一个接口,我们大部分的业务操作都是在Channel这个接口中完成的,包括定义Queue,定义Exchange、绑定Queue与Exchange、发布消息等。
2.Queue(对象储存器)
Queue是RabbitMQ的内部对象,用于存储消息。
RabbitMQ中的消息都只能存储在Queue中,生产者生产消息并最终投递到Queue中,消费者可以从Queue中获取消息并消费。
多个消费者可以订阅同一个Queue,这时Queue忠的消息会被平均分分摊给多个消费者进行处理,而不是每个消费者都收到所有的消息并处理。
3.Message acknowledgment(消息回执)
在实际应用中,可能会发生消费者收到Queue中的消息,但没有处理完成就宕机的情况,这种情况下就可能会导致消息丢失。为了避免这种情况的放生,我们可以要求消费者在消费完消息后发送一个回执给RabbitMQ,RabbitMQ收到消息回执后将该消息从Queue中移除;如果RabbitMQ没有收到回执并检测到消费者的RabbitMQ连接断开,则RabbitMQ会将消息发送给其他消费者进行处理,这里不存在timeout概念,一个消费者处理消息时间在唱也不会导致该消息被发送给其他消费者,除非他的RabbitMQ链接断开。
这里会产生另一个问题,如果我们的开发人员在处理完业务逻辑后,忘记发送回执给RabbitMQ,这将会导致严重的bug——Queue中堆积的消息会越来越多,消费者从启后会重复执行业务逻辑。
4.Message durability(消息持久化)
如果我们希望及时在RabbitMQ服务重启的情况下,也不消息丢失,我们可以将Queue与Message都设置为可持久化的。这样可以保证绝大部分情况下我们的RabbitMQ消息不会丢失,但依然解决不了小概率时间也要管理起来,那么我们要用到事务。
5.Prefetch count(每次发送量)
前面我们讲到如果多个消费者同时订阅同一个Queue中的 消息,Queue中的消息会被平摊给多个消费者。这时如果每个消息的处理时间不同,就可能会导致某些消费者一直在忙,而另一个消费者很快就处理完手头工作并一直空闲的情况,我们可以通过设置prefetchCount来限制Queue每次发送给每个消费者的消息数,比如我们设置prefetchCount=1,则Queue每次给每一个消费者发送一条消息,消费者处理完这条消息后Queue会再给改消费者发送一条消息。
6.Exchange(交互器)
在上一节我们看到生产者将消息投递到Queue中,实际上这在RabbitMQ中这种事情永远都不会发生。实际上的情况是,生产者将消息发送到Exchange。有Exchange将消息路由到一个或多个Queue中。
RabbitMQ中的Exchange有四种类型,笔筒的类型有着不同的路由策略。
7.routing key(路由规则)
生产者在将消息发送给Exchange的时候,一般会指定一格routing key,来指定这个消息的路由规则,而这个routing key需要与ExchangeType及bindingkey联合使用才能最终生效。
在Exchange Type与bindingkey固定的情况下(载正常使用时一般这些内容都是固定配置好的),我们的生产者就都可以在发送消息给Exchange时,通过指定routingkey来决定消息流向哪里。RabbitMQ为routingkey设定的长度限制为255 bytes。
8.binding(绑定Exchange和Queue的中间件)
RabbitMQ中通过Binding将Exchange与Queue关联起来,这样RabbitMQ就知道如何正确地将消息路由到指定的Queue了。
9.Binding key(绑定key)
在绑定(Binding)Exchange与Queue的同时,一般会指定一个bindingkey,消费者将消息发送给Exchange时,一般会指定一个routing key,当binding key与routing key相匹配时,消息会被路由到对应的Queue中。
10.Exchange Types(交互器类型)
RabbitMQ常用的Exchange Type有fanout、direct、topic、headers这四种。
fanout
fanout类型的Exchange路由规则非常简单,它会把所有发送到该Exchange的消息路由到所有与他绑定的Queue中。
p生产者、X交互器、C消费者、amq是Queue
direct
direct类型的Exchange路由规则也很简单,它会把消息路由到那些binding key与routting key完全匹配的Queue中。
以上图的配置为例,我们以routingkey=“error”发送消息到Exchange。则消息会路由到Queue1和Queue2,如果我们以routingkey=“info“或routingkey=”warning“来发送消息,则消息会路由到Queue2.如果我们以其他routingkey发送消息,则消息不会路由到这两个Queue中。
topic
topic类型的Exchange在匹配规则上进行扩展,它与direct类型的Exchange相似,也是消息路由到bindingkey与routingkey相匹配的Queue中,但这里的匹配规则有些不同,他约定:
routingkey为一个句号:“.”分割的字符串
bindingkey与routingkey也一样也是句号“.”分割字符串
bindingkey中可以存在两个特殊字符串“*”和“#”,用于做模糊匹配,其中“ * ”用于匹配一个单词,“#”用于匹配多个单词。
headers
headers类型的Exchange不依赖于routingkey与bindingkey的匹配规则来路由消息,而是根据发送的消息内容中的headers属性进行匹配。
在绑定Queue与Exchange时指定一组键值对,当消息发送方到Exchange时,RabbitMQ会取到该消息的headers,对比其中的键值对是否完全匹配Queue与Exchange绑定是指定的键值对;如果完全匹配则消息会路由到该Queue,否则不会路由到该Queue。
11.RPC
MQ本身是其余一步的消息处理,但实际的应用场景中,我们很可能需要一些同步处理,需要同步等待服务器将我的消息处理完后在进行下一步处理,这相当于RPC。
RabbitMQ中实现RPC的机制是:
客户端发送请求时,在消息的属性(MessageProperties,在AMQ协议中定义了14种properties,这些属性会随着消息一起发送)中设置两个值replyTo(一个Queue名称,用于告诉服务器处理完成后通知我的消息发送到这个Queue中)和correlationld(此次请求的标识,服务器处理完成后需要将此属性返还,哭护短根据这个id了解那条请求被执行成功或执行失败)。
服务器端收到消息并处理:
服务器端处理完消息后,将会生成一条应答消息到replyTo指定的Queue,同时带上correlationld属性。
客户端之前已订阅replyTo指定的Queue,从中受到服务器端的应答消息后,根据其中的correlationld属性分析那条请求被执行了,根据执行结果进行后续业务处理。
Count来限制Queue每次发送给每个消费者的消息数,比如我们设置prefetchCount=1,则Queue每次给每一个消费者发送一条消息,消费者处理完这条消息后Queue会再给改消费者发送一条消息。
6.Exchange(交互器)
在上一节我们看到生产者将消息投递到Queue中,实际上这在RabbitMQ中这种事情永远都不会发生。实际上的情况是,生产者将消息发送到Exchange。有Exchange将消息路由到一个或多个Queue中。
RabbitMQ中的Exchange有四种类型,笔筒的类型有着不同的路由策略。
7.routing key(路由规则)
生产者在将消息发送给Exchange的时候,一般会指定一格routing key,来指定这个消息的路由规则,而这个routing key需要与ExchangeType及bindingkey联合使用才能最终生效。
在Exchange Type与bindingkey固定的情况下(载正常使用时一般这些内容都是固定配置好的),我们的生产者就都可以在发送消息给Exchange时,通过指定routingkey来决定消息流向哪里。RabbitMQ为routingkey设定的长度限制为255 bytes。
8.binding(绑定Exchange和Queue的中间件)
RabbitMQ中通过Binding将Exchange与Queue关联起来,这样RabbitMQ就知道如何正确地将消息路由到指定的Queue了。
9.Binding key(绑定key)
在绑定(Binding)Exchange与Queue的同时,一般会指定一个bindingkey,消费者将消息发送给Exchange时,一般会指定一个routing key,当binding key与routing key相匹配时,消息会被路由到对应的Queue中。
10.Exchange Types(交互器类型)
RabbitMQ常用的Exchange Type有fanout、direct、topic、headers这四种。
fanout
fanout类型的Exchange路由规则非常简单,它会把所有发送到该Exchange的消息路由到所有与他绑定的Queue中。
p生产者、X交互器、C消费者、amq是Queue
direct
direct类型的Exchange路由规则也很简单,它会把消息路由到那些binding key与routting key完全匹配的Queue中。
以上图的配置为例,我们以routingkey=“error”发送消息到Exchange。则消息会路由到Queue1和Queue2,如果我们以routingkey=“info“或routingkey=”warning“来发送消息,则消息会路由到Queue2.如果我们以其他routingkey发送消息,则消息不会路由到这两个Queue中。
topic
topic类型的Exchange在匹配规则上进行扩展,它与direct类型的Exchange相似,也是消息路由到bindingkey与routingkey相匹配的Queue中,但这里的匹配规则有些不同,他约定:
routingkey为一个句号:“.”分割的字符串
bindingkey与routingkey也一样也是句号“.”分割字符串
bindingkey中可以存在两个特殊字符串“*”和“#”,用于做模糊匹配,其中“ * ”用于匹配一个单词,“#”用于匹配多个单词。
headers
headers类型的Exchange不依赖于routingkey与bindingkey的匹配规则来路由消息,而是根据发送的消息内容中的headers属性进行匹配。
在绑定Queue与Exchange时指定一组键值对,当消息发送方到Exchange时,RabbitMQ会取到该消息的headers,对比其中的键值对是否完全匹配Queue与Exchange绑定是指定的键值对;如果完全匹配则消息会路由到该Queue,否则不会路由到该Queue。
11.RPC
MQ本身是其余一步的消息处理,但实际的应用场景中,我们很可能需要一些同步处理,需要同步等待服务器将我的消息处理完后在进行下一步处理,这相当于RPC。
RabbitMQ中实现RPC的机制是:
客户端发送请求时,在消息的属性(MessageProperties,在AMQ协议中定义了14种properties,这些属性会随着消息一起发送)中设置两个值replyTo(一个Queue名称,用于告诉服务器处理完成后通知我的消息发送到这个Queue中)和correlationld(此次请求的标识,服务器处理完成后需要将此属性返还,哭护短根据这个id了解那条请求被执行成功或执行失败)。
服务器端收到消息并处理:
服务器端处理完消息后,将会生成一条应答消息到replyTo指定的Queue,同时带上correlationld属性。
客户端之前已订阅replyTo指定的Queue,从中受到服务器端的应答消息后,根据其中的correlationld属性分析那条请求被执行了,根据执行结果进行后续业务处理。