AMQP消息通讯的理解

  • 作者:未知
  • 来源:
  • 2018-04-26 18:18:52

1.消费者和生产者     生产者(producer)创建消息,然后发布到代理服务器(RabbitMQ)。消息包含两部分内容:有效载荷(payload)和标签(label)。有效载荷就是想要传输的数据。标签用于描述有效载荷,并且RabbitMQ用它来决...

1.消费者和生产者

生产者(producer)创建消息,然后发布到代理服务器(RabbitMQ)。消息包含两部分内容:有效载荷(payload)和标签(label)。有效载荷就是想要传输的数据。标签用于描述有效载荷,并且RabbitMQ用它来决定谁将获得消息的拷贝。举例来说,不同于TCP协议的是,当你明确指定发送方和接收方,AMQP只会用标签表示这条消息(一个交换器的名称和可选的主题标记),然后把消息交由RabbitMQ,RabbitMQ会根据标签把消息发送给感兴趣的接收方。这种通讯方式是一种“发后忘却”(fire-and-forget)的单向方式。

20140308164024_2956.jpg

消费者连接到代理服务器,并订阅到队列(queue)上。可以把消息队列想象撑一个具名邮箱。每当消息到达特定的邮箱时,RabbitMQ会将其发送给起重一个订阅的/监听的消费者。当消费者接收到消息时,它只会获得有效载荷。在消息路由过程中,消息的标签并没有随有效载荷一同传递。RabbitMQ甚至不会告诉你是谁产生/发送了消息。就好比收到快递时,寄件人是空白的。

发送与接收的整个过程其实很简单:生产者创建信息,消费者接收信息。不过再次之前,必须创建一条信道(channel)。

2.信道

在应用程序和Rabbit代理服务器之间创建一条TCP连接。一旦TCP连接打开(通过了认证),应用程序就可以创建一条AMQP信道。信道是建立在“真实的”TCP连接内的虚拟连接。AMQP命令都是通过信道发送出去的。每条信道都会被指派一个唯一ID。不论是发布消息、订阅队列或是接收消息,这些动作都是通过信道完成的。

为什么不直接通过TCP连接发送AMQP命令呢?主要原因在于对操作系统来说,建立和销毁TCP会话是非常昂贵的开销。假设在高峰期,会有成百上千的连接,这样会造成TCP连接的巨大浪费,操作系统每秒也就只能建立这点数量的连接。因此,可能很快就碰到性能瓶颈了。在一条TCP连接上,创建多少条信道是没有限制的。

3.AMQP消息路由的组成

AMQP消息路由必须有三个部分:交换器、队列和绑定。

队列就如同具名邮箱,消息最终达到队列中并等待消费。消费者通过consume或者get来从特定的队列中接收消息:

consume用来订阅命令。这样做会将信道设置为接收模式,直到取消对队列的订阅为止。

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)队列,它用来存放那些被拒绝而不重新入队列的消息。

4.交换器与绑定

当你想把消息投到队列时,需要把消息发送给交换器来完成。然后,根据确定的规则,RabbitMQ会决定消息该投递给哪个队列。这些规则被称为路由键(routing key)。队列通过路由键绑定到交换器。当你把消息发送到代理服务器时,消息将拥有一个路由键,即使是空的。RabbitMQ也会将其和绑定使用的路由键进行匹配。

一共有四种类型是交换器:direct、fanout、topic和headers。其中headers允许匹配AMQP消息的header而非路由,其余的和direct完全一致。

direct非常简单,如果路由键匹配的话,消息就被投递到对应的队列。

fanout会将收到的消息广播到绑定的队列上。

topic允许来自不同源头的消息达到同一个队列。例如,可以使用log.*这种表达式发送队列。

以上三种交换器与绑定方式,将在后面使用代码进行实现。

5.虚拟主机与隔离

每一个RabbitMQ服务器都能创建虚拟消息服务器(vhost),每一个vhost本质上是一个mini的RabbitMQ服务器,拥有自己的队列、交换器和绑定,还有自己的权限机制。

由于RabbitMQ包含了开箱即用的默认vhost:"/",因此使用起来非常简单。vhost之间是绝对隔离的。

  • 相关专题

免责声明:本文内容由互联网用户自发贡献自行上传,本网站不拥有所有权,也不承认相关法律责任。如果您发现本社区中有涉嫌抄袭的内容,请发送邮件至:operations@xinnet.com进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。

免费咨询获取折扣