RabbitMQ实践——超时消息的处理方法

大纲

在项目中,我们往往会遇到消息具有时效性:在一定时间内的消息需要处理,其他消息则不用处理。RabbitMQ提供了两种功能来满足这种需求:

  • 整个队列的消息都有相同的时效性。
  • 消息可以指定自己的超时时间。

对于超时的消息,我们可以选择抛弃,或者让其进入死信。本文我们将实验这些场景。

准备工作

我们先新建一个交换器direct.ttl。后续不同场景我们再设定其不同路由。

然后再创建一个死信队列queue.dead.letter

最后新建交换器direct.ttl和队列queue.dead.letter的路由绑定关系

后续我们将根据不同场景新建不同的队列和绑定关系。

整个队列的消息都有相同的时效性

抛弃超时消息

新建带x-message-ttl的队列

如果队列设置了x-message-ttl,则其全部消息的最大ttl就是其值。它的单位是毫秒。下图中,队列消息如果30秒没有处理,就会从队列中移除。

新建绑定关系

我们让交换器中Routing key是to.queue.all.message.ttl的消息路由到上面创建的队列中。

实验

向该交换器发送一条消息

消息出现在队列queue.all.message.ttl中。

半分钟后,该条消息从队列中消失。

超时消息路由到死信队列

不同于上例,只是设置了x-message-ttl,还要设置死信相关参数。本例我们将使用"重写Routing key"的方案,节省一次交换器的创建。

新建带死信和ttl的队列

新建名字是queue.all.msg.ttl.dead.letter的队列。这个队列中的所有消息的最大超时时间(x-message-ttl)是30秒;超时消息会被修改Routing key为to.queue.dead.letter后,使用direct.ttl交换器来路由。

新建绑定关系

将这个队列和之前新建的交换器direct.ttl关联。

实验


可以看到消息在过了30秒后,被从原来的队列queue.all.msg.ttl.dead.letter中移除,然后路由到死信队列queue.dead.letter中。

消息指定自己的超时时间

本例我们只实验相对复杂的场景,即将超时消息路由到死信。

新建带死信的队列

这个队列我们没有设置ttl相关数据,只是设置了死信相关配置:死信消息交由交换器direct.ttl处理,其Routing key被修改成to.queue.dead.letter。

绑定

实验

这次我们不能使用后台来发送消息,而是通过Java代码来发送。

java 复制代码
public void sendWithTTL(String exchangeName, String routingKey, String message, int ttl) {
    String msgId = UUID.randomUUID().toString();
    Message msg = MessageBuilder.withBody(message.getBytes())
            .setContentType("text/plain")
            .setCorrelationId(msgId)
            .setMessageId(msgId)
            .setExpiration(String.valueOf(ttl))
            .build();

    CorrelationData correlationData = new CorrelationData(msgId);
    rabbitTemplateWithoutMandatory.convertAndSend(exchangeName, routingKey, msg, correlationData);
}

发送消息时我们只需要给消息增加setExpiration调用即可。它的单位是毫秒,需要转换为字符串。

可以看到20秒后,消息从queue.with.dead.letter队列进入queue.dead.letter队列。

消息自带TTL和队列TTL的关系

如果一个自带TTL的消息被路由到一个所有消息都被队列指定TTL的队列上,那么哪个TTL生效呢?

我们用第二个案例的接口,给第一个案例的队列发送一个自带TTL的消息。

消息TTL < 队列指定TTL


可以看到消息在20秒时就进入了死信。

消息TTL > 队列指定TTL



可以看到消息在30秒时就进入了死信。

总结

如果队列指定TTL,消息也设置了TTL,取最接近当前时间的TTL。即用最短的那一个。

代码工程

https://github.com/f304646673/RabbitMQDemo

相关推荐
ABB自动化1 小时前
ABB 500CIM06 (1MRB150077R0111) | REB500 通信接口
大数据·分布式·系统架构·系统安全·模块测试·plc 控制器
ZENERGY-众壹1 小时前
告别本地工控机:分布式光伏 SCADA 架构如何实现云边协同
分布式·架构·光伏运维·能源数字化·电站监控
code_slave(码畜)1 小时前
微服务架构落地:读写分离架构 —— 主从延迟引发的“刚开单查不到”灾难与破局
spring boot·分布式·spring cloud·微服务·云原生·架构·读写分离
JAVA_AI人工智能项目实战3 小时前
分布式大模型训练_学习笔记
人工智能·分布式·语言模型·自然语言处理
星夜孤帆3 小时前
Redis缓存击穿与分布式锁实战:专栏目录、源码与实验说明
redis·分布式·缓存
yyk333245 小时前
Spark介绍
大数据·分布式·spark
成为你的宁宁5 小时前
【基于 SSH 与 JNLP 协议的 Jenkins 分布式构建方案】
分布式·jenkins
PingCAP21 小时前
善战者无赫赫之功:消费金融核心系统的数据库选型与升级路径
数据库·分布式·架构
库库的数据库笔记1 天前
金融核心交易系统的数据库国产信创改造该如何做?
大数据·数据库·分布式·mysql·oracle·金融·数据库架构
爱吃火鸡面呀1 天前
深入理解 Spark RDD:五大特性与实战解析
大数据·分布式·spark