《RabbitMQ》|《RabbitMQ》| 解决消息延迟和堆积问题
大家好,我是小菜。
一个希望能够成为 吹着牛X谈架构 的男人!如果你也想成为我想成为的人,不然点个关注做个伴,让小菜不再孤单!
本文主要介绍RabbitMQ的常见问题
如有需要,可以参考
【《RabbitMQ》|《RabbitMQ》| 解决消息延迟和堆积问题】如有帮助,不忘 点赞 ?
微信公众号已开启,小菜良记,没关注的同学们记得关注哦!
- 消息可靠性问题:如何确保发送的消息至少被消费一次?
- 延迟消息问题:如何实现消息的延迟投递?
- 消息堆积问题:如何解决数百万级以上消息堆积,无法及时消费问题?
消息丢失
的问题,也就是保证了消息的可靠性,那么其余两个问题同样重要,这篇我们将讲述其余两个问题的解决方式~!消息丢失解决方案: 《RabbitMQ》 | 消息丢失也就这么回事一、延迟消息
延迟消息 字面意思就是让延迟接收消息,那么如何能让消息延迟到达?这就是我们要思考解决的问题,在了解延迟队列之前我们需要先明白
RabbitMQ
中的两个概念- 死信交换机
- TTL
- 消费者使用
basic.reject
或basic.nack
声明消费失败,并将消息的 requeue 参数设置为false
- 消息是一个过期消息,超时后无人消费
- 要投递的队列消息堆积满了,最早的消息就会成为死信
死信交换机
便是 死信
的归属。如果一个队列配置了
dead-letter-exchange
属性,指定了一个交换机,那么队列中的死信就会投递到这个交换机中,而这个交换机就称为 死信交换机 - DLX
(Dead Letter Exchange )步骤:当生产者正常投递到队列(simple.queue)中,如果消费者从队列(simple.queue) 消费消息却声明了 reject,那并且队列绑定了死信交换机(dl.queue),那么这个时候成为死信的消息就会投递到这个死信队列(dl.queue)中。
文章图片
从
正常队列 --> 死信队列
的过程,我们必须声明两个关键信息- 死信交换机的名称
- 死信交换机与死信队列绑定的路由key
接下来我们简单模拟一下 条件1 所产生的场景
1、首先声明一个死信交换机和死信队列 我们这边是使用简单的注解方式直接生成
文章图片
通过 RabbitMQ 控制台界面可以看出已经成功生成
文章图片
2、声明正常使用交换机与队列 然后这个时候我们就可以创建一个正常使用的交换机与队列,并指明死信交换机
文章图片
同样可以通过控制台查看创建状态
文章图片
其中是否有声明死信交换机我们可以通过队列的
DLX
和 DLK
标志判断3、模拟拒收 然后我们现在通过代码模拟客户端拒绝消息的场景
1)消息发送
文章图片
2)消息接收
文章图片
查看控制台,结果如下:
2021-11-06 23:56:52.095INFO 2112 --- [ntContainer#0-1] c.l.m.c.listener.SpringRabbitListener: 正常业务交换机 | 接收到的消息 : [hello]
2021-11-06 23:56:52.118INFO 2112 --- [ntContainer#1-1] c.l.m.c.listener.SpringRabbitListener: 死信交换机 | 接收到的消息 : hello
这说明我们死信交换机已经成功发挥作用
2)TTL 以上我们已经成功认识到了
死信交换机
的使用,但是这与我们一开始说的 延迟队列 似乎并没有太大关系,莫急~接下来说到的 TTL(Time-To-Live)
就是用来处理延迟消息的~!在 TTL 的概念中,如果一个队列中的消息 TTL 结束后仍未被消费,那么这个消息就会自动变为死信,而 TTL 超时情况分为两种:
- 消息所在的队列设置了存活时间
- 消息本身设置了存活时间
文章图片
我们同样进行上述 条件2 的模拟场景
1、声明死信交换机与死信队列(上述已完成) 2、声明延迟队列并指定死信交换机
文章图片
同样控制台查看创建结果,并且我们发现不止有
DLX
和 DLK
标志,还多了个 TTL
,说明该队列是延迟队列文章图片
3、模拟消费超时情况 我们往延迟队列中发送一条消息,并且没有消费者进行消费,等待 1 分钟后查看是否能进入 死信队列 中
文章图片
我们已经发送了一条消息到延迟队列并且一分钟后也成功在控制台发现了这条信息已经进入到了死信交换机
2021-11-07 00:01:30.854INFO 32752 --- [ntContainer#1-1] c.l.m.c.listener.SpringRabbitListener: 死信交换机 | 接收到的消息 : test ttl-message
以上是配置了
队列超时
时间,消息本身自然也能配置超时时间,当 消息 和 队列 都存在超时时间时,那么就以最短的 TTL 为准,消息的超时配置如下:文章图片
如上图所示,我们可以利用
Message
这个类来传递消息信息,并设置上超时时间,我们设置的是 5000 ms,等待发送成功后,控制台过5000 ms 也成功打印了死信交换机消费的消息:2021-11-07 00:03:09.048INFO 39996 --- [ntContainer#1-1] c.l.m.c.listener.SpringRabbitListener: 死信交换机 | 接收到的消息 : this is a ttl message
3)延迟队列 我们上述是使用 死信交换机 来间接实现 延迟队列 的效果,但实际在 RabbitMQ 不必如此麻烦,RabbitMQ 已经为我们封装好了插件,我们只需要下载安装即可~
RabbitMQ 插件下载地址我们进入地址可以发现有许多插件,搜索
delay
关键字找到我们需要的插件进行下载文章图片
下载完后直接上传到
RabbitMQ
的插件目录 - plugins,小菜这边是使用 docker 临时安装测试的,所以已经将该插件目录挂载出来了:docker run -itd --name rabbitmq -v plugins:/plugins -p 15672:15672 -p 5672:5672 rabbitmq:management
因此我这边直接将插件上传到容器中的
plugins
目录即可~然后进入到容器中执行以下命令进行插件开启
rabbitmq-plugins enable rabbitmq_delayed_message_exchange
文章图片
并且我们在控制台创建交换机的时候可以看到
type
类型多了个选项文章图片
成功执行到这步就说明已经开启了 RabbitMQ 的延迟队列功能
那接下来我们就可以来使用
DelayExchange
,首先我们需要了解代码的方式创建延迟交换机:方式1
文章图片
方式2
文章图片
当我们万事具备之后就可以来发送消息了
在发送消息的时候,消息头中一定要携带上 x-delay 参数,指定上延迟时间
文章图片
通过这样配置之后,我们可以在控制台看到,经过10秒后
delay.queue
才收到对应消息,然后被对应消费者消费3)总结 我们上面从
死信交换机
到 TTL
到 延迟队列
,一步步认识了如何实现延迟消息的功能,然后我们进行一个小小的总结:问题1:什么样的消息会成为死信?
- 消息被消费者 reject 或返回 nack
- 消息超时未及时消费
- 消息队列满了
- 给队列设置 TTL 属性
- 给消息设置 TTL 属性
- 下载并启用 RabbitMQ 延迟队列插件
- 声明一个交换机,并将 delayed 属性设置为 true
- 发送消息时,添加 x-delay 头,值为超时时间
- 延迟发送短信通知
- 订单自动取消
- 库存自动回滚
讲完延迟队列,我们继续来认识
惰性队列
讲
惰性队列
之前,我们先抛出一个问题~RabbitMQ 如何解决消息堆积问题什么情况下会出现消息堆积问题?
- 当生产者生产速度远远消费者消费速度
- 当消费者宕机没有及时重启
- 在消费者机器重启后,增加更多的消费者进行处理
- 在消费者处理逻辑内部开辟线程池,利用多线程的方式提高处理速度
- 扩大队列的容量,提高堆积上限
惰性队列
什么是惰性队列?我们认识一下惰性队列的几个特性:
- 接收到消息后直接存入磁盘而非内存
- 消费者要消费消息时才会从磁盘中读取并加载到内存中
- 它支持百万级消息的存储
消息的时效性会降低,性能受限于磁盘的IO
,认识特性和缺点之后,我们便来看看如何创建惰性队列方式1
文章图片
方式2
文章图片
方式3 该方式是直接基于命令行修改将一个正在运行中的队列修改为惰性队列
rabbitmqctl set_policy Lazy "^lazy-queue$" '{"queue-mode":"lazy"}' --apply-to queues
其中几个命令参数含义如下:
- rabbitmqctl:命令行工具
- set_policy:添加一个策略
- Lazy:策略名称,可以自定义
- ^lazy-queue$:用正则表达式匹配队列的名称
- '{"queue-mode":"lazy"}':设置队列为 lazy 模式
- --apply-to queues:策略的作用对象,是所有的队列
- 基于磁盘存储,消息上限高
- 没有间歇性的 page-out,性能稳定
不要空谈,不要贪懒,和小菜一起做个
吹着牛X做架构
的程序猿吧~点个关注做个伴,让小菜不再孤单。咱们下文见!文章图片
今天的你多努力一点,明天的你就能少说一句求人的话!
我是小菜,一个和你一起变强的男人。
微信公众号已开启, 小菜良记,没关注的同学们记得关注哦!
推荐阅读
- 慢慢的美丽
- 《真与假的困惑》???|《真与假的困惑》??? ——致良知是一种伟大的力量
- 《跨界歌手》:亲情永远比爱情更有泪点
- 诗歌:|诗歌: 《让我们举起世界杯,干了!》
- 期刊|期刊 | 国内核心期刊之(北大核心)
- 《魔法科高中的劣等生》第26卷(Invasion篇)发售
- 人间词话的智慧
- 《一代诗人》37期,生活,江南j,拨动心潭的一泓秋水
- 广角叙述|广角叙述 展众生群像——试析鲁迅《示众》的展示艺术
- 书评——《小行星》