RabbitMQ学习笔记之入门篇
基本概念
先看个图直观感受下:
Broker
RabbitMQ的服务节点或者服务实例。
Exchange
交换器。生产者将消息发送到交换器,由交换器将消息路由到一个或者多个队列中。如果路由不到,或许会返回给生产者,或许直接丢弃,这要看怎么配置。
交换器类型
fanout
它会把所有发送到该交换器的消息路由到所有与该交换器绑定的队列中
direct
它会把消息路由到那些BindingKey和RoutingKey完全匹配的队列中
topic
支持模糊匹配BindingKey和RoutingKey。他约定:
- RoutingKey为一个点号“.”分割的字符串(被点号“.”分割开的每一段独立额字符串称为一个单词),如“com.rabbitmq.client”;
- BindingKey和RoutingKey一样也是点号"."分隔的字符串;
- BindingKey中可以存在两种特殊字符串“*”和“#”,用于模糊匹配,其中“*”用于匹配一个单词,“#”用于匹配多规格单词(可以是零个)。
示例如下:
— 路由键为“com.rabbitmq.client”的消息会同时路由到Queue1和Queue2;
— 路由键为“com.hidden.client”的消息只会路由到Queue2中;
— 路由键为“com.hidden.demo”的消息只会路由到Queue2;
— 路由键为“java.rabbitmq.demo”的消息只会路由到Queue1中;
— 路由键为“java.util.concurrent”的消息将会被丢弃或者返回给生产者(需要设置mandatory参数),因为它没有匹配到任何路由键。
headers
这种类型的交换器不依赖于路由键的匹配规则来路由消息,而是根据发送的消息内容中的header属性进行匹配,在绑定队列和交换器时制定一组键值对,当发送消息到交换器时,RabbitMQ会获取到该消息的header(也是一个键值对的形式),对比其中的键值对是否是完全匹配队列和交换器绑定时指定的键值对,如果完全匹配则消息会路由到该队列,否则不会。header类型的交换器性能很差,而且不实用,基本上看不到它的存在。
Queue
队列,是RabbitMQ的内部对象,用于存储消息。多个消费者可以订阅同一个队列,这时队列中的消息会被平均分摊(Round-Robin,即轮询)给多个消费者进行处理,而不是每个消费者都收到所有的消息。RabbitMQ不支持队列层面的广播消费。
RoutingKey
路由键。生产者将消息发给交换器的时候,一般会指定一个路由键,用来指定这个消息的路由规则,而这个路由键需要与交换器类型以及绑定键(BindingKey)结合使用才能最终生效。
BindingKey
绑定键。RabbitMQ中通过绑定将交换器与队列关联起来,在绑定的时候一般会指定一个绑定键,这样RabbitMQ就知道如何正确的将消息路由到队列了。
Producer
生产者,就是投递消息的一方。
Consumer
消费者,就是收消息的一方。
运转流程
初始状态下,生产者发送消息的时候:
- 生产者连接到RabbitMQ Broker,建立一个连接(Connection),开启一个信道(Channel);
- 生产者声明一个交换器,并设置相关属性,比如交换器类型、是否持久化等;
- 生产者声明一个队列并设置相关属性,比如是否排他、是否持久化、是否自动删除等;
- 生产者通过绑定键将交换器和队列绑定起来;
- 生产者发送消息至RabbitMQ Broker,其中包含路由键、交换器等信息;
- 相应的交换器根据接收到的路由键查找相匹配的队列;
- 如果找到,则将从生产者发送过来的消息存入相应的队列找;
- 如果没有找到,则根据生产者配置的属性选择丢弃还是回退消息给生产者;
- 关闭信道;
- 关闭连接。
消费者接收消息的过程:
- 消费者连接到RabbitMQ Broker,建立一个连接,开启一个信道;
- 消费者向RabbitMQ Broker请求消费相应队列中的消息,可能会设置相应的回调函数,以及做一些准备工作;
- 等待RabbitMQ Broker回应并投递相应队列中的消息,消费者接收消息;
- 消费者确认(ack)接收到的消息;
- RabbitMQ 从队列中删除相应已被确认的消息;
- 关闭信道;
- 关闭连接。
消费端的确认与拒绝
为了保证消息从队列可靠地到达消费者,RabbitMQ提供了消息确认机制。消费者在订阅队列时,可以指定autoAck参数,当autoAck等于false时,RabbitMQ会等待消费者显式地回复确认信号后才从内存(或磁盘)中移去消息(实质上是先打上删除标记,之后再删除)。当autoAck等于true时,RabbitMQ会自动把发送出去的消息置为确认,然后从内存(或磁盘)中删除,而不管消费者是否真正地消费到了这些消息。
当autoAck参数置为false,对于RabbitMQ服务端而言,队列中的消息分成了两个部分:一部分是等待投递给消费者的消息;一部分是已经投递给消费者,但是还没有收到消费者确认信号的消息。如果RabbitMQ一直没有收到消费者的确认信号,并且消费此消息的消费者已经断开连接,则RabbitMQ会安排该消息重新进入队列,等待投递给下一个消费者,当然也有可能还是原来那个消费者(ps:原来的消费者重连)。
参考资料
- 朱忠华《RabbitMQ实战指南》