RabbitMQ研究与应用一.背景介绍1.1相关概念谈到RabbitMQ,首先要谈到MQ和AMQP.MQ全称为MessageQueue,消息队列(MQ)是一种应用程序对应用程序的通信方法。应用程序通过写和检索出入列队的针对应用程序的数据(消息)来通信,而无需用专用连接来链接它们。AMQP:AdvancedMessageQueuingProtocol,高级消息队列协议,是应用层协议的一个开放标准,为面向消息的中间件设计。AMQP的主要特征是面向消息、队列、路由(包括点对点和发布/订阅)、可靠性、安全性要求很严格。AMQP允许来自不同供应商的消息生产者和消费者实现真正的互操作扩展,就如同SMTP、HTTP、FTP等协议采用的方式一样。而此前对于消息中间件的标准化努力则集中在API层面上(比如JMS),且没有提供互操作性的途径。不同于JMS的仅仅定义API,AMQP是一个线路级的协议——它描述了通过网络传输的字节流的数据格式。因此,遵从这个协议的任何语言编写的工具均可以操作AMQP消息。AMQP的实现有:1.OpenAMQAMQP的开源实现,用C语言编写,运行于Linux、AIX、Solaris、Windows、OpenVMS。2.ApacheQpidApache的开源项目,支持C++、Ruby、Java、JMS、Python和.NET。3.RedhatEnterpriseMRG实现了AMQP的最新版本0-10,提供了丰富的特征集,比如完全管理、联合、Active-Active集群,有Web控制台,还有许多企业级特征,客户端支持C++、Ruby、Java、JMS、Python和.NET。4.RabbitMQ一个独立的开源实现,服务器端用Erlang语言编写,支持多种客户端,如:Python、Ruby、.NET、Java、JMS、C、PHP、ActionScript、XMPP、STOMP等,支持AJAX。RabbitMQ发布在Ubuntu、FreeBSD平台。5.AMQPInfrastructureLinux下,包括Broker、管理工具、Agent和客户端。6.?MQ一个高性能的消息平台,在分布式消息网络可作为兼容AMQP的Broker节点,绑定了多种语言,包括Python、C、C++、Lisp、Ruby等。7.Zyre是一个Broker,实现了RestMS协议和AMQP协议,提供了RESTfulHTTP访问网络AMQP的能力。RabbitMQ是由LShift提供的一个AMQP的开源实现,由以高性能、健壮以及Scalability出名的Erlang写成,因此也是继承了这些优点。ZeroMQ和RabbitMQ都支持开源消息协议AMQP,不过ZeroMQ暂时不支持消息持久化和崩溃恢复,且稳定度稍差。而RabbitMQ克服了这几大缺点,因而成功的在这几大协议中脱颖而出。1.2诞生背景AMQP主要是由金融领域的软件专家们贡献的创意,而联合了通讯和软件方面的力量,一起打造出来的规范。粗略的讲AMQP首先满足的是金融系统的消息通讯业务需求。这是一个可以和JMS进行类比的消息中间件开放规范,所不同的是AMQP同时定义了消息中间件的语意层面和协议层面;另外一个不同是AMQP是语言中立的,而JMS仅和Java相关。AMQP在“语意层面的定义”,这就意味着,它并不仅仅是象JMS或者其他的MQ一样,仅能按照预定义的方式工作,而是“可编程”的消息中间件。而“语言中立”则意味着只要遵循AMQP的协议,任何一种语言都可以开发消息组件乃至中间件本身。二.基本原理2.1核心组件:Exchange&QueueRabbitMQ的两大核心组件是Exchange和Queue,以下是它的运行原理图:图1RabbitMQ通信原理图1中,绿色的X就是Exchange,红色的是Queue,这两者都在Server端,又称作Broker,这部分是RabbitMQ实现的,而蓝色的则是客户端,通常有Producer和Consumer两种类型。Exchange,又称交换器,它接受消息和路由信息,然后将消息发送给消息队列。对于每个虚拟主机内部,交换器有独一无二的名字。应用程序在其权限范围之内可以自由的创建、共享、使用和销毁交换器实例。交换器可以是持久的、临时的或者自动删除的。持久交换器会一直存在于服务器,直到它被显式删除;临时交换器会工作到服务器被关闭时为止;而一旦没有应用程序使用自动删除交换器,它就会被服务器自动删除掉。消息队列是一个具名缓冲区,它们代表一组消费者应用程序保存消息。应用程序在其权限范围之内可以自由的创建、共享、使用和消费消息队列。消息队列提供了有限制的先进先出保证。服务器会将从某一个生产者发出的同等优先级的消息按照它们进入队列的顺序传递给某个消费者,万一某些消息不能被消费者处理,它们可能会被打乱顺序重新传递。消息队列可以是持久的、临时的或者自动删除的。临时消息队列会工作到服务器被关闭时为止;而一旦没有应用程序使用自动删除消息队列,它就会被服务器自动删除掉。只要用户(客户端)拥有相应的权限,任何队列都可以被显式删除。消息队列将消息保存在内存、硬盘,或者这两种介质的组合之中。消息队列限定在虚拟主机范围之中。消息队列保存消息,并将消息分发给一个或多个订阅客户端。消息队列会跟踪消息的获取情况,消息要出队就必须被获取(acquire和consume是两个动作,先执行acquire,相当于对消息加锁)。这阻止了多个客户端同时获取和消费同一条消息,也可以被用来做单个队列多个消费者之间的负载均衡。2.2重要特性:持久化持久化是RabbitMQ的一大重要特性。设想你花了大量的时间来创建队列、交换机,然后,服务器程序在不明原因下崩溃了,你的队列、交换机,甚至是放在队列里面但是尚未处理的消息都有可能消失。这种后果在某些场景下将会带来不会估计的损失。然而RabbitMQ正有方法解决这一问题。队列和交换机有一个创建时候指定的标志durable(持久化)。durable的唯一含义就是具有这个标志的队列和交换机会在重启之后重新建立,它不表示说在队列当中的消息会在重启后恢复。那么如何才能做到不只是队列和交换机,还有消息都是持久的呢?但是首先一个问题是,我们需要考虑是否真的需要消息是持久化得?对于一个需要在重启之后回复的消息来说,它需要被写入到磁盘上,而即使是最简单的磁盘操作也是要消耗时间的。如果和消息的内容相比,你更看重的是消息处理的速度,那么不要使用持久化的消息。不过大多数场合下将消息设为持久化是很重要。因而一个完全的持久化应当如下:1.将交换机设成durable。2.将队列设成durable。3.将消息设成durable2.3核心概念:绑定所谓绑定就是将一个特定的Exchange和一个特定的Queue绑定起来,绑定关键字成为BindingKey,程序中语句声明方法为:channel.queueBind(Exchange,Queue,BindingKey);Exchange和Queue的绑定可以是多对多的关系,每个发送给Exchange的消息都有一个叫做RoutingKey的关键字,Exchange要想将该消息转发给特定队列,该队列与交换器的BindingKey必须与消息的RoutingKey相匹配才行。为了进一步了解绑定过程,必须先了解Exchange的常见三种类型:2.2.1.直接式交换器类型(direct)直接式交换器类型提供了这样的消息路由机制:通过精确匹配消息的路由关键字,将消息路由到零个或者多个队列中,绑定关键字用来将队列和交换器绑定到一起。这让我们可以构建经典的点对点队列消息传输模型,不过和任何已定义的交换器类型一样,当消息的路由关键字与多个绑定关键字匹配时,消息可能会被发送到多个队列中。直接式交换器的工作方式如下:图2direct类型Exchange通信原理从图中可以看出,当某个消息到达交换器X时,如果的他的RoutingKey是orange,则他将被交付给队列Q1,如果的他的RoutingKey是black或者是green,则他将被交付给队列Q2.此外,direct模式下还可以实现多路绑定,即一个Exchange和多个Queue绑定时具有同样的BindingKey,如图示:图3实现多路绑定Exchange(direct类型)图中,当一个送到交换器X的消息的RoutingKey是black时,该消息将被同时送往队列Q1和队列Q2。2.2.2.广播式交换器类型(fanout)广播式交换器类型提供了这样的路由机制:不论消息的路由关键字是什么,这条消息都会被路由到所有与该交换器绑定的队列中。广播式交换器类型的工作方式如下:不使用任何参数将消息队列与交换器绑定在一起。发布者(直接式交换器类型描述中的producer变成了publisher,已经隐含了二种交换器类型的区别)向交换器发送一条消息。消息被无条件的传递到所有和这个交换器绑定的消息队列中。图4fanout类型Exchange通信原理在图中,送达交换器X的所有消息,将被送到所有和交换器绑定的Queue上。2.2.3.主题式交换器类型(topic)主题式交换器类型提供了这样的路由机制:通过消息的路由关键字和绑定关键字的模式匹配,将消息路由到被绑定的队列中。这种路由器类型可以被用来支持经典的发布/订阅消息传输模型——使用主题名字空间作为消息寻址模式,将消息传递给那些部分或者全部匹配主题模式的多个消费者。主题交换器类型的工作方式如下:绑定关键字用零个或多个标记构成,每一个标记之间用“.”字符分隔。绑定关键字必须用这种形式明确说明,并支持通配符:“*”匹配一个词组,“#”零个或多个词组。因此绑定关键字“*.stock.#”匹配路由关键字“usd.stock”和“eur.stock.db”,但是不匹配“stock.nasdaq”。这种交换器类型是可选的。服务器应该(不是必须)实现主题式交换器类型,在这种情况下,服务器必须事先在每一个虚拟主机中定义至少一个主题式交换器:名为“topic”。图4topic类型Exchange通信原理图中,*可匹配任意一个单词,#可匹配任意多个(包括0个)单词,送到交换器X的消息,匹配了特定的RoutingKey时,就能送达特定的队列。2.4通信过程图1中,左边的客户向右边的客户发送消息:1.在RabbitMQ中申明Conection2.在RabbitMQ中申明Channel3.左边的客户获取Conection4.左边的客户获取Channel5.定义Exchange,Queue6.使用一个RoutingKey将QueueBinding到一个Exchange上7.通过指定一个Exchange和一个RoutingKey来将消息发送到对应的Queue上8.接收方在接收时也是获取connection,接着获取channel,然后指定一个Queue直接到它关心的Queue上取消息,它对Exchange,RoutingKey及如何binding都不关心,到对应的Queue上去取消息就可以了。三.RabbitMQ应用测试3.1平台发送端:linux环境服务器:linux环境接收端:Windows环境3.2开发工具及语言Eclipse、JAVA3.3实验原理发送端定义5个线程,每个线程连续不断地发送数据,数据大小为6KB,RabbitMQ-Server中定义5个Exchange和5个Queue,Exchange全部采用direct类型,接收端5个接收方分别从5个队列中取数据,并行写入数据库,同时写入JFrame,以动态显示所收到的内容,接收完毕后后,查询数据库,可获知每条消息的内容、发送时间、接收时间、耗时。原理图如下所示:图5实验原理图3.4测试过程3.4.1启动RabbitMQ-Server图6启动rabbitmq-server看到一个类似兔子头的标识,标识启动RabbitMQ服务成功3.4.2传送数据五个线程同时发送数据,数据大小为6KB。传送过程:图7传送数据过程3.4.3接收数据接收数据在windows环境下,