這篇文章將為大家詳細(xì)講解有關(guān)redis如何實(shí)現(xiàn)定時(shí)任務(wù),小編覺得挺實(shí)用的,因此分享給大家做個(gè)參考,希望大家閱讀完這篇文章后可以有所收獲。
創(chuàng)新互聯(lián)建站是專業(yè)的韶山網(wǎng)站建設(shè)公司,韶山接單;提供成都網(wǎng)站設(shè)計(jì)、成都網(wǎng)站制作,網(wǎng)頁(yè)設(shè)計(jì),網(wǎng)站設(shè)計(jì),建網(wǎng)站,PHP網(wǎng)站建設(shè)等專業(yè)做網(wǎng)站服務(wù);采用PHP框架,可快速的進(jìn)行韶山網(wǎng)站開發(fā)網(wǎng)頁(yè)制作和功能擴(kuò)展;專業(yè)做搜索引擎喜愛的網(wǎng)站,專業(yè)的做網(wǎng)站團(tuán)隊(duì),希望更多企業(yè)前來合作!技術(shù)棧
redis / nodeJs / koa
技術(shù)重難點(diǎn)
開啟redis的鍵空間通知功能(2.8.0及以上的版本才有此功能)
盡量使用單獨(dú)的redis db來實(shí)現(xiàn)
使用基于redis的分布式鎖來實(shí)現(xiàn)相關(guān)事件不會(huì)被重復(fù)消費(fèi)
需要二次使用的信息需要體現(xiàn)在redis緩存的key中
redis cache key使用業(yè)務(wù)前綴,避免重名覆蓋
防止業(yè)務(wù)服務(wù)重啟導(dǎo)致nodejs層面的監(jiān)聽失效
"talk is cheap, show me the code ?"
核心代碼
核心代碼 const { saveClient, subClient } = require('./db/redis') // 存儲(chǔ)實(shí)例和訂閱實(shí)例需要為兩個(gè)不同的實(shí)例 const processor = require('./service/task') const config = require('./config/index') const innerDistributedLockKey = '&&__&&' // 內(nèi)部使用的分布式鎖的key的特征值 const innerDistributedLockKeyReg = new RegExp(`^${innerDistributedLockKey}`) saveClient.on('ready', async () => { saveClient.config('SET', 'notify-keyspace-events', 'Ex') // 存儲(chǔ)實(shí)例設(shè)置為推送鍵過期事件 console.log('redis init success') }) subClient.on('ready', () => { // 服務(wù)重啟后依舊可以初始化所有processor subClient.subscribe(`__keyevent@${config.redis.sub.db}__:expired`) // 訂閱實(shí)例負(fù)責(zé)訂閱消息 subClient.on('message', async (cahnnel, expiredKey) => { // 分布式鎖的key不做監(jiān)聽處理 if (expiredKey.match(innerDistributedLockKeyReg)) return // 簡(jiǎn)易分布式鎖,拿到鎖的實(shí)例消費(fèi)event const cackeKey = `${innerDistributedLockKey}-${expiredKey}` const lock = await saveClient.set(cackeKey, 2, 'ex', 5, 'nx') // 這里的用法可以實(shí)現(xiàn)簡(jiǎn)易的分布式鎖 if (lock === 'OK') { await saveClient.del(cackeKey) for (let key in processor) { processor[key](expiredKey) // processor對(duì)應(yīng)的是接收到相關(guān)鍵過期通知后執(zhí)行的業(yè)務(wù)邏輯,比如推送短信,然后在相關(guān)processor中再次set一個(gè)定時(shí)過期的key } } }) console.log('subClient init success') })
servide/task (processor) exports.sendMessage = async function sendMessage(expiredKey, subClient) { // 只處理相關(guān)業(yè)務(wù)的過期事件 if (expiredKey.match(/^send_message/)) { const [prefix, userId, type] = expiredKey.split('-') let user = getUser(userId) if (user.phone) { push(message) // 偽代碼 resetRedisKey(expiredKey, ttl) // 重新把key設(shè)置為一段時(shí)間后過期,過期后會(huì)再次觸發(fā)本邏輯 } } }
總結(jié)
此功能利用了redis的鍵空間通知功能實(shí)現(xiàn)了簡(jiǎn)單了基于用戶或者基于不同業(yè)務(wù)場(chǎng)景的定時(shí)任務(wù)功能。由于鍵空間事件通知功能是一個(gè)較消耗CPU的操作,所以建議使用單獨(dú)的DB來處理。
這里展示出來的是基本用法,未考慮定時(shí)任務(wù)的持久化功能,如果使用過程中redis故障重啟,則會(huì)導(dǎo)致所有定時(shí)任務(wù)丟失。如果在redis發(fā)布鍵失效通知時(shí),訂閱服務(wù)出故障未在線,或者網(wǎng)絡(luò)問題沒有被消費(fèi)方收到,也會(huì)導(dǎo)致此次事件丟失。
redis的expired事件并不是在key過期的時(shí)候觸發(fā),而是在key被刪除的時(shí)候觸發(fā)。redis會(huì)定期清理過期的key,或者當(dāng)訪問key的時(shí)候檢查是否過期,只有這時(shí)過期的key才會(huì)觸發(fā)刪除操作,因此會(huì)有一些小的時(shí)間差距(個(gè)人的實(shí)際使用中并沒有影響用戶體驗(yàn))。
因此需要權(quán)衡使用redis的過期機(jī)制實(shí)現(xiàn)的定時(shí)任務(wù)的使用場(chǎng)景。
關(guān)于“redis如何實(shí)現(xiàn)定時(shí)任務(wù)”這篇文章就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,使各位可以學(xué)到更多知識(shí),如果覺得文章不錯(cuò),請(qǐng)把它分享出去讓更多的人看到。
另外有需要云服務(wù)器可以了解下創(chuàng)新互聯(lián)scvps.cn,海內(nèi)外云服務(wù)器15元起步,三天無(wú)理由+7*72小時(shí)售后在線,公司持有idc許可證,提供“云服務(wù)器、裸金屬服務(wù)器、高防服務(wù)器、香港服務(wù)器、美國(guó)服務(wù)器、虛擬主機(jī)、免備案服務(wù)器”等云主機(jī)租用服務(wù)以及企業(yè)上云的綜合解決方案,具有“安全穩(wěn)定、簡(jiǎn)單易用、服務(wù)可用性高、性價(jià)比高”等特點(diǎn)與優(yōu)勢(shì),專為企業(yè)上云打造定制,能夠滿足用戶豐富、多元化的應(yīng)用場(chǎng)景需求。