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

来源:脚本之家  责任编辑:小易  

背景

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

一,redis的过期key监控

1,开启过期key监听

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

notify-keyspace-events Ex

然后重启redis

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

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

@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。

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中的元素给删除掉,然后处理数据。

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 延时队列内容请搜索真格学网以前的文章或继续浏览下面的相关文章希望大家以后多多支持真格学网!

您可能感兴趣的文章:golang实现redis的延时消息队列功能示例使用Redis实现延时任务的解决方案利用Redis实现延时处理的方法实例

  • 本文相关:
  • redis 基础教程之事务的使用方法
  • redis的持久化方案详解
  • redis不同数据类型使用场景代码实例
  • redis4.0入门小结
  • redis数据库的应用场景介绍
  • redis 的各项功能主要解决了什么问题
  • 使用redis实现微信步数排行榜功能
  • 关于redis你可能不了解的一些事
  • redis中统计各种数据大小的方法
  • redis sentinel的使用方法
  • 怎么让redis队列延迟10s
  • 如何通过redis实现简单队列
  • 持久化redis有几种方式
  • redis也可以实现队列,为什么还要用rabitmq或者kafka
  • redis怎么实现将消息队列持久化到数据库中
  • 怎么实现redis队列,且应用
  • 如何使用Redis 做队列操作
  • REDIS实现定长队列
  • 消息队列为什么用redis实现
  • php怎么实现redis阻塞队列
  • 网站首页网页制作脚本下载服务器操作系统网站运营平面设计媒体动画电脑基础硬件教程网络安全mssqlmysqlmariadboracledb2mssql2008mssql2005sqlitepostgresqlmongodbredisaccess数据库文摘数据库其它首页golang实现redis的延时消息队列功能示例使用redis实现延时任务的解决方案利用redis实现延时处理的方法实例redis 基础教程之事务的使用方法redis的持久化方案详解redis不同数据类型使用场景代码实例redis4.0入门小结redis数据库的应用场景介绍redis 的各项功能主要解决了什么问题使用redis实现微信步数排行榜功能关于redis你可能不了解的一些事redis中统计各种数据大小的方法redis sentinel的使用方法超强、超详细redis数据库入门教程redis常用命令、常见错误、配置技redis操作命令总结redis中5种数据结构的使用场景介64位windows下安装redis教程redis中使用redis-dump导出、导入redis中统计各种数据大小的方法redis 密码设置和查看密码的方法redis常用命令小结让redis在你的系统中发挥更大作用解决redis开启远程访问及密码问题redis cluster添加、删除的完整操作步骤图文详解windows下使用redis缓存工具的方redis-cli 使用密码登录的实例redis中的数据结构和编码详解redis 出现错误1067的解决办法redis自动化安装及集群实现搭建过程redis偶发连接失败案例实战记录redis正确使用的十个技巧基于redis的限流器的实现(示例讲解)
    免责声明 - 关于我们 - 联系我们 - 广告联系 - 友情链接 - 帮助中心 - 频道导航
    Copyright © 2017 www.zgxue.com All Rights Reserved