RabbitMQ: 消息通信

消息

生产者

生产者 producer 创建消息,然后发布到代理服务器 RabbitMQ,消息包括两部分:有效载荷(Payload)和标签(Label)。

Payload: 要传输的数据。
Label: 描述了有效载荷,RabbitMQ根据 Label 来决定谁将获得消息的拷贝,是一种“发后即忘(fire-and-forget)”的单向方式。

消费者

消费者 consumer 连接到代理服务器上,并订阅到队列 queue 上,RabbitMQ 会将其订阅的消息发送给 consumer。

当消费者 consumer 接收到消息时,只得到消息的一部分有效载荷 payload,如果 consumer 想知道是谁生产的消息取决于 producer 是否将发送方信息放入到 payload 中。

信道

信道(Channel): 是建立在 TCP 连接内的虚拟连接,AMQP 命令都是通过信道发送的,每条信道会被指派唯一 ID。

对于操作系统来说,建立和销毁 TCP 连接发送命令的开销非常昂贵,而且操作系统每秒能建立的连接数量有限。所有线程只使用一条 TCP 连接,同时信道可以保证每个线程的私密性,而且在一条 TCP 连接上创建信道的数量是没有限制的,这就解决了性能瓶颈。

队列

消费者通过两种方式从特定的队列接收消息:basic.consumebasic.get

  • 通过basic.consume命令订阅,消费者能在最近接收的那条消息后,自动从队列接收下一条消息。
  • 通过basic.get可以从队列获得单条消息而不是持续订阅。

当队列有多个消费者时,队列收到的消息将会以循环(round-robin)的方式发送给消费者,每条消息只会发送给一个订阅者。

消费者 consumer 接收的每条消息都必须进行确认,要么显示的向 RabbitMQ 发送basic.ack命令,要么在订阅到队列的时候将auto_ack设置为true,使得消费者一旦接收了消息 RabbitMQ 自动视其确认了消息。

交换器和绑定

队列通过路由键(routing key)绑定到交换器。

交换器和绑定:可以满足更多复杂的场景,利于发布/订阅和多播,发送消息给服务器的发布者不需要关系服务器另一端的队列和消费者逻辑。

交换器类型:

  • direct
    路由键匹配的话,消息就投递到相应的队列。
  • fanout
    适合将消息广播到绑定的队列上,允许不同消费者做不同的反应。
  • topic
    使得来自不同源头的消息能够到达同一个队列。
  • headers
    允许匹配消息的 header 而不是路由键,基本和 direct 一样,性能差,几乎不用。

虚拟主机

每个 RabbitMQ 服务器都可以创建虚拟消息服务器,称为虚拟主机 vhost,可拥有自己的权限机制,vhost之间是绝对隔离的。
RabbitMQ包含了一个默认的 vhost: “/“,通过缺省的 guest 用户名和密码 guest 就可以访问默认的 vhost。

在 Rabbit 里创建一个用户时,通过会被指派给至少一个 vhost,并且只能访问被指派 vhost 内的队列、交换器和队列。

vhost 和其权限控制是唯一无法直接通过 AMQP 协议来创建的基元,需要通过安装目录./sbin/下的rabbitmqctl工具来创建。

持久化

每个队列和交换器的durable属性,默认是 false,决定了 RabbitMQ 是否需要在崩溃或重启后重新创建队列/交换器。

消息 想要从 Rabbit 崩溃中恢复的要素:

  • 把消息的投递模式(delievery mode)设置为 2(持久)。
  • 发送到持久化交换器。
  • 到达持久化的队列。

AMQP事务:
AMQP 中,在把信道设置为事务模式后,通过信道发送那些想要确认的消息,之后还有多个其他 AMQP 命令,这些命令是执行还是忽略取决于第一条消息发送是否成功。事务会降低消息吞吐量,使得生产者应用程序产生同步。

发送方确认模式:
更好的保证消息投递,和事务相仿,需要将信道设置为confirm模式。
一旦消息被投递到所匹配的队列后,信道会发送一个发送方确认模式给省城镇应用程序。
发送方确认模式最大的好处是异步的,由于没有消息回滚的概念,发送方确认模式更加轻量级,对性能几乎没有影响。