我们一起来学RabbitMQ 三:RabbiMQ 死信队列,延迟队列,持久化等知识点

咱们今天再来进一步学习一下 RabbitMQ 的知识点,整理了如下相关知识点

  • RabbitMQ 消息流向是如何走的
  • 交换机相关的知识点
  • 队列相关的知识点
  • 死信队列,延迟队列,持久化
  • 队列中传输消息的保障机制有哪些
  • 生产者确认的问题有哪些
  • 消费者消费的模式有哪些

我们一起来学RabbitMQ 三:RabbiMQ 死信队列,延迟队列,持久化等知识点_第1张图片

RabbitMQ 消息流向是如何走的 ?

生产者发送消息的时候

  • 生产者连接到 RabbitMQ Broker,建立一个连接,开启一个信道
  • 生产者声明一个交换机,并设置相关属性,例如交换机类型、是否持久化等
  • 生产者声明一个队列并设置相关属性,例如是否排他、是否持久化、是否自动删除等
  • 生产者通过路由键将交换机和队列绑定起来
  • 生产者发送消息至 RabbitMQ Broker,其中包含路由键、交换机等信息
  • 相应的交换机根据接收到的路由键查找相匹配的队列
  • 如果找到,则从生产者发送过来的消息存入相应的队列中
  • 如果没有找到,则根据生产者配置的属性选择丢弃还是回退给生产者
  • 关闭信号
  • 关闭连接

消费者接收消息的过程

  • 消费者连接到 RabbitMQ Broker,建立一个连接,开启一个信道
  • 消费者向 RabbitMQ Broker请求消费相应队列中的消息,可能会设置相应的回调函数,以及做一些准备工作
  • 等待RabbitMQ Broker回应并投递相应队列中的消息,消费者接收消息
  • 消费者确认接收到的消息
  • RabbitMQ 从队列中删除相应已经被确认的消息
  • 关闭信道
  • 关闭连接

常用的交换机都有哪些?

不同交换机有不同交换机的特性

  • fanout

适合发布订阅式,广播的方式来传递消息

  • direct

适合路由到指定队列的传输消息

  • topic

与上述交换机类似,只是多了通配符

  • headers

会匹配消息的 headers,易用性较差

fanout exchange 可以做成备份的交换机,因为 fanout 的消息是广播的方式

若A生产者A消息发送到A交换机,路由到A队列,若A消息填写的路由 key 与 A队列的绑定 key 不对齐,则会被重新发送到 另外一个备份 fanout 交换机上
  • 如果设置的备份交换机不存在,消息会丢失
  • 如果设置的备份交换机没有绑定任何队列,消息会丢失
  • 如果设置的备份交换机没有任何匹配的队列,消息会丢失

队列相关知识点有哪些?

设置 消息的TTL

  • 通过队列属性x-message-ttl(单位毫秒)设置,队列中所有消息都有相同的过期时间
  • 对消息本身进行单独设置,每条消息的TTL可以不同

若两种方式一起使用,则消息的TTL以两者之间较小的那个数值为准

消息在队列中的生存时间一旦超过设置的TTL值时,就会变成死信,消费者将无法再收到该消息

另外对于TTL 的 2 种情况:

  • 如果不设置 TTL ,则表示此消息不会过期
  • 如果将 TTL 设置为 0,则表示除非此时可以直接将消息投递到消费者,否则该消息会被立即丢弃

我们一起来学RabbitMQ 三:RabbiMQ 死信队列,延迟队列,持久化等知识点_第2张图片

设置队列的 TTL

通过队列属性x-expires可以控制队列被自动删除前处于未使用状态的时间,未使用状态的时间 有如下含义:

  • 队列上没有任何的消费者
  • 队列也没有被重新声明

死信队列是什么

我们一起来学RabbitMQ 三:RabbiMQ 死信队列,延迟队列,持久化等知识点_第3张图片

当消息在一个队列中变成死信之后,它能重新被发送到另一个交换机中,这个交换机就是 死信交换机,绑定死信交换机 的队列就称之为死信队列

消息变成死信有这几种情况:

  • 消息被拒绝了
  • 消息过期了
  • 队列达到了最大的长度

这个 死信交换机,也是一个正常的交换机

可以被任何一个队列指定,被指定成死信交换机的时候,会设置 x-dead-letter-exchange属性,并且会设置对应的路由键 x-dead-letter-routing-key

死信队列的应用场景有哪些

  • 处理异常情况

消息不能够被消费者正确消费而被置入死信队列中的情况,后续分析程序可以通过消费这个死信队列中的内容来分析当时所遇到的异常情况,进而可以改善和优化系统

  • 搭配 TTL 模拟延迟队列

延迟队列是什么?

消息发送到队列之后,并不期望消费者能马上消费,也是延迟一段时间之后,才拿到该消息进行消费。

延迟队列我们是使用 死信队列 和 TTL 来模拟 延迟队列

延迟队列使用的场景举个栗子:

  • 下单了一个外卖,需要在15分钟以内完成支付,若未按时完成,则属于异常处理,需要延迟队列来处理这些消息

本例子中,用户下单,将消息丢入队列中,TTL 为15分钟,若15还未完成支付,则消息会被丢入对应的 死信队列中进行处理

优先级队列是什么?

我们一起来学RabbitMQ 三:RabbiMQ 死信队列,延迟队列,持久化等知识点_第4张图片

指的是 具有高优先级的队列具有最高的优先权,优先级高的消息具备优先被消费的特权

可以通过 设置 x-max-priority 来设置 优先级队列

当然,如果在消费者的消费速度远大于生产者的速度,且 Broker 没有消息堆积的情况下,对发送的消息设置优先级没有什么实际意义,因为生产者生产的消息,都能很快的被消费者立刻消灭掉

持久化都有哪些?

为了提高 RabbitMQ 的可靠性,RabbitMQ 做了持久化,持久化有这三部分

  • 交换机的持久化

RabbitMQ服务重启,若交换机不设置持久化,交换机的元数据会丢失,消息不会丢失,不过消息再也不能发送到这个交换机中了

  • 队列的持久化

RabbitMQ服务重启,若队列不设置持久化,元数据会丢失,数据也会丢失

  • 消息的持久化

设置所有的消息持久化,可靠性会大大提高,可是对于性能上是一个巨大的影响,这是一个可靠性和吞吐量之间做一个权衡

队列中传输消息有哪些保障的机制?

消息的传输保障,对于一般的消息中间件来说,会考虑这三个层级

  • 最多一次

消息可能会丢失,但不会重复

其中最多一次投递实现需要考虑以下几个方面的内容:

  1. 消息生产者需要开启事务机制 或者 确认机制,以确保消息可以可靠地传输到 RabbitMQ 中
  2. 消息生产者需要配合使用备份交换机来确保消息能够从交换机路由到队列中,进而能够保存下来而不会被丢弃
  3. 消息和队列都需要进行持久化处理,以确保 RabbitMQ 服务器在遇到异常情况时不会造成消息丢失
  4. 消费者在消费消息的同时需要将autoAck设置为 false,然后通过手动确认的方式去确认已经正确消费的消息,以避免在消费端引起不必要的消息丢失
  • 最少一次

消息可能会重复,但不会丢失

生产者随意发送,消费者随意消费

  • 恰好一次

每条消息一定只会被传输一次

RabbitMQ 这边 支持最多一次和至少一次

恰好一次是 RabbitMQ 无法保障的,会有这样几个原因

  1. 消费者在消费完一条消息之后向 RabbitMQ 发送确认命令

    此时由于异常原因(网络,或宕机)造成RabbitMQ并没有收到这个确认命令,RabbitMQ不会将此条消息标记删除。

    在重新连接之后,消费者还是会消费到这一条消息,这就造成了重复消费

  2. 生产者在使用 确认机制 的时候,发送完一条消息等待 RabbitMQ 返回确认通知

    此时正好网络断开,生产者捕获到异常情况

    为了确保消息可靠性选择重新发送,这样 RabbitMQ 中就有两条同样的消息,在消费的时候,消费者就会重复消费

那么生产者确认问题呢?

RabbitMQ 中的生产者确认机制有 两种模式

  • 事务模式

事务模式性能非常低,不建议使用。

事务机制在一条消息发送之后会使发送端阻塞,以等待RabbitMQ的回应,之后才能继续放下一条消息,这种方式会影响性能,所以不建议使用

  • 发送方确认模式 confirm 模式

发送方确认机制最大的好处在于它是异步的,一旦发布一条消息,生产者就可以在等信道返回确认的同时继续发送下一条消息

当消息最终得到确认之后,生产者便可以通过回调方式来处理该确认消息,哪怕是 RabbitMQ 自己内部出现了错误,也会回复响应的应答给到生产者 例如Nack

消费者处理消息的模式有哪些?

  • 推模式

消费者正常启动程序之后,会是推模式

  • 拉模式

在消费者程序第一次起来的时候,是拉模式

参考资料:

RabbitMQ Tutorials

欢迎点赞,关注,收藏

朋友们,你的支持和鼓励,是我坚持分享,提高质量的动力

我们一起来学RabbitMQ 三:RabbiMQ 死信队列,延迟队列,持久化等知识点_第5张图片

好了,本次就到这里

技术是开放的,我们的心态,更应是开放的。拥抱变化,向阳而生,努力向前行。

我是小魔童哪吒,欢迎点赞关注收藏,下次见~

你可能感兴趣的