服务器之家:专注于服务器技术及软件下载分享
分类导航

Mysql|Sql Server|Oracle|Redis|MongoDB|PostgreSQL|Sqlite|DB2|mariadb|Access|数据库技术|

服务器之家 - 数据库 - Redis - redis实现延时队列的两种方式(小结)

redis实现延时队列的两种方式(小结)

2021-07-29 15:51卿着飞翔 Redis

这篇文章主要介绍了redis实现延时队列的两种方式(小结),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

背景

 

项目中的流程监控,有几种节点,需要监控每一个节点是否超时。按传统的做法,肯定是通过定时任务,去扫描然后判断,但是定时任务有缺点:1,数据量大会慢;2,时间不好控制,太短,怕一次处理不完,太长状态就会有延迟。所以就想到用延迟队列的方式去实现。

一,redis的过期key监控

 

1,开启过期key监听

在redis的配置里把这个注释去掉

?
1
notify-keyspace-events Ex

然后重启redis

2,使用redis过期监听实现延迟队列

继承KeyExpirationEventMessageListener类,实现父类的方法,就可以监听key过期时间了。当有key过期,就会执行这里。这里就把需要的key过滤出来,然后发送给kafka队列。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
@Component
@Slf4j
public class RedisKeyExpirationListener extends KeyExpirationEventMessageListener {
 
  @Autowired
  private KafkaProducerService kafkaProducerService;
 
  public RedisKeyExpirationListener(RedisMessageListenerContainer listenerContainer) {
    super(listenerContainer);
  }
 
  /**
   * 针对 redis 数据失效事件,进行数据处理
   * @param message
   * @param pattern
   */
  @Override
  public void onMessage(Message message, byte[] pattern){
    if(message == null || StringUtils.isEmpty(message.toString())){
      return;
    }
    String content = message.toString();
    //key的格式为  flag:时效类型:运单号 示例如下
    try {
      if(content.startsWith(AbnConstant.EMS)){
        kafkaProducerService.sendMessageSync(TopicConstant.EMS_WAYBILL_ABN_QUEUE,content);
      }else if(content.startsWith(AbnConstant.YUNDA)){
        kafkaProducerService.sendMessageSync(TopicConstant.YUNDA_WAYBILL_ABN_QUEUE,content);
      }
    } catch (Exception e) {
      log.error("监控过期key,发送kafka异常,",e);
    }
  }
}

可以看的出来,这种方式其实是很简单的,但是有几个问题需要注意,一是,这个尽量单机运行,因为多台机器都会执行,浪费cpu,增加数据库负担。二是,机器频繁部署的时候,如果有时间间隔,会出现数据的漏处理。

二,redis的zset实现延迟队列

 

1,生产者实现

可以看到生产者很简单,其实就是利用zset的特性,给一个zset添加元素而已,而时间就是它的score。

?
1
2
3
4
public void produce(Integer taskId, long exeTime) {
  System.out.println("加入任务, taskId: " + taskId + ", exeTime: " + exeTime + ", 当前时间:" + LocalDateTime.now());
  RedisOps.getJedis().zadd(RedisOps.key, exeTime, String.valueOf(taskId));
}

2,消费者实现

消费者的代码也不难,就是把已经过期的zset中的元素给删除掉,然后处理数据。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public void consumer() {
  Executors.newSingleThreadExecutor().submit(new Runnable() {
    @Override
    public void run() {
      while (true) {
        Set<String> taskIdSet = RedisOps.getJedis().zrangeByScore(RedisOps.key, 0, System.currentTimeMillis(), 0, 1);
        if (taskIdSet == null || taskIdSet.isEmpty()) {
          System.out.println("没有任务");
 
        } else {
          taskIdSet.forEach(id -> {
            long result = RedisOps.getJedis().zrem(RedisOps.key, id);
            if (result == 1L) {
              System.out.println("从延时队列中获取到任务,taskId:" + id + " , 当前时间:" + LocalDateTime.now());
            }
          });
        }
        try {
          TimeUnit.MILLISECONDS.sleep(100);
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
      }
    }
  });
}

可以看到这种方式其实是比上个方式要好的。因为,他的那两个缺点都被克服掉了。多台机器也没事儿,也不用再担心部署时间间隔长的问题。

总结

 

两个方式都是不错的,都能解决问题。碰到问题,多思考,多总结。

到此这篇关于redis实现延时队列的两种方式(小结)的文章就介绍到这了,更多相关redis 延时队列内容请搜索服务器之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持服务器之家!

原文链接:https://blog.csdn.net/qq_36268452/article/details/113392170

延伸 · 阅读

精彩推荐
  • Redis就这?Redis持久化策略——AOF

    就这?Redis持久化策略——AOF

    今天为大家介绍Redis的另一种持久化策略——AOF。注意:AOF文件只会记录Redis的写操作命令,因为读命令对数据的恢复没有任何意义...

    头发茂密的刘叔4052021-12-14
  • Redisredis启动,停止,及端口占用处理方法

    redis启动,停止,及端口占用处理方法

    今天小编就为大家分享一篇redis启动,停止,及端口占用处理方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧 ...

    澄海单挑狂5152019-11-14
  • RedisRedis存取序列化与反序列化性能问题详解

    Redis存取序列化与反序列化性能问题详解

    这篇文章主要给大家介绍了关于Redis存取序列化与反序列化性能问题的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参...

    这名字已经存在9742021-02-24
  • RedisLinux Redis 的安装步骤详解

    Linux Redis 的安装步骤详解

    这篇文章主要介绍了 Linux Redis 的安装步骤详解的相关资料,希望大家通过本文能掌握如何安装Redis,需要的朋友可以参考下 ...

    carl-zhao3822019-11-08
  • RedisRedis数据结构之链表与字典的使用

    Redis数据结构之链表与字典的使用

    这篇文章主要介绍了Redis数据结构之链表与字典的使用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友...

    白泽来了4052021-08-03
  • RedisRedis分布式锁升级版RedLock及SpringBoot实现方法

    Redis分布式锁升级版RedLock及SpringBoot实现方法

    这篇文章主要介绍了Redis分布式锁升级版RedLock及SpringBoot实现,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以...

    等不到的口琴7802021-07-25
  • Redis在ssm项目中使用redis缓存查询数据的方法

    在ssm项目中使用redis缓存查询数据的方法

    本文主要简单的使用Java代码进行redis缓存,即在查询的时候先在service层从redis缓存中获取数据。如果大家对在ssm项目中使用redis缓存查询数据的相关知识感...

    caychen8962019-11-12
  • Redis聊一聊Redis与MySQL双写一致性如何保证

    聊一聊Redis与MySQL双写一致性如何保证

    一致性就是数据保持一致,在分布式系统中,可以理解为多个节点中数据的值是一致的。本文给大家分享Redis与MySQL双写一致性该如何保证,感兴趣的朋友一...

    mind_programmonkey6432021-08-12