生产者(producer)建立消息,而后发布到代理服务器(RabbitMQ)。消息包含两部份内容:有效载荷(payload)和标签(label)。有效载荷就是想要传输的数据。标签用于描述有效载荷,而且RabbitMQ用它来决定谁将得到消息的拷贝。举例来讲,不一样于TCP协议的是,当你明确指定发送方和接收方,AMQP只会用标签表示这条消息(一个交换器的名称和可选的主题标记),而后把消息交由RabbitMQ,RabbitMQ会根据标签把消息发送给感兴趣的接收方。这种通信方式是一种“发后忘却”(fire-and-forget)的单向方式。安全
消费者链接到代理服务器,并订阅到队列(queue)上。能够把消息队列想象撑一个具名邮箱。每当消息到达特定的邮箱时,RabbitMQ会将其发送给起重一个订阅的/监听的消费者。当消费者接收到消息时,它只会得到有效载荷。在消息路由过程当中,消息的标签并无随有效载荷一同传递。RabbitMQ甚至不会告诉你是谁产生/发送了消息。就比如收到快递时,寄件人是空白的。服务器
发送与接收的整个过程其实很简单:生产者建立信息,消费者接收信息。不过再次以前,必须建立一条信道(channel)。性能
在应用程序和Rabbit代理服务器之间建立一条TCP链接。一旦TCP链接打开(经过了认证),应用程序就能够建立一条AMQP信道。信道是创建在“真实的”TCP链接内的虚拟链接。AMQP命令都是经过信道发送出去的。每条信道都会被指派一个惟一ID。不管是发布消息、订阅队列或是接收消息,这些动做都是经过信道完成的。spa
为何不直接经过TCP链接发送AMQP命令呢?主要缘由在于对操做系统来讲,创建和销毁TCP会话是很是昂贵的开销。假设在高峰期,会有成百上千的链接,这样会形成TCP链接的巨大浪费,操做系统每秒也就只能创建这点数量的链接。所以,可能很快就碰到性能瓶颈了。在一条TCP链接上,建立多少条信道是没有限制的。操作系统
AMQP消息路由必须有三个部分:交换器、队列和绑定。代理
队列就如同具名邮箱,消息最终达到队列中并等待消费。消费者经过consume或者get来从特定的队列中接收消息:队列
consume用来订阅命令。这样作会将信道设置为接收模式,直到取消对队列的订阅为止。路由
get用来向队列请求单条的消息,大体上讲get命令会订阅消息,得到单条消息,而后取消订阅。get
当队列拥有多个消费者时,队列收到的消息将以循环(round-robin)的方式发送给消费者。消费者必须经过ack命令显示地向RabbitMQ发送一个确认,或者在订阅到队列时就将auto_ack设置为true,当设置了auto_ack,一旦消费者接收消息,就会被视为确认了消息。消息队列
注意,消费者接收到了消息,不等于生产者已经知道消息已经被接收了,这两件事毫无关联。所以,消费者经过asc命令告诉RabbitMQ,它已经正确地接收了消息,这样,RabbitMQ才能安全地把消息从队列中删除。
若是消费者收到一条消息,而后在确认以前与RabbitMQ断开了链接,或者从队列上取消订阅,RabbitMQ会认为这条消息没有分发,而后从新分发给下一个订阅的消费者。另外一方面,若是应用程序有bug而忘记确认消息的话,RabbitMQ将不会继续给该消费者发送消息了。
若是你正使用RabbitMQ2.00或者更新的版本,那就可使用reject命令,设置成true的话,RabbitMQ会将消息从新发送给下一个订阅的消费者。若是设置成false的话,RabbitMQ会把消息从队列中移除,而不会把它发送给新的消费者。移除的消息会进入一个特殊的“死信”(dead letter)队列,它用来存放那些被拒绝而不从新入队列的消息。
当你想把消息投到队列时,须要把消息发送给交换器来完成。而后,根据肯定的规则,RabbitMQ会决定消息该投递给哪一个队列。这些规则被称为路由键(routing key)。队列经过路由键绑定到交换器。当你把消息发送到代理服务器时,消息将拥有一个路由键,即便是空的。RabbitMQ也会将其和绑定使用的路由键进行匹配。
一共有四种类型是交换器:direct、fanout、topic和headers。其中headers容许匹配AMQP消息的header而非路由,其他的和direct彻底一致。
direct很是简单,若是路由键匹配的话,消息就被投递到对应的队列。
fanout会将收到的消息广播到绑定的队列上。
topic容许来自不一样源头的消息达到同一个队列。例如,可使用log.*这种表达式发送队列。
以上三种交换器与绑定方式,将在后面使用代码进行实现。
每个RabbitMQ服务器都能建立虚拟消息服务器(vhost),每个vhost本质上是一个mini的RabbitMQ服务器,拥有本身的队列、交换器和绑定,还有本身的权限机制。
因为RabbitMQ包含了开箱即用的默认vhost:"/",所以使用起来很是简单。vhost之间是绝对隔离的。