RabbitMQ做为一种AMPQ代理服务器,提供了一套严格的通讯方式,核心部分的通讯几乎都使用了RPC(远程过程调用)模式。数据库
AMQP协议定义,当客户端要与RabbitMQ交互时,首先要向RabbitMQ发送一个协议头(protocol header):服务器
要彻底链接到RabbitMQ,会通过由三个同步RPC请求所组成请求序列,这三个RPC请求分别是启动、调整和打开链接。对于应用RabbitMQ而言(不许备开发RabbitMQ Client),启动会话这个阶段并非很是重要,稍做理解就好。网络
AMQP协议定义,信道要使用AMQP链接做为互相传输信息的渠道,并且要将传输过程与其余正在进行中的会话隔离开。一个AMQP链接能够有多个信道,容许客户端和RabbitMQ之间进行屡次会话,技术上称之为多路复用(multiplexing)。数据结构
不要使用过多的信道! 在传输过程当中,信道只是分配给客户端和RabbitMQ之间所传递消息的一个整数值。但在客户端和RabbitMQ中,会为每一个信道设置内存结构和对象,链接中的信道越多,用于管理该链接的消息流所需的内存也就越多。异步
AMQP使用类和方法在客户端和RabbitMQ之间建立公共语言,这些类和方法被称为AMQP命令(AMQP Commands)。AMQP中的类定义了一个功能范围,每一个类都包含执行不一样任务的方法。工具
例如:Connection.Start命令,由两部分组成:AMQP类(Class)和方法(Method)。优化
当使用命令与RabbitMQ进行交互时,执行这些命令,和所须要的全部参数,都被封装在一种数据结构中,而且对这个数据结构进行编码,以便传输。编码
帧由五个部分组成:spa
帧类型分为五种:代理
能够在rabbitmq.config配置文件中设置心跳间隔,设置为0则表明关闭心跳检测机制(若是你的程序在必定程度上阻塞了通讯,使得心跳检测难以正常运做)。
若是要向RabbitMQ发送消息,则会对方法帧、内容头帧和消息帧进行编组。
发送的第一个帧是方法帧,它携带了命令和执行它所需的参数(如交换器和路由键)。
在方法帧以后的是内容头帧,它包含了消息属性以及消息体大小,AMQP的帧大小是有上限的,默认为131KB,若是消息体超过了这个上限,消息内容将被拆分红多个消息体帧。
接着是消息帧,它携带了具体的消息内容。
为了更高效的处理这些帧,方法帧和内容头帧会被打包成二进制数据,消息帧则么有进行任何打包或编码。
虽然帧默认大小是131KB,但客户端在连接过程当中能够设置更大或更小的帧,其最大可达一个32位值。
方法帧携带构建RPC请求所需的类、方法以及相关参数。
这些属性告知RabbitMQ如何路由消息。Mandatory标识则告知RabbitMQ消息必须投递成功,不然发布消息的过程就应该是失败的。
一般,使用Basic.Publish RPC请求发送消息是一个单向会话。可是,若是你在发布消息时使用了mandatory标志,则应用程序应该监遵从RabbitMQ发送回来的Basic.Return命令。若是RabbitMQ不能知足mandatory标志设置的要求,它将在同一个信道上发送一个Basic.Return命令到客户端。
内容头帧除了告知RabbitMQ该消息的大小以外,还包含消息的各类属性。这些属性存储在Basic.Properties映射表中,可包含描述消息内容的数据,也可彻底是空白的。大多数客户端会预先填充一小部分字段,好比内容类型和投递模式。
属性是编写消息的强大工具,他们能够用来在发布者和消费则之间就消息的内容建立契约,从而容许对消息进行大量的定制操做。
消息题帧包含了实际消息数据的结构,能够是图片的二进制数据、序列化后的JSON、XML或字符串等等。
在将消息发布到队列前,有几个与配置相关的步骤,至少须要设置交换器和队列,而后将他们绑定到一块儿,下面会从协议级别来看看进行这么步骤所发生的内部过程。
协议中,建立交换器会使用Exchange.Declare命令,该命令提供了定义交换器名称和类型的参数,以及用于消息处理的其余元数据。
一旦命令被发出,RabbitMQ在建立了交换器以后将发送一个Exchange.DeclareOk的方法帧做为相应。若是处于某些缘由建立失败了,则RabbitMQ将使用Channel.Close命令关闭发送Channel.Declare命令的信道。该响应包含一个数字编码和文本值,用于说明Exchange.Declare失败并关闭信道的缘由。
协议中,建立队列会使用Queue.Declare命令,和建立交换器的过程是同样的。
在声明队列时,屡次发送同一个Queue.Declare命令并不会有任何反作用。
当尝试声明一个与现有队列同名的新队列时,若是新队列的属性与现有队列不同,那么RabbitMQ将关闭发出RPC请求的通道。 要正确的处理错误,通常是由客户端的实现来监听来自RabbitMQ的Channel.Close命令,以便能作出正确响应。 某些客户端实现可让你返回异常,让你的应用程序去捕获并处理。还有的客户端提供回调风格,经过注册一个回调方法来处理。
协议中,绑定交换器与队列的命令是Queue.Bind,每次只能指定一个队列。这一步和建立交换器或建立队列是同样的。
协议中,当发布消息到RabbitMQ时,多个帧封装了发送到服务器的消息数据。
在实际的消息内容到达RabbitMQ以前,客户端应用程序发送一个Basic.Publish方法帧,一个内容头帧和至少一个消息体帧。
当RabbitMQ接收到一个消息的全部帧并肯定下一步操做以前,它将检查方法帧以获取它所须要的信息。Basic.Publish方法帧携带消息的交换器名称和路由键。在评估这些数据时,RabbitMQ会尝试将Basic.Publish帧中的交换器名称与配置交换器的数据库进行匹配。
默认状况下,若是使用RabbitMQ配置中不存在交换器进行消息发布,RabbitMQ将自动丢弃该消息。
若是交换器存在,可是路由不到队列,那么,想要确保消息成功投递,须要在发布时将mandatory标识设置为true,或者使用投递确认机制。
当RabbitMQ发现某一个交换器与Basic.Properties方法帧中的交换器名称相匹配时,它将判断该交换器中的绑定信息,并经过路由键寻找匹配的队列。当消息与任一绑定的队列符合匹配标准时,RabbitMQ服务器将以FIFO的顺序将消息放入队列中。
放入队列数据结构中的并非实际消息,而是消息的引用。当RabbitMQ准备投递消息时,它将使用这个引用来编组消息并经过网络进行发送。这为发布到多个队列的消息提供了实质性的优化。
一旦再也不须要这个消息,实际消息数据将会从RabbitMQ的内存中移除。
默认状况下,只要没有消费者正在监听队列,消息就会被存储在队列中。RabbitMQ能够将这些消息保存到内存或磁盘,具体取决于Basic.Properties中指定的delivery-mode属性。
要消费RabbitMQ队列中的消息,消费者应用程序发出Basic.Consume命令来订阅RabbitMQ中的队列。服务器将返回Basic.ConsumerOk来响应。而后开始向消费者投递消息。
若是要让消费者中止接收消息,则能够发送Basic.Cancel命令。这个命令是异步发出的,而RabbitMQ可能仍然在发送消息,因此消费者在接收到一个Bsaic.CancelOk响应以前,仍然能够接收到来自RabbitMQ的消息。
消费消息时,有几个设置可让RabbitMQ知道你要如何接收它们。其中一个设置是Basic.Consume命令中的no_ack参数。当设置为ture时,RabbitMQ将连续发送消息直到Basic.Cancel或者链接断开。若是no_ack标记为false,则消费者必须经过发送Basic.Ack命令来确认收到的每条消息。
当发送Basic.Ack时,消费者必须在Basic.Deliver方法帧中传递一个名为delivery tag(投递标签)的参数。RabbitMQ使用投递标签和信道做为惟一标识符来实现消息确认、拒绝等操做。