这篇文章将为大家详细讲解有关redis如何实现定时任务,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。

技术栈

redis / nodeJs / koa

技术重难点

开启redis的键空间通知功能(2.8.0及以上的版本才有此功能)

尽量使用单独的redis db来实现

使用基于redis的分布式锁来实现相关事件不会被重复消费

需要二次使用的信息需要体现在redis缓存的key中

redis cache key使用业务前缀,避免重名覆盖

防止业务服务重启导致nodejs层面的监听失效

"talk is cheap, show me the code ?"

核心代码

核心代码const{saveClient,subClient}=require('./db/redis')//存储实例和订阅实例需要为两个不同的实例constprocessor=require('./service/task')constconfig=require('./config/index')constinnerDistributedLockKey='&&__&&'//内部使用的分布式锁的key的特征值constinnerDistributedLockKeyReg=newRegExp(`^${innerDistributedLockKey}`)saveClient.on('ready',async()=>{saveClient.config('SET','notify-keyspace-events','Ex')//存储实例设置为推送键过期事件console.log('redisinitsuccess')})subClient.on('ready',()=>{//服务重启后依旧可以初始化所有processorsubClient.subscribe(`__keyevent@${config.redis.sub.db}__:expired`)//订阅实例负责订阅消息subClient.on('message',async(cahnnel,expiredKey)=>{//分布式锁的key不做监听处理if(expiredKey.match(innerDistributedLockKeyReg))return//简易分布式锁,拿到锁的实例消费eventconstcackeKey=`${innerDistributedLockKey}-${expiredKey}`constlock=awaitsaveClient.set(cackeKey,2,'ex',5,'nx')//这里的用法可以实现简易的分布式锁if(lock==='OK'){awaitsaveClient.del(cackeKey)for(letkeyinprocessor){processor[key](expiredKey)//processor对应的是接收到相关键过期通知后执行的业务逻辑,比如推送短信,然后在相关processor中再次set一个定时过期的key}}})console.log('subClientinitsuccess')})

servide/task(processor)exports.sendMessage=asyncfunctionsendMessage(expiredKey,subClient){//只处理相关业务的过期事件if(expiredKey.match(/^send_message/)){const[prefix,userId,type]=expiredKey.split('-')letuser=getUser(userId)if(user.phone){push(message)//伪代码resetRedisKey(expiredKey,ttl)//重新把key设置为一段时间后过期,过期后会再次触发本逻辑}}}

总结

此功能利用了redis的键空间通知功能实现了简单了基于用户或者基于不同业务场景的定时任务功能。由于键空间事件通知功能是一个较消耗CPU的操作,所以建议使用单独的DB来处理。

这里展示出来的是基本用法,未考虑定时任务的持久化功能,如果使用过程中redis故障重启,则会导致所有定时任务丢失。如果在redis发布键失效通知时,订阅服务出故障未在线,或者网络问题没有被消费方收到,也会导致此次事件丢失。

redis的expired事件并不是在key过期的时候触发,而是在key被删除的时候触发。redis会定期清理过期的key,或者当访问key的时候检查是否过期,只有这时过期的key才会触发删除操作,因此会有一些小的时间差距(个人的实际使用中并没有影响用户体验)。

因此需要权衡使用redis的过期机制实现的定时任务的使用场景。

关于“redis如何实现定时任务”这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,使各位可以学到更多知识,如果觉得文章不错,请把它分享出去让更多的人看到。