这篇文章将为大家详细讲解有关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') // 存储实例和订阅实例需要为两个不同的实例 const processor = require('./service/task') const config = require('./config/index') const innerDistributedLockKey = '&&__&&' // 内部使用的分布式锁的key的特征值 const innerDistributedLockKeyReg = new RegExp(`^${innerDistributedLockKey}`) saveClient.on('ready', async () => { saveClient.config('SET', 'notify-keyspace-events', 'Ex') // 存储实例设置为推送键过期事件 console.log('redis init success') }) subClient.on('ready', () => { // 服务重启后依旧可以初始化所有processor subClient.subscribe(`__keyevent@${config.redis.sub.db}__:expired`) // 订阅实例负责订阅消息 subClient.on('message', async (cahnnel, expiredKey) => { // 分布式锁的key不做监听处理 if (expiredKey.match(innerDistributedLockKeyReg)) return // 简易分布式锁,拿到锁的实例消费event const cackeKey = `${innerDistributedLockKey}-${expiredKey}` const lock = await saveClient.set(cackeKey, 2, 'ex', 5, 'nx') // 这里的用法可以实现简易的分布式锁 if (lock === 'OK') { await saveClient.del(cackeKey) for (let key in processor) { processor[key](expiredKey) // processor对应的是接收到相关键过期通知后执行的业务逻辑,比如推送短信,然后在相关processor中再次set一个定时过期的key } } }) console.log('subClient init success') })
servide/task (processor) exports.sendMessage = async function sendMessage(expiredKey, subClient) { // 只处理相关业务的过期事件 if (expiredKey.match(/^send_message/)) { const [prefix, userId, type] = expiredKey.split('-') let user = 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如何实现定时任务”这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,使各位可以学到更多知识,如果觉得文章不错,请把它分享出去让更多的人看到。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。