RabbitMQ基础

来源:互联网 发布:人工智能 下半场 编辑:程序博客网 时间:2024/06/05 07:30

最近需要用到Rabbitmq来转发消息数据,在这里总结一下RabbitMQ的基本概念。

RabbitMQ简介

消息队列(Message Queue,简称MQ)是一种应用程序之间通信方法。应用程序之间通过向指定消息服务器读写数据出入队列的消息来通信,而无需直接两两建立连接。该方法也可以用于构建需要使用远程过程调用(RPC)的应用。

AMQP,即Advanced Message Queuing Protocol,高级消息队列协议,是应用层协议的一个开放标准,为面向消息的中间件设计。AMQP的主要特征是面向消息、队列、路由(包括点对点和发布/订阅)、可靠性、安全。

RabbitMQ是一个使用Erlang语言开发的AMQP开源实现,是目前使用的最多的AMQP实现,支持多种语言客户端,如:Python、Ruby、.NET、Java、JMS、C、PHP、ActionScript、XMPP、STOMP等,支持AJAX。

RabbitMQ基本概念

RabbitMQ主要由Producer、Broker server和Consumer组成,其中Broker server包括Exchange和Queue:

Producer

数据或消息的发送方。负责创建消息并将消息发布(publish)到Broker server(准确地讲是发布到Exchange中),所发送的消息有两部分组成:消息主体(payload)和路由信息(routing key)。消息主体是以二进制数据的形式进行转发和接收的。打个简单的比方,Producer就像寄信人。

Exchange

消息的转发者。负责接收由生产者(Producer)发布的消息,并根据消息的路由信息(routing key)将消息主体投递到合适的队列(Queue)中。从Exchange根据路由信息转发的方式可以分为fanout、direct、topic、headers这四种。简单来说,Exchange就像负责转发信件的邮局。

Queue

消息的接收队列。负责接收来自Exchange的消息,维护队列消息有序和持久性。消息最后被消费者(Consumer)获取并被确认(Ack)之后便自动销毁。需要注意的是,RabbitMQ不支持对已存在的队列进行修改,所以重复定义(Declare)一个同名的队列并不会改变原来队列的属性。简单来说,Queue就像暂存信件的信箱。

Consumer

消息的消费者。从队列(Queue)获取到消息后进行处理并确认(Ack)。简单来说,Consumer就像收信人。

除上述基本概念之外,还有使用RabbitMQ api时必须接触的概念:

ConnectionFactory、Connection、Channel

在创建与Broker server(即RabbitMQ server)的连接使用的对象。ConnectionFactory是Connection的创建工厂,通过Connection可以创建Channel对象。Channel是与RabbitMQ交互的主要接口,许多操作都是通过它的接口完成的,包括定义定义Exchange、定义Queue、绑定(bind)Queue和Exchange还有最重要的发布和接收消息等。

Round-robin dispatching

默认地,RabbitMQ一般会循环消费者订阅的顺序来分派发送队列中不同的消息(有消费者宕机则可能会相同),这样能够一般情况下能够保证所有消费者收到同样多的消息。这种方式官方命名为”round-robin”。

Message acknowledgement

RabbitMQ中队列的消息都是需要确认(Acknowledgement)后才能销毁,而RabbitMQ默认从队列中获取消息后自动确认。但有时候我们需要进行的消息处理是一个耗时操作,特别是在涉及数据库操作或者RPC调用时,万一在处理过程中宕机了,这时候就会发生消息丢失,这是我们不愿意看到的。
为了避免这种情况的发生,我们就需要在对某一可能导致耗时操作的消息进行处理时,将自动确认机制关闭,然后处理后手动由应用程序来完成确认。这样做的好处是,RabbitMQ在没有收到Ack的时候,如果发现原来的客户端断开连接了(可能宕机了),那么RabbitMQ就会将消息发送给其他订阅了该队列的消费者,因而保证了消息不会丢失。

Message durability

尽管我们通过关闭自动确认机制保证了RabbitMQ运行期间消息不会丢失,但万一保存队列消息的RabbitMQ server因故障停止了,按照默认的设置,消息(和队列)还是会丢失。
解决办法是,首先我们要保证队列的持久性,通过定义Queue的时候设置durable属性为true,这样在RabbitMQ server宕机重启之后原来的队列还在。然后,我们还需要在发布消息时将消息标识为持久化,这样server宕机后队列还能从磁盘中还原消息(这些操作由RabbitMQ帮助我们完成)。
注意:尽管有上述机制做保障,但还是不能完全保证消息不会丢失,比如消息还未完成向磁盘文件中备份就宕机,消息还是会有丢失的可能。最保险的方法就是在客户端加多一层确认机制,参照官方文档(https://www.rabbitmq.com/confirms.html)

Fair dispatch

在round-robin的分派方式下,有可能会出现某一消费者总接收到负担较重的消息的情况。例如:有两个消费者订阅了同一个队列,而刚好序号(假如存在)为偶数的消息计算任务较重,那么第二个订阅该队列的消费者就总是会收到计算任务较重的消息。出现这种情况的原因是RabbitMQ采用的是Fair dispatch,对订阅队列的消费者一视同仁,不管消息具体是什么或当前消费者负担如何,而只按照顺序分派发送给消费者。
解决办法(java当中)便是设置basicQos为1,这样子消费者一次只会接收到一个消息,在处理完成和Ack之前RabbitMQ不会再向他分派消息。

Bindings

Binding是Exchange和Queue的一种关联关系。可以通过binding key将指定Exchange和指定Queue绑定在一起,这样在Exchange转发消息时,就可以(由Exchange类型决定)根据消息的路由信息(routing key)与binding key匹配情况转发到相应的Queue。

Exchange type

Exchange的类型决定了Exchange转发消息时如何将routing key与binding key进行匹配,RabbitMQ常用的Exchange Type有fanout、direct、topic、headers这四种:

fanout:fanout类型的Exchange路由规则非常简单,它会把所有发送到该Exchange的消息路由到所有与它绑定的Queue中。

在上面的例子中,Exchange将会把消息都转发给所有与它关联(bind)的队列。

direct:direct类型的Exchange路由规则也很简单,它会把消息路由到那些binding key与routing key完全匹配的Queue中。

在上面的例子中,routing key为orange的将被转发给Q1,而routing key为black或green的将被转发给Q2。

topic:发布到Exchange的routing key必须具有明确的内容(用点号分隔),binding key也是类似。但在topic类型的Exchange中有两个例外:

* 可以用来匹配仅一个字串(两个点号内的内容)
# 可以用来匹配零或多个字串


一条routing key为”quick.orange.rabbit”将会被转发给上面的两个队列,routing key为”lazy.orange.elephant”的消息也会被转发给这两个队列。另外,”quick.orange.fox”将会被转发给Q1,”lazy.pink.rabbit”将会被转发给Q2。而”quick.brown.fox”没有匹配的binding key最后被丢弃。
注意:假如binding key没有使用上面两个通配符,此时的Exchange对该Queue工作方式就像direct Exchange;另一方面,如果binding key使用的是”#”,则此时就类似fanout。

headers:headers类型的Exchange不依赖binding key与routing key的匹配规则来分派消息,而是根据消息内容中的headers属性来匹配。headers是一个键值对集合,可以用HashMap实现。发送方发布消息时定义键值对,接收方在将Queue与Exchange绑定时也定义键值对,这样发布的消息就会根据匹配规则发送到相应接收方。其中匹配规则有两种:all和any。匹配规则需要在接收端定义headers时用键名”x-match”来定义,值便是all或any。实际使用较少,这里不再详细举例。

原创粉丝点击