背景
20世纪八十年代,来自孟买的年轻工程师为了解决应用程序之间繁重的信息通信工作,创造性的提出了用一种总线的方式来规整信息通信,于是消息总线诞生。
随着技术的发展,这种总线的想法和发布订阅的通信模型得到越来越多人的认可,于是在80年代的后期,各大厂商都开始研发自己的消息队列。众多的MQ产品使用不同的API、底层使用不同的消息协议,统一MQ的使用日渐迫切。为了解决统一使用MQ的问题,在2001年JMS诞生了。
JMS试图通过提供公共Java API的方式,隐藏单独MQ产品提供商的实际接口,从而解决了各种MQ使用互通的问题。
AMQP 协议的诞生
JMS 非常棒,微软也开发了NMS(.NET 消息传递服务)来支持他们的平台和编程语言,它的效果也还不错,但使用两套不同标准的应用之间该怎么异步消息通信呢,因此,需要一个异步消息的通用标准。
JMS、NMS都没有标准的底层协议,并且API是与编程语言绑定的。为了解决这个问题,AMQP诞生了。
AMQP(Advanced Message Queueing Protocal) 是独立于平台的底层消息底层协议,具有跨语言及平台,支持经典的消息队列,循环,存储于转发,支持事务等特性,以解决众多的消息队列需求和拓扑结构问题。
什么是RabbitMQ
RabbitMQ(Rabbit Message Queue),是一种开源的消息队列中间件,最核心的特点是天生对AMQP(Advanced Message Queueing Protocal)协议的支持。该消息队列采用Erlang语言开发。
RabbitMQ的特点:
- 异步消息技术(支持多种消息协议,如AMQP、消息投递确认机制、多种交换器、灵活的消息路由)
- 支持多客户端语言(Java、python、PHP等)
- 分布式集群部署
- 丰富的plugins
- 内置强大的服务器监控系统
RabbitMQ AMQP协议消息通信模型

RabbitMQ 依然使用生产者消费者概念,我们开发的应用程序可以作为生产者或者消费者。生产者创建消息,并对消息设置标签(路由键),发送消息到RabbitMQ;消费者也连接到RabbitMQ,进行订阅消息,从而实现生产者和消费者的异步通信。消费消息时,接收到的消息只是消息的内容,没有标签。
在整个模型中,有几个重要的概念:生产者Producer、消费者Consumer、信道channel、连接Connection、交换器Exchange、绑定Bing、队列Queue,接下来会逐一解释。
注意:RabbitMQ默认支持AMQP协议,其实这里的消息通信模型是指AMQP协议的消息通信模型
信道 vs 连接
无论发布消息或是消费消息,首先你必须连接到RabbitMQ。此时,你的应用程序和Rabbit服务器之间创建了一条TCP连接。因为创建TCP连接的开销较大,因此,RabbitMQ创建了信道这个概念。信道是建立在真正的TCP连接内的虚拟连接,AMQP命令是通过信道发送出去。

交换器Exchange 和 绑定Binding

AMQP的生产者不会直接将消息发布到队列中,AMQP在消息的生产者以及传递消息队列之间引入了交换器这种间接机制。消息先发给交换器,然后根据路由键,和交换器的类型,来决定消息应该投递到哪个队列。
交换器Exchange通过路由键来绑定一个或多个队列。路由键就是图中形如api_call、logs.*等的字符串。
AMQP协议定义了四种类型的交换器,每种类型实现了不同的路由算法
- headers 交换器:允许你匹配AMQP消息的header,而非路由键。除此之外,headers与direct完全一致,但性能差,不推荐使用
- direct交换器:直接匹配路由键,消息匹配成功后入队列
- fanout交换器:交换器将收到的消息广播到绑定的所有队列上,每个队列拥有消息的一个副本。
-
topic交换器:可以使得来自不同源头的消息到达同一个队列。消息的路由键通过*来分为几部分,*用来匹配特定部分的任意文本。
topic类型.png
topic交换器接收到两条消息,路由键分别为log.critical、alert.critical。交换器同时通过log.*绑定了Q1,通过*.critical绑定了Q2,通过alert.* 绑定了Q3。因此log.critical消息符合两条路由路径,所有被发送到Q1、Q2,alert.critical消息符合两条路由路径,所以被发送到Q2、Q3。
队列
生产者把消息发布到交换器上,消息最终会到达队列,并被消费者接收。消费者通过以下两种方式从队列中接收消息:
- AMQP basic.consume命令 这样会将信道设置为接收模式,消费者在接收一条消息后,能自动接收下条消息,直到取消对队列的订阅为止。
- AMQP basic.get命令 每发送一次basic.get命令,消费者能够从队列中获取一条消息。
当队列拥有多个消费者时,队列接收到的消息将以round-robin方式发送给消费者。每条消息只会发送给一个订阅的消费者。
队列消息将以循环(round_robin)方式发给消费者
假设有一个消息队列seed_bin,有两个消费者A、B,消息投递方式如下:
(1)消息Message_A到达seed_bin
(2)RabbitMQ把消息Message_A发送给A
(3)A向RabbitMQ确认,接收到Message_A
(4)RabbitMQ把Message_A从seed_bin 中删除
(5)消息Message_B到达seed_bin
(6)RabbitMQ把消息Message_B发送给B
(7)B向RabbitMQ确认,接收到Message B
(8)RabbitMQ删除Message_B消息
注意细节:消费者会确认收到消息、缺认后消息被删除
RabbitMQ 内置监控系统

RabbitMQ系统默认自带一个管理系统,在15672端口监听。默认登录用户名/密码为guest:guest。可以看到主界面分别对Connections连接、信道、交换器、队列进行了管理。更具体的操作,在文末有参考资料。
总结
- AMQP三大组件:交换器、队列、绑定
- 消息设置路由键后,发布到交换器
- 队列根据路由键绑定到交换器
- 常用三种类型交换器:topic、direct、fanout
- round-robin消费算法
参考资料
-1. AMQP协议官方网站
-2. RabbitMQ 官方网站
-3. 实现JMS的ActiviteMQ
-4. 各种主流的MQ性能对比
网友评论