05 29,2018

消息队列RabbitMQ(一):介绍

什么是RabbitMQ?

AMQP,即Advanced Message Queuing Protocol,高级消息队列协议,是应用层协议的一个开放标准,为面向消息的中间件设计。消息中间件主要用于组件之间的解耦,消息的发送者无需知道消息使用者的存在,反之亦然。 AMQP的主要特征是面向消息、队列、路由(包括点对点和发布/订阅)、可靠性、安全。

RabbitMQ是一个开源的AMQP实现,服务器端用Erlang语言编写,支持多种客户端,如:Python、Ruby、.NET、Java、JMS、C、PHP、ActionScript、XMPP、STOMP等,支持AJAX。用于在分布式系统中存储转发消息,在易用性、扩展性、高可用性等方面表现不俗。

基本特性

1)可靠性
消息持久化、消息发送和投递确认机制、集群高可用方案

2)灵活路由
消息通过exchange的方式路由到不同的queue中,提供了包括fanout, direct, topic等多种exchange实现,并且支持通过编写exchange插件的方式自实现路由方案

3)支持集群
同网段下的rabbitmq节点可以通过集群的方式,组成一个逻辑上的单一broker

4)Federation
通过Federation可以在跨网段节点间组件集群

5)高可用消息队列
通过设置镜像队列的方式,消息可以在镜像队列间进行复制,使节点down机或硬件损坏的情况下保证队列服务的高可用

6)多协议支持
包括AMQP, STOMP, MQTT, HTTP等多种消息交换协议

7)多客户端支持
JAVA, .NET, Ruby, Python, PHP, Node, Go……

8)可视化管理界面
RabbitMQ 提供了一个易用的用户界面,使得用户可以监控和管理消息 Broker 的许多方面。

9)丰富的插件支持
tracing, managment-plugin, and you can also write your own.

RabbitMQ中的重要概念

Virtual Host

虚拟主机,表示一批交换器、消息队列和相关对象。虚拟主机是共享相同的身份认证和加密环境的独立服务器域。每个 vhost 本质上就是一个 mini 版的 RabbitMQ 服务器,拥有自己的队列、交换器、绑定和权限机制。vhost 是 AMQP 概念的基础,必须在连接时指定,RabbitMQ 默认的 vhost 是 / 。

Broker

经纪人。提供一种传输服务,维护一条从生产者到消费者的传输线路,保证消息数据能按照指定的方式传输。粗略的可以将图中的RabbitMQ Server当作Broker。

Producer

消息生产者。主要将消息投递到对应的Exchange上面。一般是独立的程序。

Consumer

消息消费者。消息的接收者,一般是独立的程序。

Message

消息,消息是不具名的,它由消息头和消息体组成。消息体是不透明的,而消息头则由一系列的可选属性组成,这些属性包括routing-key(路由键)、priority(相对于其他消息的优先权)、delivery-mode(指出该消息可能需要持久性存储)等。

Channel

信道,多路复用连接中的一条独立的双向数据流通道。信道是建立在真实的TCP连接内地虚拟连接,AMQP 命令都是通过信道发出去的,不管是发布消息、订阅队列还是接收消息,这些动作都是通过信道完成。

对于操作系统来说,建立和关闭TCP连接是有代价的,频繁的建立关闭TCP连接对于系统的性能有很大的影响,而且TCP的连接数也有限制,这也限制了系统处理高并发的能力。但是,在TCP连接中建立Channel是没有上述代价的。对于Producer或者Consumer来说,可以并发的使用多个Channel进行Publish或者Receive。

Exchange

消息交换机。指定消息按照什么规则路由到哪个队列Queue。

Producer将并不能直接将消息投递到Queue中。需要将消息发送到Exchange,由Exchange将消息路由到一个或多个Queue中(或者没有绑定Queue的情况下将消息丢弃)。

Exchange是按照什么逻辑将消息路由到Queue的?这个将在下面Binding中介绍。 RabbitMQ中的Exchange有四种类型,不同的类型有着不同的路由策略,这将在下面Exchange类型中介绍。

Queue

消息队列。消息的载体,每条消息都会被投送到一个或多个队列中。

RabbitMQ中的消息都只能存储在Queue中,Producer生产消息并通过Exchange投递到Queue中,Consumer可以通过Exchange从Queue中获取消息并消费。

多个消费者可以订阅同一个Queue,这时Queue中的消息会被平均分摊给多个消费者进行处理,而不是每个消费者都收到所有的消息并处理。

Binding

绑定。作用就是将Exchange和Queue按照某种路由规则绑定起来。这样RabbitMQ就知道如何正确地将消息路由到指定的Queue了。

Exchange 和 Queue的绑定

生产者发送 key 和 数据 ,消费者定义订阅的 队列 ,Broker收到数据之后会通过 一定的逻辑计算出key对应的队列,然后把数据交给队列。
通过绑定模式下解耦了key和queue,在这种架构中queue是非常轻量级的(在RabbitMQ中它的上限取决于你的内存),消费者关心的只是自己的queue;生产者不必关心数据最终给谁只要指定key就行了。

Routing Key

生产者在将消息发送给Exchange的时候,一般会指定一个routing key,来指定这个消息的路由规则,而这个routing key需要与Exchange Type及binding key联合使用才能最终生效。
在Exchange Type与binding key固定的情况下(在正常使用时一般这些内容都是固定配置好的),我们的生产者就可以在发送消息给Exchange时,通过指定routing key来决定消息流向哪里。
RabbitMQ为routing key设定的长度限制为255 bytes。

Binding Key

在绑定(Binding)Exchange与Queue的同时,一般会指定一个binding key;消费者将消息发送给Exchange时,一般会指定一个routing key;当binding key与routing key相匹配时,消息将会被路由到对应的Queue中。这个将在Exchange Types章节会列举实际的例子加以说明。
在绑定多个Queue到同一个Exchange的时候,这些Binding允许使用相同的binding key。
binding key 并不是在所有情况下都生效,它依赖于Exchange Type,比如fanout类型的Exchange就会无视binding key,而是将消息路由到所有绑定到该Exchange的Queue。

Exchange Type

direct

消息中的路由键(routing key)如果和 Binding 中的 binding key 一致, 交换器就将消息发到对应的队列中。路由键与队列名完全匹配,如果一个队列绑定到交换机要求路由键为“dog”,则只转发 routing key 标记为“dog”的消息,不会转发“dog.puppy”,也不会转发“dog.guard”等等。它是完全匹配、单播的模式。

fanout

每个发到 fanout 类型交换器的消息都会分到所有绑定的队列上去。fanout 交换器不处理路由键,只是简单的将队列绑定到交换器上,每个发送到交换器的消息都会被转发到与该交换器绑定的所有队列上。很像子网广播,每台子网内的主机都获得了一份复制的消息。fanout 类型转发消息是最快的。

topic

topic 交换器通过模式匹配分配消息的路由键属性,将路由键和某个模式进行匹配,此时队列需要绑定到一个模式上。它将路由键和绑定键的字符串切分成单词,这些单词之间用点隔开。它同样也会识别两个通配符:符号“#”和符号“”。#匹配0个或多个单词,匹配不多不少一个单词。

headers

headers 匹配 AMQP 消息的 header 而不是路由键,此外 headers 交换器和 direct 交换器完全一致,但性能差很多,目前几乎用不到了。

总结

本文只是简单介绍了RabbitMQ的一些特性。具体的实际使用请看接下来的文章。

参考资料

https://www.jianshu.com/p/79ca08116d57
http://www.infoq.com/cn/articles/kafka-vs-rabbitmq
https://my.oschina.net/u/236698/blog/501834