Redis实现延迟队列的方案总结

数据库 Redis
Redis实现的延迟队列适用于处理一些比较简单的业务,如发送邮件、发送通知等,对于复杂的业务不适用于Redis的延迟任务方案。​

 redis是我们项目开发中常见的技术中间件,它除了可以实现常见的分布式锁和分布式缓存功能之外,还可以帮助我们实现很多的功能,如延迟队列。下面介绍几种redis常见的实现延迟队列的方案。

1、通过过期key通知实现

图片图片

 实现思路:首先开启redis的key过期通知,然后在业务中给key设置过期时间,到了过期时间后redis会自动的将过期的key消息推送给监听者,从而实现延迟任务。

核心的代码实现:

#1、开始redis的过期通知
notify-keyspace-events Ex


#2、监听redis的过期key
@Component
@Slf4j
public class RedisExpireKeyService extends 
                  KeyExpirationEventMessageListener {


    /**
     * Creates new {@link MessageListener} for {@code __keyevent@*__:expired} messages.
     *
     * @param listenerContainer must not be {@literal null}.
     */
    public RedisExpireKeyService(RedisMessageListenerContainer listenerContainer) {
        super(listenerContainer);
    }


    /**
     * 监听过期的key
     *
     */
    @Override
    public void onMessage(Message message, byte[] pattern) {
        String expireKey = message.toString();


        //执行具体的业务
        System.out.println("监听到key=" + expireKey + ",已经过期");
    }




}

生产环境是不推荐使用此方案,原因Redis 的过期策略采用的是惰性删除和定期删除相结合的方式,redis并不保证 key 在过期时会被立即删除操作,此方案适用于平时自己项目练习的时候使用。

2、通过Zset数据类型+定时任务实现

图片图片

    实现思路:ZSet 是一种有序集合类型,它可以存储不重复的元素,并且给每个元素赋予一个 double 类型的排序权重值(score),所以可以将元素的过期时间作为分值,通过定时任务扫描的方式判断是否达到过期时间,从而实现延迟队列。

    核心的代码实现:

#使用xxl-job
@JobName("consumerTaskJob")
public void consumerTaskJob() {
   String expireKey = "ExPIRE_KEY";
   try {
       //获取当前时间
        double currentTime = System.currentTimeMillis();
        //获取超时的数据
        Set<String> expiredMemberSet = redisTemplate.opsForZSet().rangeByScore(expireKey, Double.MIN_VALUE, currentTime);


        //过期key
        for (String expiredMember : expiredMemberSet) {
            //todo 做实际的延迟任务
            
            //从ZSet中移除数据
            redisTemplate.opsForZSet().remove(expireKey, expiredMember);
        } 
       } catch (Exception e) {
          log.error("数据处理失败",e);
       }
    }

Zset+定时任务的实现延迟任务的方式虽然比监听过期key方案合理一些,但是它还是存在一定的缺陷,如无重试机制、延迟时间固定化(依赖定时任务的执行时间)、不适用于大规模的延迟任务。

3、Redisson实现延迟队列

Redisson是一个操作Redis的 Java 客户框架,它提供了RDelayedQueue 接口和 RQueue 接口可以实现延迟队列(Redisson 提供的延迟队列底层也是基于 Zset 数据结构实现的)。

    核心的代码实现:

#1、添加依赖
<dependency>
 <groupId>org.redisson</groupId>
 <artifactId>redisson</artifactId>
 <version>3.16.0</version> 
</dependency>


#2、添加数据到队列中
//创建RedissonClient实例
RedissonClient redissonClient = Redisson.create();
//创建阻塞队列
RBlockingDeque<String> queue = redissonClient.getBlockingDeque("delayQueue");
//创建延迟队列并关联到阻塞队列
RDelayedQueue<String> delayedQueue = redissonClient.getDelayedQueue(queue);
//添加延迟任务
delayedQueue.offer("Task1", 5000, TimeUnit.MILLISECONDS);


#3、消费数据
while (true) {
    try {
          //获取并移除队首元素,如果队列为空,则阻塞等待
          String task = queue.take();
          System.out.println("Task: " + task);
       } catch (Exception e) {
          log.error("消费失败",e);
     }
}

总结:Redis实现的延迟队列适用于处理一些比较简单的业务,如发送邮件、发送通知等,对于复杂的业务不适用于Redis的延迟任务方案。

责任编辑:武晓燕 来源: 龙虾编程
相关推荐

2024-05-11 07:29:48

Redis延迟队列优化

2023-09-05 15:48:14

RabbitMQ延迟队列

2023-02-13 22:41:24

RedisMQRocketMQ

2024-04-19 00:47:07

RabbitMQ消息机制

2023-10-10 13:39:53

Spring队列优化

2021-12-08 10:47:35

RabbitMQ 实现延迟

2024-01-26 13:16:00

RabbitMQ延迟队列docker

2023-10-23 10:02:58

RabbitMQ延迟队列

2024-04-28 08:52:33

RabbitMQ延迟队列延迟插件

2023-12-30 13:47:48

Redis消息队列机制

2022-01-21 19:22:45

RedisList命令

2022-01-15 07:20:18

Redis List 消息队列

2024-03-22 12:10:39

Redis消息队列数据库

2024-04-09 10:40:04

2024-04-24 11:42:21

Redis延迟消息数据库

2020-10-16 15:06:59

开发技术方案

2021-10-15 10:39:43

RabbitMQ队列延迟

2023-02-27 22:03:06

数据库内存RocketMQ

2023-08-08 08:28:03

消息消费端Spring

2023-04-27 07:43:22

RabbitMQ重试队列死信队列
点赞
收藏

51CTO技术栈公众号