发送延迟消息_延迟消息的五种实现方案

生产者把消息发送到消息队列中以后,并不期望被立即消费,而是等待指定时间后才可以被消费者消费,这类消息通常被称为延迟消息。延迟消息的应用场景其实是非常的广泛,比如以下的场景:· 网上直播授课时,在课程开始前15分钟通知所有学生准备上课。· 订单提交成功后1个小时内未支付,订单需要及时关闭并且释放对应商品的库存。· 用户超过15天未登录时,给该用户发送召回推送。· 工单提交后超过24小时未处...
摘要由CSDN通过智能技术生成

生产者把消息发送到消息队列中以后,并不期望被立即消费,而是等待指定时间后才可以被消费者消费,这类消息通常被称为延迟消息。延迟消息的应用场景其实是非常的广泛,比如以下的场景:

· 网上直播授课时,在课程开始前15分钟通知所有学生准备上课。 · 订单提交成功后1个小时内未支付,订单需要及时关闭并且释放对应商品的库存。 · 用户超过15天未登录时,给该用户发送召回推送。 · 工单提交后超过24小时未处理,向相关责任人发送催促处理的提醒。 针对延迟消息,本文向大家分享五种实现方案,下面我们就来逐一讨论各种方案的大致实现和优缺点。 1 Redis 在Redis中,有一种有序集合(Sorted Set)的数据结构,在有序集合中,所有元素是按照其 Score 进行排序的。 我们可以把消息被消费的预期时间戳作为Score,定时任务不断读取Score大于当前时间的元素即可。 基本流程如下: 1. 调用API,传入执行时间、消息体等数据。 2. 生成唯一key,把消息体数据序列化后存入Redis的String结构中。 3. 把key和执行时间的时间戳存入Redis的有序集合结构中,有序集合中不存储具体的消息体数据,而是存储唯一的key。 4. 定时任务不断读取时间戳最小的消息。 5. 如果时间戳小于当前时间,将key放入作为队列的Redis的List结构中。 6. 另外一个定时任务不断从队列中读取需要消费的消息的key。 7. 根据key获取消息体数据,对消息进行消费。 8. 如果消费消息成功,删除key对应的消息体数据。 9. 如果消费消息失败,重新存入key和时间戳(加60秒)。 具体方案如下图: 9d0ac8a5f4e3febc827911765592a03f.png 为了避免一个有序集合中存储过多的延时消息,存入操作以及查询操作速度变慢的问题,可以建立多个有序集合,通过哈希算法把消息路由到不同的有序集合中去。
优点
简单实用,快速落地。
缺点
· 单个有序集合无法支持太大的数据量。 · 定时任务不断读取可能造成不必要的请求。 所以,Redis方案并不是一个十分成熟的方案,只是一个支持小消息量可以快速落地的方案。2 RabbitMQ RabbitMQ本身是不支持延迟消息功能的,一般的做法,是通过 最大生存时间 (Time-To-Live)和 死信交换机 (Dead Letter Exchanges)两个特性模拟出延迟消息的功能。消息超过最大生存时间没有被消费就变成一条死信,便会被重新投递到死信交换机,然后死信交换机根据绑定规则转发到对应的死信队列上,监听该队列就可以让消息被重新消费。 不过,在RabbitMQ的3.5.8版本以后,我们就可以使用官方推荐的 rabbitmq delayed message exchange 插件很方便地实现延迟消息的功能。
安装插件
首先去官方插件列表页面  https://www.rabbitmq.com/community-plugins.html 下载rabbitmq_delayed_message_exchang插件,然后复制到RabbitMQ每个节点的plugins目录中。使用命令启用插件:
rabbitmq-plugins enable rabbitmq_delayed_message_exchange
一旦插件被启用,我们就可以开始使用它了。
使用示例
安装该插件后会生成支持延迟投递机制的Exchange类型: x-delayed-message 。接收到该类型的消息后不会立即将消息投递至目标队列中,而是存储在mnesia表中,检测消息达到可投递时间时再投递到目标队列。 使用延迟消息时,需要先声明一个 x-delayed-message 类型的交换器机:
Map args = new HashMap<>();
args.put("x-delayed-type", "direct");
channel.exchangeDeclare("one-more-exchange", "x-delayed-message", true, false, args);
发送延迟消息,其中在header中添加 x-delay ,表示延迟的毫秒数:
byte[] messageBodyBytes = "This is a delayed message".getBytes();
AMQP.BasicProperties.Builder props = new AMQP.BasicProperties.Builder();
headers = new HashMap();
headers.put("x-delay", 5000);
props.headers(headers);
channel.basicPublish("one-more-exchange", "", props.build(), messageBodyBytes);
优点
大品牌中间件,可靠稳定。
缺点
由于master单节点&#
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值