RabbitMQ消息队列高级特性

1.消息的可靠投递

在线上生产环境中,RabbitMQ可能会产生消息丢失或者是投递失败的一个场景,RabbitMQ为了避免这种场景的发生,提供了两种方式来控制消息传递的可靠性。

  • Confirm确认模式
    • 消息从生产者到MQ的Exchange过程中,如果消息成功到达,则会返回一个ConfirmCallback的确认函数。
  • Return退回模式
    • 消息从Exchange到队列的过程中,如果失败了则会返回一个ReturnCallback的函数。

我们可以利用RabbitMQ的两种可靠性投递模式分析产生失败的原因,从业务逻辑上解决问题。

2.ConSumer ACK消费者确认接收消息

ConSumer ACK是指消费方接收到消息数据后的确认方式,消费者从MQ中读取到消息数据后,需要返回一个确认接收的动作。

确认有三种方式:

  • 自动确认
    • acknowledge=“none”
    • 自动确认是指当接收消息后,程序自动向MQ回应消息已经收到,MQ在队列中将消费的数据删除。
  • 手动确认
    • acknowledge=“manual”
    • 收到消息后,程序需要收到确认消息有没有收到,收到调用代码进行查阅,当接收没有问题回应MQ消息已经收到。
  • 根据异常情况确认
    • acknowledge=“auto”
    • 需要根据不同的场景定义不通的处理方式。

3.消费者限流

消费者限流这个特性是非常有必要的,在前面我们提到过削峰填谷的概念,削峰填谷就是消费者限流的概念。

当系统高并发时,生产者一直在发消息数据,MQ全部存储在队列中,如果消费方没有进行限流的操作,那么大了的消费数据读取可能就会使消费者挂掉,因此就需要对消费方读取消息数据的频次进行限流,例如每秒5千个请求,我们允许消费者每秒从MQ中读取一千个请求,至少不会使消费者由于压力巨大而崩溃。

另外当消费方挂掉后,MQ中堆积了大量请求,如果没有限流,一下都让消费者读取,消费者还会挂掉。

4.TTL过期时间

RabbitMQ中可以对消息数据设置TTL过期时间,当消息达到过期时间后,还没有被消费者读取,MQ就会自动将消息进行清除。

RabbitMQ可以对消息设置过期时间,也可以对整个队列设置过期时间。

一个典型的应用场景:订单系统为生产者,用户下单后发送一条消息到MQ消息队列,MQ对这条消息的过期时间为30分钟,如果用户在30分内没有下单,就会被取消订单。

5.死信队列

死信队列在任何MQ消息队列中间件中都有这个概念,在RabbitMQ中私信队列简称为DLX(Dead Letter Exchange)死信交换机,RabbitMQ与其他的MQ中间件不同,RabbitMQ有Exchange交换机的概念,因此死信队列在RabbitMQ中也被成为死信交换机。

在没有Exchange交换机概念的MQ消息队列中,通常就被成为死信队列Dead Letter Queue。

什么是死信队列?当有消息数据成为死信消息时,消息所在的队列会将消息传递到DLX死信交换机上,由死信交换机再将消息数据存放在死信交换机,等待消费者读取数据。

消息成为死信的情况:

  • 队列中存储的消息太多,无法再写入新的消息时,新消息就会成为死信消息。
  • 消费者拒绝读取队列中的消息,并且不把消息重新放到原来所在的队列中,此时消息也会成为死信消息。
  • 队列中的消息设置了过期时间,消息到达过期时间后没有被消费者消费,此时消息也会成为死信消息。

死信队列的典型应用场景:当消息设置了TTL过期时间,超过过期时间后消息数据没有被消费,此时消息成为了死信消息,消息所在的队列会将消息传递给DLX死信交换机,再由死信交换机将数据写入到死信队列中,等待消费者读取数据。

image-20220309134302019

队列如何绑定死信交换机:

需要给队列设置绑定参数,才可以绑定死信交换机,设置x-dead-letter-exchange(死信交换机名称)和 x-dead-letter-routeing-key(死信交换机的routeingkey)

当有消息成为死信消息后,队列会根据死信交换机的名称以及消息中指定的死信交换机routeingkey,将死信消息传递给死信交换机,死信交换在通过死信队列的routeingkey,将消息数据写入到死信队列。

image-20220309140308465

6.延迟队列

**延迟队列:**消息进入队列后不会立即被消费,当到达指定时间后,才可以被消费。

延迟队列的典型应用场景:

  • 电商订单系统,用户拍了一件商品,处于待付款的状态,但是库存系统的数量会发生改变,业务逻辑上会给用户30分钟的付款时间,如果30分钟内完成支付了则流程结束,若30分钟内没有支付则会取消订单,并且通过程序代码回滚库存的数量。
  • 定期发生短信给用户,例如当用户注册满7天后,发生一条问候短信,7天这个时间段就可以在MQ的延迟队列里进行设置,7天后调用消费者发生短信。

image-20220309143708634

以上两种常见的场景都是要求消费者一段时间后再对数据进行处理,实现该需求的方式有以下两种。

  • 定时器
    • 通过在程序里面设置一个定时器,30分钟后在将消息数据传递给库存系统,但是多多少少会存在误差,如果按分钟级的定时器,那么至少会存在1分钟的误差,程序会比对订单表中的时间与当前时间,计算出差值,如果按秒级定时器,那么对于数据库的压力是非常大的,不推荐使用定时器方式。
  • 延迟队列
    • 通过MQ的延迟队列,当发布者将数据写入到队列后,设置30分钟的延迟,消费者再30分钟后读取消息数据,基本上不存在误差,并且只读取一次数据库表的时间进行比对,方式比较优雅。

虽然延迟队列的功能很好用,但是RabbitMQ并没有延迟队列的功能,不过我们可以通过TTL+死信队列的方式实现延迟队列的功能。

TTL+死信队列实现延迟队列

用户在订单系统下单后,会发送一条消息数据到RabbitMQ的Exchange交换机,Exchange交换机将数据写入到队列中,这个队列设置TTL过期时间为30分钟,并且不允许消费者读取数据,30分钟后消息成为死信消息,此时队列将死信消息发送到DLX死信交换机,死信交换机再将消息数据传递给死信队列,然后由消费者从死信队列中读取数据并进行处理。

image-20220309144512530

7.日志与监控

RabbitMQ的日志存放在/var/log/rabbitmq/[email protected]中,xxx表示主机名。

日志中包含了RabbitMQ的版本号、Erlang版本号、RabbitMQ服务节点名称、Cookie的hash值、RabbitMQ配置文件地址、内存限制、磁盘限制、默认账户guest的创建已经权限配置。

在Web控制台中有很多RabbitMQ的监控信息。

RabbitMQ常用命令

rabbitmqctl list_queues					//查看队列
rabbitmqctl environment					//查看环境变量
rabbitmqctl list_exchanges				//查看exchange
rabbitmqctl list_queues aa messages_unacknowledged					//查看未被确认的队列
rabbitmqctl list_users					//查看用户
rabbitmqctl list_queues name memory				//查看单个队列的内存使用
rabbitmqctl list_connections					//查看链接
rabbitmqctl list_queues name messages_ready					//查看准备就绪的队列
rabbitmqctl list_consumers				//查看消费者信息

8.消息追踪

在使用任何消息中间件的过程中,难免会出现某条消息异常丢失的情况。对于RabbitMQ而言,可能是因为生产者或消费者与RabbitMQ断开了连接,而它们与RabbitMQ丈采用了不同的确认机制;也有可能是因为交换器与队列之间不同的转发策略;甚至是交换器并没有与任何队列进行绑定,生产者又不感知或者没有采取相应的措施;另外RabbitMQ本身的集群策略也可能导致消息的丢失。这个时候就需要有一个较好的机制跟踪记录消息的投递过程,以此协助开发和运维人员进行问题的定位。
在RabbitMQ中可以使用Firehose和rabbitmq_tracing插件功能来实现消息追踪。

trace交换机默认自带,需要开启才可以使用:rabbitmqctl trace_on

image-20220309153318432

猜你喜欢

转载自blog.csdn.net/weixin_44953658/article/details/131397538