共计 2156 个字符,预计需要花费 6 分钟才能阅读完成。
自动写代码机器人,免费开通
这篇文章将为大家详细讲解有关 redis 如何实现定时任务,丸趣 TV 小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。
技术栈
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 如何实现定时任务”这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,使各位可以学到更多知识,如果觉得文章不错,请把它分享出去让更多的人看到。
向 AI 问一下细节