百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术教程 > 正文

Redis通过Redisson实现延迟队列(含源码)

mhr18 2024-12-09 12:14 65 浏览 0 评论

实现延迟队列的方式有很多种,有本地自己jdk方式实现、Quartz 定时任务实现、RabbitMQ 延时队列实现,还有Redis方式实现。综合自己的生产情况,Redis是符合分布式服务及开发成本较小的一种方式。基本的机制如下图


本文将通过工具包Redisson用极简单的方式来实现一个延迟队列。同时提供一下比较完备的例子。

一、延迟队列的使用场景

背景:

1、当订单一直处于未支付状态时,如何及时地关闭订单

2、如何定期检查处于退款状态的订单是否已经退款成功

3、在订单长时间没有收到下游系统的状态通知的时候,如何实现阶梯式的同步订单状态的策略

4、在系统通知上游系统支付成功终态时,上游系统返回通知失败,如何进行异步通知实行分频率发送:15s 3m 10m 30m 30m 1h 2h 6h 15h

一般的解决方案:

1、最简单的方式,定时扫表。例如对于订单支付失效要求比较高的,每2S扫表一次检查过期的订单进行主动关单操作。优点是简单,缺点是每分钟全局扫表,浪费资源,如果遇到表数据订单量即将过期的订单量很大,会造成关单延迟。

2、使用RabbitMq或者其他MQ改造实现延迟队列,优点是,开源,现成的稳定的实现方案,缺点是:MQ是一个消息中间件,如果团队技术栈本来就有MQ,那还好,如果不是,那为了延迟队列而去部署一套MQ成本有点大

3、使用Redis的zset、list的特性,我们可以利用redis来实现一个延迟队列RedisDelayQueue。本文使用Redisson来实现。

二、Redisson实现方式

1、添加包

<dependency>
    <groupId>org.redisson</groupId>
    <artifactId>redisson</artifactId>
    <version>3.12.5</version>
</dependency>

2、实现

下面用一个抢红包的例子来演示实现过程。在一定时间内,红包没有领取的话,将失效。

创建红包类

import java.io.Serializable;

public class RedPacketMessage implements Serializable {
    /**
     * 红包 ID
     */
    private  long redPacketId;

    /**
     * 创建时间戳
     */
    private  long timestamp;

    public RedPacketMessage() {

    }

    public RedPacketMessage(long redPacketId) {
        this.redPacketId = redPacketId;
        this.timestamp = System.currentTimeMillis();
    }

    public long getRedPacketId() {
        return redPacketId;
    }

    public long getTimestamp() {
        return timestamp;
    }

}

实现类


import com.test.moredatasourse.bean.RedPacketMessage;
import org.redisson.Redisson;
import org.redisson.api.RBlockingQueue;
import org.redisson.api.RDelayedQueue;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.sql.Time;
import java.util.concurrent.TimeUnit;

/**
 * 延迟队列 redis实现
 */
public class RedPacketDelayQueue {
    private static final Logger LOGGER = LoggerFactory.getLogger(RedPacketDelayQueue.class);

    public static void main(String[] args) throws Exception {
        Config config = new Config();
        config.useSingleServer().setAddress("redis://192.168.197.24:36379");
        RedissonClient redissonClient = Redisson.create(config);
        /**
         * 红包目标队列
         */
        RBlockingQueue<RedPacketMessage> blockingRedPacketQueue
                = redissonClient.getBlockingQueue("redPacketDelayQueue");
        /**
         * 定时任务将到期的元素转移到目标队列
         */
        RDelayedQueue<RedPacketMessage> delayedRedPacketQueue
                = redissonClient.getDelayedQueue(blockingRedPacketQueue);

        /**
         * 延时信息入队列
         */
        // 经常会出现首条消息消费不了的情况,加一个初始为0的消息。
        delayedRedPacketQueue.offer(new RedPacketMessage(0), 1, TimeUnit.SECONDS);

        // 下面是真正的业务
        delayedRedPacketQueue.offer(new RedPacketMessage(5), 5, TimeUnit.SECONDS);
        delayedRedPacketQueue.offer(new RedPacketMessage(10), 10, TimeUnit.SECONDS);
        delayedRedPacketQueue.offer(new RedPacketMessage(30), 30, TimeUnit.SECONDS);
        delayedRedPacketQueue.offer(new RedPacketMessage(50), 50, TimeUnit.SECONDS);
        LOGGER.info("红包ID:");
        while (true){
            /**
             * 取出失效红包
             */
            RedPacketMessage redPacket = blockingRedPacketQueue.take();
            LOGGER.info("红包ID:{}过期失效",redPacket.getRedPacketId());
            /**
             * 处理相关业务逻辑:记录相关信息并退还剩余红包金额
             */
        }

    }
}

三、源码

1、本文源码:

https://gitee.com/yaokj/demo-toutiao/blob/master/src/main/java/com/test/moredatasourse/utils/RedPacketDelayQueue.java

本文的方式很简单。还有一个稍完备的可以看:

https://blog.csdn.net/zxl646801924/article/details/107610699

2、本文并没有解决删除消息的情况。在实际中,还是会遇到从队列中删除一个元素的情况。

还有一个更完备的例子的源码:

https://gitee.com/fork-out-project/zing-project/tree/master/zing-delay-queue

相关推荐

Java面试题及答案总结(2025版)

大家好,我是Java面试陪考员最近很多小伙伴在忙着找工作,给大家整理了一份非常全面的Java面试题及答案。涉及的内容非常全面,包含:Redis、Linux、SpringBoot、Spring、MySQ...

Java面试题及答案最全总结(2025春招版)

大家好,我是Java面试分享最近很多小伙伴在忙着找工作,给大家整理了一份非常全面的Java面试题及答案。涉及的内容非常全面,包含:Spring、MySQL、JVM、Redis、Linux、Spring...

Java面试题及答案最全总结(2025版持续更新)

大家好,我是Java面试陪考员最近很多小伙伴在忙着找工作,给大家整理了一份非常全面的Java面试题及答案。涉及的内容非常全面,包含:Spring、MySQL、JVM、Redis、Linux、Sprin...

蚂蚁金服面试题(附答案)建议收藏:经典面试题解析

前言最近编程讨论群有位小伙伴去蚂蚁金服面试了,以下是面试的真题,跟大家一起来讨论怎么回答。点击上方“捡田螺的小男孩”,选择“设为星标”,干货不断满满1.用到分布式事务嘛?为什么用这种方案,有其他方案...

测试工程师面试必问的十道题目!全答上来的直接免试

最近参加运维工程师岗位的面试,笔者把自己遇到的和网友分享的一些常见的面试问答收集整理出来了,希望能对自己和对正在准备面试的同学提供一些参考。一、Mongodb熟悉吗,一般部署几台?部署过,没有深入研究...

10次面试9次被刷?吃透这500道大厂Java高频面试题后,怒斩offer

很多Java工程师的技术不错,但是一面试就头疼,10次面试9次都是被刷,过的那次还是去了家不知名的小公司。问题就在于:面试有技巧,而你不会把自己的能力表达给面试官。应届生:你该如何准备简历,面试项目和...

java高频面试题整理

【高频常见问题】1、事务的特性原子性:即不可分割性,事务要么全部被执行,要么就全部不被执行。一致性或可串性:事务的执行使得数据库从一种正确状态转换成另一种正确状态隔离性:在事务正确提交之前,不允许把该...

2025 年最全 Java 面试题,京东后端面试面经合集,答案整理

最近京东搞了个TGT计划,针对顶尖青年技术天才,直接宣布不设薪资上限。TGT计划面向范围包括2023年10月1日到2026年9月30日毕业的海内外本硕博毕业生。时间范围还...

idGenerator测评

工作中遇到需要生成随机数的需求,看了一个个人开发的基于雪花算法的工具,今天进行了一下测评(测试)。idGenerator项目地址见:https://github.com/yitter/IdGenera...

2024年开发者必备:MacBook Pro M1 Max深度体验与高效工作流

工作机器我使用的是一台16英寸的MacBookProM1Max。这台电脑的表现堪称惊人!它是我用过的最好的MacBook,短期内我不打算更换它。性能依然出色,即使在执行任务时也几乎听不到风扇的...

StackOverflow 2022 年度调查报告

一个月前,StackOverflow开启了2022年度开发者调查,历时一个半月,在6月22日,StackOverflow正式发布了2022年度开发者调查报告。本次报告StackO...

这可能是最全面的SpringDataMongoDB开发笔记

MongoDB数据库,在最近使用越来越广泛,在这里和Java的开发者一起分享一下在Java中使用Mongodb的相关笔记。希望大家喜欢。关于MongoDB查询指令,请看我的上一篇文章。SpringD...

Mac M2 本地部署ragflow

修改配置文件Dockerfile文件ARGNEED_MIRROR=1//开启国内镜像代理docker/.envREDIS_PORT=6380//本地redis端口冲突RAGFLOW_IMA...

别再傻傻分不清!localhost、127.0.0.1、本机IP,原来大有讲究!

调试接口死活连不上?部署服务队友访问不了?八成是localhost、127.0.0.1、本机IP用混了!这三个看似都指向“自己”的东西,差之毫厘谬以千里。搞不清它们,轻则调试抓狂,重则服务裸奔。loc...

我把 Mac mini 托管到机房了:一套打败云服务器的终极方案

我把我积灰的Macmini托管到机房了,有图有真相。没想到吧?一台在家吃灰的苹果电脑,帮我省了大钱!对,就是控制了自己的服务器,省了租用云服务器的钱,重要数据还全捏在自己手里,这感觉真爽。你可...

取消回复欢迎 发表评论: