RabbitMQ 是由
Erlang
语言开发,基于 AMQP(Advanced Message Queue 高级消息队列协议)协议实现的消息队列。
基本概念
Producer:
消息的生产者,是一个向交换机发布消息的客户端应用程序。
Connection:
生产者/消费者和 RabbitMQ 服务器之间建立的 TCP 连接。
Channel:
TCP 里面的虚拟连接。
- Connection 相当于电缆,Channel 相当于独立光纤束,一条 TCP 连接中可以创建多条信道,增加连接效率。
- 无论是发布消息、接收消息、订阅队列都是通过信道完成的。
为什么使用信道而不直接使用 TCP 连接通信?
- TCP 连接的创建和销毁开销特别大,创建需要 3 次握手,销毁需要 4 次挥手。
- 高峰时每秒成千上万条 TCP 连接的创建会造成资源巨大的浪费。
- 而且操作系统每秒处理 TCP 连接数也是有限制的,会造成性能瓶颈。
- 而如果一条线程使用一条信道,一条 TCP 链接可以容纳无限的信道,即使每秒成千上万的请求也不会成为性能的瓶颈。
Broker:
消息队列服务器实体,即 RabbitMQ 服务器。
Virtual Host:
虚拟主机,每个 Virtual Host 本质上就是一个 mini 版的 RabbitMQ 服务器,拥有自己的队列、交换机、绑定和权限机制。
当多个不同的用户使用同一个 RabbitMQ 服务器时,可以划分出多个虚拟主机。
- RabbitMQ 默认的虚拟主机路径是 /
Exchange:
交换机,用来接收生产者发送的消息,并根据分发规则,将这些消息分发给服务器中的队列中。
不同的交换机有不同的分发规则。
交换机类型有4种:
direct(直连):
- 它会把消息路由到那些
BindingKey RoutingKey
完全匹配的队列中。fanout(扇形):
- 它会把所有发送到该交换器的消息路由到所有与该交换器绑定的队列中。
topic(主题):
- 将消息路由到 BindingKey RoutingKey 相匹配的队列中。
headers(标题):
- 交换器不依赖于路由键的匹配规则来路由消息,而是根据发送的消息内容中 headers 属性进行匹配。
直连交换机(dirext exchange)为 RabbitMQ 默认的交换机。
Queue:
消息队列,用来保存消息直到发送给消费者。
它是消息的容器,也是消息的终点,消息一直在队列里面,等待消费者链接到这个队列将其取走。
Binding:
消息队列和交换机之间的虚拟连接,绑定中包含路由规则,绑定信息保存到交换机的路由表中,作为消息的分发依据。
Consumer:
消息的消费者,表示一个从消息队列中取得消息的客户端应用程序。
死信队列
当消息在队列中由于某些原因没有被及时消费而变成死信(Dead Message)后,消息中间件可以将其从当前队列发送到另一个队列中,这个队列就是死信队列。
在 RabbitMQ 中,由于有交换机的概念,实际是将死信发送给了死信交换机(Dead Letter Exchange,简称DLX)。
死信交换机 和 死信队列与普通的没有区别。
- 死信队列只是一种特殊的队列,里面的消息仍然可以消费。
消息成为死信的情况:
队列消息长度到达限制
消费者拒签消息,并且不把消息重新放入原队列
消息到达存活时间未被消费
延迟队列
延迟队列,即消息进入队列后不会立即被消费,只有到达指定时间后,才会被消费。
但 RabbitMQ 中并未提供延迟队列功能,可以使用死信队列实现延迟队列的效果。
- 延迟队列:TTL + 死信队列的合体。
工作模式
简单模式
一个生产者对应一个消费者,通过队列进行消息传递。
该模式使用 direct 交换机,direct 交换机是 RabbitMQ 默认交换机。
工作队列模式
与简单模式相比,工作队列模式(Work Queue)多了一些消费者。
该模式也使用 direct 交换机,应用于处理消息较多的情况。
特点如下:
- 一个队列对应多个消费者。
- 一条消息只会被一个消费者消费。
- 消息队列默认采用 轮询 的方式将消息平均发送给消费者。
发布订阅模式
在开发过程中,有一些消息需要不同消费者进行不同的处理,如电商网站的同一条促销信息需要短信发送、邮件发送、站内信发送等。
此时可以使用发布订阅模式(Publish/Subscribe)。
特点如下:
生产者将消息发送给交换机,交换机将消息转发到绑定此交换机的 每个队列 中。
工作队列模式的交换机只能将消息发送给一个队列,发布订阅模式的交换机能将消息发送给多个队列。
发布订阅模式使用 fanout 交换机。
路由模式
使用发布订阅模式时,所有消息都会发送到绑定的队列中,但很多时候,不是所有消息都无差别的发布到所有队列中。
比如电商网站的促销活动,618大促可能会发布到所有队列。
而一些小的促销活动为了节约成本,只发布到站内信队列。
此时需要使用 路由模式 (Routing)完成这一需求。
特点如下:
每个队列绑定路由关键字 RoutingKey。
生产者将带有 RoutingKey 的消息发送给交换机,交换机根据 RoutingKey 转发到指定队列。
路由模式使用 direct 交换机。
能按照路由键将消息发送给指定队列。
通配符模式
通配符模式(Topics)是在路由模式的基础上,给队列绑定带通配符的路由关键字,只要消息的 RoutingKey 能实现通配符匹配,就会将消息转发到该队列。
通配符模式比路由模式更灵活,通配符模式使用 topic 交换机。
能按照通配符规则将消息发送给指定队列。
通配符规则如下:
队列设置 RoutingKey 时,
#
可以匹配任意多个单词,*
可以匹配任意一个单词。消息设置 RoutingKey 时,RoutingKey 由多个单词构成,中间以
.
分割。
基本原理
消息的可靠性投递
RabbitMQ 消息的投递路径为:
- 生产者 ------> 交换机 ------> 队列 ------> 消费者
在 RabbitMQ 工作的过程中,每个环节消息都有可能传递失败,可以通过以下三种模式来监听消息时候投递成功:
确认模式(Confirm):可以监听消息是否从生产者成功传递到交换机。
退回模式(Return):可以监听消息是否从交换机成功传递到队列。
消费者消息确认(Consumer Ack):可以监听消费者是否成功处理消息。
高级特性
消费端限流
RabbitMQ 提供了一种 Qos(Quality Of Service,服务质量)服务质量保证功能。
即在非自动确认消息的前提下,如果一定数目的消息未被确认之前,不再进行消费新的消息。
通过消费端限流的方式限制消息的拉取速度,达到保护消费端的目的。
不公平分发
在 RabbitMQ 中,多个消费者监听同一条队列,则队列默认采用的轮询分发。
但是在某种场景下这种策略并不是很好,例如消费者1 处理任务的速度非常快,而其他消费者处理速度却很慢。
- 此时如果采用公平分发,则消费者1 有很大一部分时间处于空闲状态。
- 此时可以采用不公平分发,即谁处理的快,谁处理的消息多。
消息存活时间
可以设置消息的存活时间(Time To Live,简称TTL),单位是毫秒,当消息到达存活时间后还没有被消费,会被移出队列。
RabbitMQ 可以对队列的所有消息设置存活时间,也可以对某条消息设置存活时间。
- 消息到达存活时间未被消费时,消息会被放入死信队列。
优先级队列
RabbitMQ 优先级队列(Priority Queue)是一种特殊的队列,它根据消息的优先级将其放置在队列中。
当消费者从队列中获取消息时,它将按照优先级从高到低的顺序获取消息。
优先级队列可以用于处理一些需要按照优先级处理的消息,例如日志记录、任务调度等。