RabbitMQ基础

上一博客把RabbitMQ的安装配置介绍了下,今天主要是介绍下RabbitMQ的一些基础名词。

一、什么是RabbitMQ?用它能做什么?

1.简介

AMQP,即Advanced Message Queuing Protocol,高级消息队列协议,是应用层协议的一个开放标准,为面向消息的中间件设计。消息中间件主要用于组件之间的解耦,消息的发送者无需知道消息使用者的存在,反之亦然。AMQP的主要特征是面向消息、队列、路由(包括点对点和发布/订阅)、可靠性、安全。RabbitMQ是一个开源的AMQP实现,服务器端用Erlang语言编写,支持多种客户端,如:Python、Ruby、.NET、Java、JMS、C、PHP、ActionScript、XMPP、STOMP等,支持AJAX。

2.作用

消息中间件之间解耦,以网上商城为例,用户下单时可能会有大并发量,服务器压力也会增大,特别是类似双11的时候,那如何解决呢?可以使用消息队列将订单信息放在队列中,下单后付款需要把订单信息传给仓库并会发送短信或者邮箱,仓库这边又联系着进销存系统,这样如果把网上商城系统和进销存系统都放在一起,那就会更加庞大不利于系统解耦,体现不了高内聚低耦合的思想。同时会把订单信息通过邮箱或者短信发送给用户,这样会调用发送邮件或短信的系统,发送邮件或短信的速度速度有限,高峰时可能会将服务器爆了,这种情况可以使用消息队列来起到错峰的作用。

二、名词介绍

1.ConnectionFactory、Connection、Channel

ConnectionFactory从名词可以看出Connection工厂,它主要用来创建Connection。Connection客户端与服务器打交道需要先创建与服务器的链接,然后通过管道Channel来进行操作。

2.Queue队列

RabbitMQ中的消息都只能存储在Queue中,相同属性的queue可以重复定义,有以下几个属性。
– 持久性:如果启用,队列将会在server重启前都有效。
– 自动删除:如果启用,那么队列将会在所有的消费者停止使用之后自动删除掉自身。
– 惰性:如果没有声明队列,那么在执行到使用的时候会导致异常,并不会主动声明。
– 排他性:如果启用,队列只能被声明它的消费者使用

3.生产者消费者模式

生产者消费者模式是通过一个容器来解决生产者和消费者的强耦合问题,生产者和消费者彼此之间不直接通讯,而通过阻塞队列来进行通讯,所以生产者生产完数据之后不用等待消费者处理,直接扔给阻塞队列,消费者不找生产者要数据,而是直接从阻塞队列里取,阻塞队列就相当于一个缓冲区,平衡了生产者和消费者的处理能力。一个生产者可以有多个消费者,例如上面的网上商城的例子中,生产者是网上商城系统的订单,消费者是仓库系统、邮件、短信服务系统以及日志系统等。

4.Message acknowledgment消息回执

比如在下单过程中用户下单后需要给仓库进销存系统、邮件服务系统、日志系统等,而每个系统又会创建多个消费者,此时消息队列并不会就把消息删除,而是需要发送一个回执,以防止消费者宕机等原因导致消息丢失。这里有一个需要注意的地方就是这里没有timeout超时的概念,一个消费者处理消息时间再长也不会导致该消息被发送给其他消费者(多个消费者),除非它的RabbitMQ连接断开,在消费者消费之后要记得发送回执,不然会一直堆积在队列中,消费者重启后会重复消费这些消息并重复执行业务逻辑。

5.持久化

RabbitMQ服务器也有重启或宕机的可能性,为了不让消息丢失,我们可以将Queue与Message都设置为可持久化的(durable),这样可以保证绝大部分情况下我们的RabbitMQ消息不会丢失。

6.Prefetch count

使用Prefetch count可以实现负载均衡,多个消费者消费一个消息队列时,可能每个消费者处理信息的时间快慢不同,不能让有的累死有的饿死,可以通过设置Prefetch count=1,Queue每次给每个消费者发送一条消息;消费者处理完这条消息后Queue会再给该消费者发送一条消息。

7.Exchange交换机

从名词理解,类似网络的交换机,还是以订单为例,生产者网上商城生产的消息需要给仓库进销存系统,邮件系统,日志系统,而每个系统又可以创建多个消费者来处理,每个系统不可能都操作一个消息队列,那样的话任何一个消费者系统发送回执就会导致消息丢失,导致其他系统遗漏信息处理,实际上一般是会把消息发给交换机,由Exchange将消息路由到一个或多个Queue中(或者丢弃)。这样进销存、邮件、日志系统都分别会有一个消息队列,这样就不会导致消息丢失了。

8.Binding、Binding key、routing key

Exchange将消息路由到一个或多个Queue,那如何与消息队列发生关系呢?那就需要先将消息队列与交换机绑定到一起,一般会指定一个binding key。当消息队列与交换机绑定之后,消费者就可以生产消息传递给消息队列,那各个消息如何进入到不同的队列呢?生产者在将消息发送给Exchange的时候,一般会指定一个routing key,来指定这个消息的路由规则,而这个routing key需要与Exchange Type及binding key联合使用才能最终生效。在Exchange Type与binding key固定的情况下(在正常使用时一般这些内容都是固定配置好的),我们的生产者就可以在发送消息给Exchange时,通过指定routing key来决定消息流向哪里。当binding key与routing key相匹配时,消息将会被路由到对应的Queue中。RabbitMQ为routing key设定的长度限制为255 bytes。binding key 并不是在所有情况下都生效,它依赖于Exchange Type,比如fanout类型的Exchange就会无视binding key,而是将消息路由到所有绑定到该Exchange的Queue.

9.Exchange Types

RabbitMQ一般的Exchange Type有fanout、direct、topic、headers这四种。fanout、direct、topic比较常用headers并不常用。

1.fanout:它会把所有发送到该Exchange的消息路由到所有与它绑定的Queue中.

2.direct: DirectExchange是RabbitMQ Broker的默认Exchange,它有一个特别的属性对一些简单的应用来说是非常有用的,在使用这个类型的Exchange时,可以不必指定routing key的名字,在此类型下创建的Queue有一个默认的routing key,这个routing key一般同Queue同名。

3.topic:direct类型的Exchange路由规则是完全匹配binding key与routing key,但这种严格的匹配方式在很多情况下不能满足实际业务需求。topic类型的Exchange在匹配规则上进行了扩展,它与direct类型的Exchage相似,也是将消息路由到binding key与routing key相匹配的Queue中,但这里的匹配规则有些不同,它约定:

1)、routing key为一个句点号“. ”分隔的字符串(我们将被句点号“. ”分隔开的每一段独立的字符串称为一个单词)
2)、binding key与routing key一样也是句点号“. ”分隔的字符串 binding key中可以存在两种特殊字符“*”与“#”,用于做模糊匹配,其中“*”用于匹配一个单词,“#”用于匹配多个单词(可以是零个)