Redisson延迟队列执行流程源码分析一下

本文详细分析了Redisson延迟队列的执行流程,包括初始执行、offer添加任务、定时器源码解析。从JVM内存存储的不足出发,介绍了如何使用Redisson延迟队列处理分布式项目的延迟任务,通过源码解读展示了任务的添加、获取和定时器的工作机制。
摘要由CSDN通过智能技术生成
  • 在实际分布式项目中延迟任务一般不会使用JDK自带的延迟队列,因为它是基于JVM内存存储,没有持久化操作,所以当服务重启后就会丢失任务。
  • 在项目中可以使用MQ死信队列或redisson延迟队列进行处理延迟任务,本篇文章将讲述redisson延迟队列的使用demo和其执行源码。

demo示例

  • 通过脚手架创建一个简易springboot项目,引入redisson的maven依赖,并简单配置redisson连接属性。
    <!-- redisson引用 -->
    <dependency>
        <groupId>org.redisson</groupId>
        <artifactId>redisson</artifactId>
        <version>3.16.6</version>
    </dependency>

@Configuration
public class RedissonConfig {

    @Value("${spring.redis.host}")
    private String host;
    @Value("${spring.redis.port}")
    private String port;

    /**
     * 获取redissonClient实例
     *
     * @return
     * @throws Exception
     */
    @Bean
    public RedissonClient getRedisson() {
        Config config = new Config();
        String address = "redis://" + host + ":" + port;
        config.useSingleServer().setAddress(address);
        return Redisson.create(config);
    }
}
复制代码
  • 定义一个redisson延迟队列插入和获取任务处理类RedissonQueueHandle,通过控制spring的bean加载周期开启独立线程获取延迟任务。
  • 这里获取延迟任务使用了三种方法,除了第一种阻塞式获取任务方法外,其他两种方法都不是百分比按照延迟参数获取到任务,因为是时间间隔定时循环获取延迟任务。
/**
 * redisson延迟队列处理器
 *
 * @author zrh
 */
@Slf4j
@Component
public class RedissonQueueHandle implements InitializingBean {

    private final RBlockingQueue<RedisDataEntity<?>> queue;
    private final RDelayedQueue<RedisDataEntity<?>> delayedQueue;

    public RedissonQueueHandle (RedissonClient client) {
        this.queue = client.getBlockingQueue("redisson:queue");
        this.delayedQueue = client.getDelayedQueue(queue);
    }

    @Override
    public void afterPropertiesSet () {

        // 开一个线程阻塞式获取任务
        thread();

        // 使用netty时间轮循环获取任务
//        watchDog(new HashedWheelTimer());

        // 使用线程池定时获取任务
//        schedule();
    }

    private void thread () {
        new Thread(() -> {
            while (true) {
                try {
                    RedisDataEntity entity = queue.take();
                    log.info("本次获取数据:{},耗时:{}", entity, System.currentTimeMillis() - entity.getTime());
                } catch (Exception e) {
                }
            }
        }, "zrh").start();
    }

    private void watchDog (final HashedWheelTimer timer) {
        timer.newTimeout(timeout -> {
            RedisDataEntity entity = queue.poll();
            if (null != entity) {
                log.info("本次获取数据:{},耗时:{}", entity, System.currentTimeMillis() - entity.getTime());
            }
            watchDog(timer);
        }, 3, TimeUnit.SECONDS);
    }

    private void schedule () {
        Executors.newScheduledThreadPool(1).scheduleWithFixedDelay(() -> {
            RedisDataEntity entity = queue.poll();
            if (null != entity) {
                log.info("本次获取数据:{},耗时:{}", entity, System.currentTimeMillis() - entity.getTime());
            }
        }, 5, 5, TimeUnit.SECONDS);
    }

    /**
     * 放入redis,定时过期
     *
     * @param entity
     */
    public void offer (RedisDataEntity entity) {
        try {
            delayedQueue.offer(entity, entity.getExpire(), TimeUnit.MILLISECONDS);
        } catch (Exception e) {
            log.error("放入redis延迟队列异常", e);
        }
    }
}
复制代码
  • 放入redisson延迟队列可以是字符串也可以是对象RedisDataEntity,因为有进行IO磁盘存储操作,所以必须实现Serializable序列化接口。
/**
 * @Author: ZRH
 * @Date: 2022/1/10 11:54
 */
@Data
public class RedisDataEntity<T> implements Serializable {

    /**
     * 数据
     */
    private final T data;
    /**
     * 过期时间(单位:毫秒)
     */
    private final Long expire;
    /**
     * 添加时间
     */
    private final Long time;

    public RedisDataEntity (T data, Long expire, Long time) {
        this.data = data;
        this.expire = expire;
        this.time = time;
    }
}
复制代码
  • 然后开一个插入数据接口:
/**
 * @Author: ZRH
 * @Date: 2022/1/10 11:45
 */
@Slf4j
@RestController
public class IndexController {

    private final RedissonQueueHandle redisHandle;

    public IndexController (RedissonQueueHandle redisHandle) {
        this.redisHandle = redisHandle;
    }

    @PostMapping("redissonQueue")
    public String redissonQueue (@RequestParam String data, @RequestParam Long expire) {
        RedisDataEntity entity = new RedisDataEntity(data, expire, System.currentTimeMillis());
        log.info("本次添加数据:{}", entity);
        redisHandle.offer(entity);
        return "ok";
    }
}

访问接口设置延迟30秒:http://localhost:8802/redissonQueue?data=a&expire=30000,打印结果如下

2022-01-14 14:21:52.140  INFO 10808 --- [nio-8802-exec-1] c.r.web.controller.IndexController       :
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值