Redis实现简单延时队列

本文介绍了如何在SpringBoot项目中利用Redis的ZSet数据类型创建一个轻量级的延时队列,包括消息设置、删除和定时监听机制。作者详细展示了如何定义队列类和监控线程,以及如何启动监控线程来确保消息的及时处理。

什么情况使用redis实现延时队列        

相较于使用mq实现延时队列使用redis更加轻量简单,并且redis读写性能更高,所以一些简单的场景很适合使用redis实现延时队列

redis实现延时队列的基本原理

redis的zset数据类型是有序、不可重复的,我们可以将消息关键键(订单id)作为member,消息到期时间作为score存储到zset,能满足消息不重复消费、按时消费、按顺序消费。

往zset塞入消息之后开一个线程监控redis,获取zset中到期的消息的member完成相应业务。

基于springboot实现

队列类

定义了设置消息、删除消息、监听队列完成业务三个方法。



@Component
@Slf4j
public class RedisDelayQueue<T> {

    /**
     * 延迟队列名称
     */
    private String delayQueueName = "delayQueue";

    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * 删除消息
     * @param msg
     * @return
     */
    public Boolean deleteDelayTask(T msg){

        if (redisTemplate.opsForZSet().remove(delayQueueName, JSONObject.toJSONString(msg)) > 0) {
            return true;
        }
        return false;
    }

    /**
     * 设置延迟消息
     */
    public boolean setDelayTasks(T msg, long delayTime) {

        Boolean addResult = redisTemplate.opsForZSet().add(delayQueueName, JSONObject.toJSONString(msg), System.currentTimeMillis() + delayTime);
        if(addResult) {

            log.info("delayQueue添加任务成功!"+JSONObject.toJSONString(msg)+"当前时间为"+ LocalDateTime.now());

            return true;
        }
        return false;
    }

    /**
     * 监听延迟消息
     */
    public void listenDelayLoop() {
        //每隔一秒去队列中获取过期的消息
        while (true) {
            // 获取一个到点的消息
            Set<String> set = redisTemplate.opsForZSet().rangeByScore(delayQueueName, 0, System.currentTimeMillis(), 0, 1);

            // 如果没有,就等等
            if (set.isEmpty()) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                // 继续执行
                continue;
            }
            // 获取具体消息的key
            String it = set.iterator().next();
            // 删除成功
            if (redisTemplate.opsForZSet().remove(delayQueueName, it) > 0) {

                // 拿到任务member
                String bookId = JSONObject.parseObject(it, String.class);
                
                //处理业务

            }
        }

    }


}

 监控线程类

用于监控队列的线程

@Component
public class ListenThread extends Thread{

    @Autowired
    RedisDelayQueue queue;

    @Override
    public void run(){
        queue.listenDelayLoop();
    }


}

启动线程

根据需求启动线程监控队列,这里是项目启动就开启监控线程

@Component
@Slf4j
public class MyApplicationRunner implements ApplicationRunner {

    @Autowired
    ListenThread listenThread;

    @Override
    public void run(ApplicationArguments args) throws Exception {
        log.info("项目启动开启redis延时消息监控线程");
        listenThread.start();
    }
}

参考https://blog.youkuaiyun.com/weixin_51110874/article/details/123288473?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522171098879316800184198991%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fall.%2522%257D&request_id=171098879316800184198991&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~first_rank_ecpm_v1~rank_v31_ecpm-24-123288473-null-null.142^v99^pc_search_result_base6&utm_term=redis%E5%BB%B6%E6%97%B6%E9%98%9F%E5%88%97&spm=1018.2226.3001.4187

评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值