1. AMQP简介

在了解RabbitMQ之前,首先要了解AMQP协议。AMQP,即Advanced Message Queuing Protocol,高级消息队列协议,是应用层协议的一个开放标准,为面向消息的中间件设计。

当前各种应用大量使用异步消息模型,并随之产生众多消息中间件产品及协议,标准的不一致使应用与中间件之间的耦合限制产品的选择,并增加维护成本。AMQP是一个提供统一消息服务的应用层标准协议,基于此协议的客户端与消息中间件可传递消息,并不受不同客户端/中间件产品,不同开发语言等条件的限制。

AMQP的主要特征是面向消息、队列、路由(包括点对点和发布/订阅)、可靠性、安全。

AMQP的实现有:

  • OpenAMQ

  • AMQP的开源实现,用C语言编写,运行于Linux、AIX、Solaris、Windows、OpenVMS

  • Apache Qpid

  • Apache的开源项目,支持C++、Ruby、Java、JMS、Python和.NET

  • Redhat Enterprise MRG

  • 实现了AMQP的最新版本0-10,提供了丰富的特征集,比如完全管理、联合、Active-Active集群,有Web控制台,还有许多企业级特征,客户端支持C++、Ruby、Java、JMS、Python和.NET

  • RabbitMQ

  • 一个独立的开源实现,服务器端用Erlang语言编写,支持多种客户端,如:Python、Ruby、.NET、Java、JMS、C、PHP、ActionScript、XMPP、STOMP等,支持AJAX。RabbitMQ发布在Ubuntu、FreeBSD平台

  • AMQP Infrastructure

  • Linux下,包括Broker、管理工具、Agent和客户端

  • ØMQ

  • 一个高性能的消息平台,在分布式消息网络可作为兼容AMQP的Broker节点,绑定了多种语言,包括Python、C、C++、Lisp、Ruby等

  • Zyre

  • 是一个Broker,实现了RestMS协议和AMQP协议,提供了RESTful HTTP访问网络AMQP的能力

以上是AMQP中的核心概念:

  • Broker

  • 消息服务器的实体

  • 虚拟主机(Virtual Host)

  • 一批交换器、消息队列和相关对象。虚拟主机是共享相同的身份认证和加密环境的独立服务器域。客户端应用程序在登录到服务器之后,可以选择一个虚拟主机。每个连接(包括所有channel)都必须关联至一个虚拟主机

  • 交换器(Exchange)

  • 服务器中的实体,用来接收生产者发送的消息并将这些消息路由给服务器中的队列

  • 消息队列(Message Queue)

  • 服务器中的实体,用来保存消息直到发送给消费者

  • 生产者(Producer)

  • 一个向交换器发布消息的客户端应用程序

  • 消费者(Consumer)

  • 一个从消息队列中请求消息的客户端应用程序

  • 绑定器(Binding)

  • 将交换器和队列连接起来,并且封装消息的路由信息

所有这些组件的属性各不相同,但是只有交换器和队列被命名。客户端可以通过交换器的名字来发送消息,也可以通过队列的名字收取信息。因为AMQ 协议没有一个通用的标准方法来获得所有组件的名称,所以客户端对队列和交换器的访问被限制在仅能使用熟知的或者只有自己知道的名字。

绑定器没有名字,它们的生命期依赖于所紧密连接的交换器和队列。如果这两者任意一个被删除掉,那么绑定器便失效了。这就说明,若要知道交换器和队列的名字,还需要设置消息路由。

消息是一个不透明的数据包,这些包有如下性质:

  •  元数据,例如内容的编码或者表明来源的字段

  •  标志位,标记消息投递时候的一些保障机制

  •  一个特殊的字段叫做routing key

发送消息是一个非常简单的过程。客户端声明一个它想要发送消息的目的交换器,然后将消息传递给交换器。

接受消息的最简单办法是设置一个订阅。客户端需要声明一个队列,并且使用一个绑定器将之前的交换器和队列绑定起来,这样的话,订阅就设置完毕。

交换器的类型:

  • fanout交换器

  • 不会解释任何东西:它只是将消息投递到所有绑定到它的队列中

  • direct交换器

  • 将消息根据其routing-key属性投递到包含对应key属性的绑定器上

  • topic交换器

  • 模式匹配分析消息的routing-key属性。它将routing-key和binding-key的字符串切分成单词。这些单词之间用点隔开。它同样也会识别两个通配符:#匹配0个或者多个单词,*匹配一个单词。例如,binding key *.stock.#匹配routing-key usd.stcok和eur.stock.db,但是不匹配stock.nasdaq

  • header交换器

  • 根据应用程序消息的特定属性进行匹配

  • failover和system交换器

  • 当前RabbitMQ版本中均未实现

没有绑定器,哪怕是最简单的消息,交换器也不能将其投递到队列中,只能抛弃它。通过订阅一个队列,消费者能够从队列中获取消息,然后在使用过后将其从队列中删除。

不同于队列的是,交换器有相应的类型,表明它们的投递方式(通常是在和绑定器协作的时候)。因为交换器是命名实体,所以声明一个已经存在的交换器, 但是试图赋予不同类型是会导致错误。客户端需要删除这个已经存在的交换器,然后重新声明并且赋予新的类型。

交换器也有一些性质:

  •  持久性:如果启用,交换器将会在Broker重启前都有效

  •  自动删除:如果启用,那么交换器将会在其绑定的队列都被删除掉之后自动删除掉自身

  •  惰性:如果没有声明交换器,那么在执行到使用的时候会导致异常,并不会主动声明

AMQP Broker都会对其支持的每种交换器类型(为每一个虚拟主机)声明一个实例。这些交换器的命名规则是amq.前缀加上类型名。例如 amq.fanout。空的交换器名称等于amq.direct。对这个默认的direct交换器(也仅仅是对这个交换器),Broker将会声明一个绑定了系统中所有队列的绑定器。

这个特点告诉我们,在系统中,任意队列都可以和默认的direct交换器绑定在一起,只要其routing-key等于队列名字。

默认绑定器的行为揭示了多绑定器的存在,将一个或者多个队列和一个或者多个交换器绑定起来。这使得可以将发送到不同交换器的具有不同routing key(或者其他属性)的消息发送到同一个队列中。

队列也有以下属性,这些属性和交换器所具有的属性类似。

  •  持久性:如果启用,队列将会在Broker重启前都有效

  •  自动删除:如果启用,那么队列将会在所有的消费者停止使用之后自动删除掉自身

  •  惰性:如果没有声明队列,那么在执行到使用的时候会导致异常,并不会主动声明

  •  排他性:如果启用,队列只能被声明它的消费者使用

这些性质可以用来创建例如排他和自删除的transient或者私有队列。这种队列将会在所有链接到它的客户端断开连接之后被自动删除掉 – 它们只是短暂地连接到Broker,但是可以用于实现例如RPC或者在AMQ上的对等通信。

AMQP上的RPC是这样的:RPC客户端声明一个回复队列,唯一命名(例如用UUID19), 并且是自删除和排他的。然后它发送请求给一些交换器,在消息的reply-to字段中包含了之前声明的回复队列的名字。RPC服务器将会回答这些请求,使用消息的reply-to作为routing key(之前提到过默认绑定器会绑定所有的队列到默认交换器)发送到默认交换器。注意仅仅是惯例而已。根据和RPC服务器的约定,它可以解释消息的任何属性(甚至数据体)来决定回复给谁。

队列也可以是持久的,可共享,非自动删除以及非排他的。使用同一个队列的多个用户接收到的并不是发送到这个队列的消息的一份拷贝,而是这些用户共享这队列中的一份数据,然后在使用完之后删除掉。


RabbitMQ简介

RabbitMQ是一个遵循AMQP协议的消息中间件,它从生产者接收消息并递送给消费者,在这个过程中,根据规则进行路由,缓存与持久化。

几个概念说明(完全遵循AMQP中的概念):

  •  Broker:简单来说就是消息队列服务器实体

  •  Exchange:消息交换机,它指定消息按什么规则,路由到哪个队列

  •  Queue:消息队列载体,每个消息都会被投入到一个或多个队列

  •  Binding:绑定,它的作用就是把exchange和queue按照路由规则绑定起来

  •  Routing Key:路由关键字,exchange根据这个关键字进行消息投递

  •  vhost:虚拟主机,一个broker里可以开设多个vhost,用作不同用户的权限分离

  •  producer:消息生产者,就是投递消息的程序

  •  consumer:消息消费者,就是接受消息的程序

  •  channel:消息通道,在客户端的每个连接里,可建立多个channel,每个channel代表一个会话任务

消息队列的使用过程大概如下:

  1. 客户端连接到消息队列服务器,打开一个channel

  2. 客户端声明一个exchange,并设置相关属性

  3. 客户端声明一个queue,并设置相关属性

  4. 客户端使用routing key,在exchange和queue之间建立好绑定关系

  5. 客户端投递消息到exchange

exchange接收到消息后,就根据消息的key和已经设置的binding,进行消息路由,将消息投递到一个或多个队列里。

exchange也有几个类型,完全根据key进行投递的叫做Direct交换机,例如,绑定时设置了routing key为”abc”,那么客户端提交的消息,只有设置了key为”abc”的才会投递到队列。对key进行模式匹配后进行投递的叫做Topic交换机,符号”#”匹配一个或多个词,符号”*”匹配正好一个词。例如”abc.#”匹配”abc.def.ghi”,”abc.*”只匹配”abc.def”。还有一种不需要key的,叫做Fanout交换机,它采取广播模式,一个消息进来时,投递到与该交换机绑定的所有队列。

RabbitMQ支持消息的持久化,消息队列持久化包括3个部分:

  •  exchange持久化,在声明时指定durable为true

  •  queue持久化,在声明时指定durable为true

  •  消息持久化,在投递时指定delivery_mode 为2(1是非持久化)

如果exchange和queue都是持久化的,那么它们之间的binding也是持久化的。如果exchange和queue两者之间有一个持久化,一个非持久化,就不允许建立绑定。

RabbitMQ的特性:

  •  可靠性:包括消息持久化,消费者和生产者的消息确认

  •  灵活路由:遵循AMQP协议,支持多种Exchange类型实现不同路由策略

  •  分布式:集群的支持,包括本地网络与远程网络

  •  高可用性:支持主从备份与镜像队列

  •  多语言支持:支持多语言的客户端

  •  WEB界面管理:可以管理用户权限,exhange,queue,binding,与实时监控

  •  访问控制:基于vhosts实现访问控制

  •  调试追踪:支持tracing,方便调试




关注极客云图了解更多内容