RabbitMQ的工作原理
基本概念
- Broker:RabbitMQ消息中间件的服务节点,主要负责消息的存储和转发。
- Exchange(交换机):用于接收来自生产者的消息,并将其路由到队列。 Exchange必须确保消息发送到一个或多个队列,这是通过绑定到Exchange的队列列表来实现的。Exchange有不同的类型(如Direct、Fanout、Topic、Headers),每种类型都有不同的路由规则,可以根据不同的需求进行选择。
- Binding(绑定):用于连接Exchange和Queue。 Binding规定了Exchange将消息路由到哪些队列中,以及如何路由到这些队列中。
- Queue(队列):用于存储消息的缓冲区。生产者向队列发送消息,而消费者从队列中接收消息。队列有许多不同的属性,例如消息过期时间、消息优先级等。
- Virtual Host(虚拟主机):用于在单个RabbitMQ服务器中创建多个独立的消息系统。每个虚拟主机都有自己的队列、交换机和绑定,可以使不同的应用程序在相同的RabbitMQ服务器上独立运行。
- Connection(连接):生产者和消费者与RabbitMQ Broker之间的TCP连接。每个连接都有一个唯一的标识符,可以用于标识客户端和服务器之间的通信通道。
- Channel(通道):在连接中创建的虚拟连接,用于实现复用TCP连接,可以在一个连接中创建多个通道,每个通道可以进行不同的数据流传输。通道也可以用于实现不同的QoS(Quality of Service)机制,例如确认模式、事务模式等。
- Publisher(生产者):发送消息到Exchange的客户端。
- Consumer(消费者):从队列中接收消息的客户端。
- Acknowledgment(确认):消费者在处理完消息后向Broker发送的确认信息。确认可以在多种模式下实现,例如自动确认、手动确认等。
- Routing Key(路由键):用于将消息路由到特定的Exchange和Queue。在Direct和Topic类型的Exchange中使用Routing Key。
- Message(消息):生产者发送到Exchange的基本信息单元,包含消息体和元数据。元数据包括Routing Key、Headers、Priority等。
- Dead Letter Exchange(死信交换机):用于处理未能成功投递的消息。当消息无法路由到目标队列时,可以将其发送到死信交换机,由死信交换机将其重新路由到另一个队列。
Routing Key & Binding key
绑定键(Binding Key)和路由键(Routing Key)是两个不同的概念。
- 绑定键(Binding Key)是在交换机和队列之间建立绑定关系时指定的。绑定关系存储在 RabbitMQ 服务器上,通常由管理员在 RabbitMQ 控制台或通过 RabbitMQ 命令行管理工具定义。
- 路由键(Routing Key)是消息发送者在将消息发送到交换机时指定的。路由键存储在消息的消息头中。
路由键是消息发布者在发送消息时指定的一个字符串,用于描述这条消息的路由规则,交换机根据路由键来将消息路由到绑定键和路由键相匹配的队列中。
绑定键是消费者在绑定队列和交换机时指定的一个字符串,用于描述消费者所需接收的消息的路由规则,绑定键和交换机的绑定关系决定了交换机将消息路由到哪些队列中。
换句话说,路由键是消息的属性,用于决定消息被路由到哪个队列,而绑定键是队列的属性,用于告诉交换机应该将消息发送到哪个队列中。
在 Topic Exchange 中,绑定键和路由键都可以使用通配符进行匹配,这是 Topic Exchange 的一个特性,可以实现更加灵活的路由规则。
交换机类型
在 RabbitMQ 中,有四种不同类型的交换机,分别是:Direct、Fanout、Topic 和 Headers。每种交换机类型的路由规则不同,用于不同的场景。
- Direct Exchange(直接交换机):
Direct Exchange 是 RabbitMQ 的默认交换机,它会把消息发送到与 Routing Key 完全匹配的队列中。Direct Exchange 只会把消息发送到一个队列中,无论该队列有多少个消费者。
- Fanout Exchange(扇形交换机):
Fanout Exchange 会把消息发送到所有与该 Exchange 绑定的队列中,不需要使用 Routing Key。该类型的交换机通常用于广播消息。
- Topic Exchange(主题交换机):
Topic Exchange 会把消息发送到与 Routing Key 模式匹配的队列中。Routing Key 由单词和句点组成,其中星号匹配单个单词,井号匹配零个或多个单词。
在 Topic Exchange 中,消息的路由规则使用一种通配符的方式来实现。通配符由单词和星号(*)和井号(#)组成,其中单词之间使用点号(.)进行分隔。
通配符 * 匹配单个单词,例如 routingKey.* 将会匹配到 routingKey.abc、routingKey.xyz,但不匹配 routingKey.abc.xyz。
通配符 # 匹配多个单词,例如 routingKey.# 将会匹配到 routingKey.abc、routingKey.xyz 和 routingKey.abc.xyz 等任何以 routingKey 开头的路由键。
通过将消息发送到特定的路由键上,可以将消息路由到相应的队列中。当一个队列绑定到交换机上时,必须指定一个路由键 routing key。消息的路由键需要和绑定时指定的路由键匹配才能被该队列接收。
举个例子,如果有两个队列,分别绑定到一个 Topic Exchange 上,其中一个队列绑定的路由键为 "com.rabbitmq.client",另一个队列绑定的路由键为 "com.rabbitmq",当发送一条路由键为 "com.rabbitmq.client.example" 的消息时,只有第一个队列会收到该消息。
需要注意的是,主题交换机不会缓存消息,一旦消息被投递到相应队列中,它就从主题交换机中移除。如果没有任何队列与路由键匹配,那么该消息将被丢弃。因此在使用 Topic Exchange 时需要确保至少有一个队列与消息的路由键匹配,否则消息将会丢失。
- Headers Exchange(头交换机):
Headers Exchange 会根据消息头中的键值对进行匹配,而不是 Routing Key。消息头可以包含任意的键值对,这使得 Headers Exchange 可以灵活地路由消息,但是由于性能的原因,Headers Exchange 不如其他类型的交换机常用。
需要注意的是,队列只能与一个交换机绑定。如果需要将一个队列绑定到多个交换机上,需要分别创建多个队列。
-----服务启动-----
- 启动Broker中的RabbitMQ程序,包括消息队列、交换机、绑定关系等。
- 通过RabbitMQ的管理工具创建Exchange和Queue,建立绑定关系。
- 启动生产者和消费者客户端。
-----发送消息-----
- 生产者和Broker建立TCP连接。
- 生产者和Broker建立Channel通道。
- 生产者将消息发送给Exchange交换机。
- Exchange根据路由键将消息路由到一个或多个队列中。
- 队列将消息保存在其中,等待消费者处理。
-----接收消息-----
- 消费者和Broker建立TCP连接。
- 消费者和Broker建立Channel通道。
- 消费者向RabbitMQ发送消费请求。
- RabbitMQ将等待中的消息推送给消费者。
- 消费者收到消息并进行处理。
为了确保消息传输的可靠性,RabbitMQ支持以下机制:
- ACK确认机制:消费者从队列中接收消息时,需要向RabbitMQ发送ACK确认消息,表示已成功接收到该消息。如果RabbitMQ在一定时间内没有收到ACK确认消息,则认为该消息未被正确处理,将重新将该消息发送给其他消费者。
- 消息持久化:生产者可以将消息标记为持久化,RabbitMQ会将其保存到磁盘上,以便在重启后能够恢复已经存储的消息。
- 消息重复检测:消费者处理消息时,可以通过消息的唯一标识符来判断该消息是否已经处理过,避免重复处理。
- TTL机制:设置消息的TTL(Time-To-Live)属性,表示该消息在一定时间内未被处理,则自动删除。
- 备份机制:RabbitMQ支持将消息备份到其他节点,以避免因节点故障导致的消息丢失。
为了保证消息传递的顺序性,可以通过以下方式:
- 单一消费者:为了保证消息的顺序性,可以使用单一消费者模式,即每个队列只有一个消费者。
- 分区队列:将一个大的队列拆分成多个分区队列,每个分区队列只有一个消费者,保证分区内消息的顺序性。
- 消息序列化:如果消息本身有序,可以在生产者将消息序列化成二进制数据时,按照特定的顺序进行