如何使用redis做一个定时任务?

前言

前一阵子遇到了一个头疼两天的问题,如何在项目运行中动态自定义一个以小时为单位的定时任务?我后来想到了redis键空间,用来监听过期的key,结合存储的执行间隔,重新存储有效期的key。

正文

查了查大佬们的文章,简单学习后,了解了redis键空间的用法和基本的知识。

什么是redis键空间?

Redis的键空间通知:keyspace notifications
这个功能是在2.8版本后加入的,在客户端通过订阅鸡汁,来接收那些以某种方式改变了redis数据空间的事件通知。
比如说,改变key的命令;所有在0号库过期的key;

事件类型

改变redis数据空间的每个操作,键空间通知都会发送两个不同的事件。
比如在1号数据库,执行 del zhangsan 的操作,将会触发两个消息:

1、keyevent@1:del zhangsan
2、keyspace@1:zhangsan del

keyspace是对所有zhangsan的key操作进行监听的。

keyevent是对所有执行成功的del操作进行监听,
如果有订阅者订阅监听了他,则会收到zhangsan返回的通知。

我就是利用了可以接收某个库过期的key这个操作,完成了这个定时任务。
而这个功能是可以通过redis配置来实现的,下面来说下到底怎么修改这个配置。

redis配置

因为键空间通知会消耗一定的CPU时间,所以在默认情况下,redis是关闭这个功能的,我们需要手动修改redis.conf来修改此功能的开启状态。

找到配置中 # notify-keyspace-events去掉注释,然后重新启动redis就可以了,easy吧?

这条配置,是需要在后面加多个指定的字符组成,来代表其不同的功能:

K:keyspace事件,事件以__keyspace@<库名>__为前缀进行发布;

E:keyevent事件,事件以__keyevent@<库名>__为前缀进行发布;

g:一般性的,非特定类型的命令,比如del,expire,rename等;

$:字符串特定命令;

l:列表特定命令;

s:集合特定命令;

h:哈希特定命令;

z:有序集合特定命令;

x:过期事件,当某个键过期并删除时会产生该事件;

e:驱逐事件,当某个键因maxmemore策略而被删除时,产生该事件;

A:g$lshzxe的别名,因此”AKE”意味着所有事件。

这些选项中,至少要包含K或者E,否则就没啥用了
比如我在这个定时任务中,使用了E和x:notify-keyspace-events Ex

话不多说了,上菜!
@Configuration
public class RedisConfiguration {

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private RedisConnectionFactory redisConnectionFactory;

    @Bean(name = "redisTemplate")
    public RedisTemplate<String, String> redisTemplate(RedisConnectionFactory factory) {
        RedisTemplate<String, String> template = new RedisTemplate<>();
        template.setConnectionFactory(factory);
        template.setKeySerializer(new StringRedisSerializer());
        template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
        template.setHashKeySerializer(new GenericJackson2JsonRedisSerializer());
        template.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
        template.afterPropertiesSet();
        return template;
    }

    /**
     * 监听key过期事件
     */
    @Bean
    public RedisMessageListenerContainer redisMessageListenerContainer() {
        RedisMessageListenerContainer container = new RedisMessageListenerContainer();
        container.setConnectionFactory(redisConnectionFactory);
        return container;
    }

    /**
     * 指定监听库
     */
    @Bean
    public ChannelTopic expiredTopic() {
        return new ChannelTopic("__keyevent@1__:expired");
    }

}

expiredTopic()方法,就可以指定某个库,某个事件,expired就是过期啦。

@Component
@Slf4j
public class RedisKeyExpirationListener extends KeyExpirationEventMessageListener {

    public RedisKeyExpirationListener(RedisMessageListenerContainer listenerContainer) {
        super(listenerContainer);
    }

	/**
     * 失效后回调函数
     * @param message
     * @param pattern
     */
    @SneakyThrows
    @Override
    public void onMessage(Message message, byte[] pattern) {
        super.onMessage(message, pattern);
        String msg = new String(message.getBody(), "UTF-8");
        String channel = new String(message.getChannel(), "UTF-8");

        log.info("Redis-Listener Channel:"+channel+" Listen to the key:"+msg);

        //msg字符串处理,获取想要的key名字....

		//具体的业务处理

		//想要定时,那就继续把key存到redis,结合过期时间
        
    }
    
}

正菜就是这些,具体业务还是需要结合不同项目,这里就不单独写我的了,至于怎么重新存储redis,这就不再多说了,工具类一找一大堆的哇!

总结

测试类我就不写出来了,自己动动手,马上就明白了这个redis键空间的用法。
可能这个功能会再以后运行中出现一些问题,在这里提几个,提前有所准备吧!比如说:
1、redis挂了?
2、一般来说这种动态定时不是很多,可如果很多,占内存或者影响速度怎么办?
3、反复启停定时,是否影响redis的其它操作?如果影响了,怎么办?
4、redis的订阅发布模式是fire and forget模式,发了就扔了,所以说收不到咋办,定时不存啦?
5、如果订阅发布的客户端over了又重连,岂不是事件都丢了?

好啦,大概提几个可能遇到的,我就不单独去说了,毕竟我也还没遇到咧!我这个项目比较小,问题也不大。但真的也要留心,任何一个错误,都不是小事!

希望对大家有点帮助!我是左小涩,一个独自在大城市努力的年轻人。

  • 11
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
引用\[1\]:在Spring Boot中使用Redis实现定时任务的步骤如下:首先,在应用程序启动类上加上注解@EnableScheduling,这个注解是用来支持计划任务的。然后,在定时任务执行类中使用@Scheduled注解来指定定时任务的执行时间。最后,在启动类上增加注解@EnableScheduling来启用定时任务的功能。\[1\] 引用\[2\]:在定时任务执行类中,可以使用Redis来实现定时任务的锁。通过在定时任务执行前获取Redis锁,可以避免多个重复任务同时执行的问题。可以使用缓存Redis或者数据库加字段加锁的方式来实现。另外,也可以使用分布式锁工具Zookeeper来实现定时任务的锁。\[2\] 引用\[3\]:具体实现代码如下:首先,引入Redis的依赖。然后,在定时任务执行类中使用@Scheduled注解来指定定时任务的执行时间。在任务执行前,通过Redis获取锁,并在任务执行完毕后释放锁。最后,在启动类上增加注解@EnableScheduling来启用定时任务的功能。\[3\] 综上所述,使用Redis实现定时任务的步骤包括:在应用程序启动类上加上@EnableScheduling注解,编写定时任务执行类并使用@Scheduled注解指定执行时间,引入Redis依赖,使用Redis获取锁来避免重复执行任务。 #### 引用[.reference_title] - *1* *2* [SpringBoot实践之---集群环境下利用Redis实现定时任务](https://blog.csdn.net/shimilysj/article/details/84889335)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^koosearch_v1,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [Springboot结合Redis实现分布式定时任务](https://blog.csdn.net/xrq1995/article/details/127521054)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^koosearch_v1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

左小涩°

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值