工作原理:
RabbitMQ 有 4 个组件:生产者、Exchange、queue 队列、消费者。当生产者发出一条消息时,先经过 Exchange,由 Exchange 转发给队列,然后由消费者进行消费。
系统架构
Rabbitmq 系统最核心的组件是 Exchange 和 Queue,下图是系统简单的示意图。Exchange 和 Queue 是在服务(又叫做 broker)端,producer 和 consumer 在应用端。
producer&Consumer
producer 指的是消息生产者,consumer 消息的消费者。
Queue
消息队列,提供了 FIFO 的处理机制,具有缓存消息的能力。rabbitmq 中,队列消息可以设置为持久化,临时或者自动删除。
- 设置为持久化的队列,queue 中的消息会在 server 本地硬盘存储一份,防止系统 crash,数据丢失
- 设置为临时队列,queue 中的数据在系统重启之后就会丢失
- 设置为自动删除的队列,当不存在用户连接到 server,队列中的数据会被自动删除
Exchange
Exchange 类似于数据通信网络中的交换机,提供消息路由策略。rabbitmq 中,producer 不是通过信道直接将消息发送给 queue,而是先发送给 Exchange。一个 Exchange 可以和多个 Queue 进行绑定,producer 在传递消息的时候,会传递一个 ROUTING_KEY,Exchange 会根据这个 ROUTING_KEY 按照特定的路由算法,将消息路由转发给匹配的 queue。和 Queue 一样,Exchange 也可设置为持久化,临时或者自动删除。
Exchange 有 4 种类型:direct (默认),fanout, topic, 和 headers,不同类型的 Exchange 转发消息的策略有所区别:
- Direct
直接交换器,工作方式类似于单播,Exchange 会将消息发送完全匹配 ROUTING_KEY 的 Queue - fanout
广播式交换器,不管消息的 ROUTING_KEY 设置为什么,Exchange 都会将消息转发给所有绑定的 Queue。 - topic
主题交换器,工作方式类似于组播,Exchange 会将消息转发和 ROUTING_KEY 匹配模式相同的所有队列,比如,ROUTING_KEY 为 user.stock 的 Message 会转发给绑定匹配模式为 * .stock,user.stock, * . * 和 #.user.stock.# 的队列。( * 表是匹配一个任意词组,# 表示匹配 0 个或多个词组) - headers
消息体的 header 匹配(几乎不用,可以忽视)
Binding
所谓绑定就是将一个特定的 Exchange 和一个特定的 Queue 绑定起来。Exchange 和 Queue 的绑定可以是多对多的关系。
virtual host
在 rabbitmq server 上可以创建多个虚拟的 message broker,又叫做 virtual hosts (vhosts)。每一个 vhost 本质上是一个 mini-rabbitmq server,分别管理各自的 exchange,和 bindings。vhost 相当于物理的 server,可以为不同 app 提供边界隔离,使得应用安全的运行在不同的 vhost 实例上,相互之间不会干扰。producer 和 consumer 连接 rabbit server 需要指定一个 vhost。
通信过程
假设 P1 和 C1 注册了相同的 Broker,Exchange 和 Queue。P1 发送的消息最终会被 C1 消费。基本的通信流程大概如下所示:
- P1 生产消息,发送给服务器端的 Exchange
- Exchange 收到消息,根据 ROUTINKEY,将消息转发给匹配的 Queue1
- Queue1 收到消息,将消息发送给订阅者 C1
- C1 收到消息,发送 ACK 给队列确认收到消息
- Queue1 收到 ACK,删除队列中缓存的此条消息
Consumer 收到消息时需要显式的向 rabbit broker 发送 basic.ack 消息或者 consumer 订阅消息时设置 auto_ack 参数为 true。在通信过程中,队列对 ACK 的处理有以下几种情况:
- 如果 consumer 接收了消息,发送 ack,rabbitmq 会删除队列中这个消息,发送另一条消息给 consumer。
- 如果 cosumer 接受了消息,但在发送 ack 之前断开连接,rabbitmq 会认为这条消息没有被 deliver(交付), 在 consumer 在次连接的时候,这条消息会被 redeliver。
- 如果 consumer 接受了消息,但是程序中有 bug, 忘记了 ack,rabbitmq 不会重复发送消息。
- rabbitmq2.0.0 和之后的版本支持 consumer reject 某条(类)消息,可以通过设置 requeue 参数中的 reject 为 true 达到目地,那么 rabbitmq 将会把消息发送给下一个注册的 consumer。