您好,登錄后才能下訂單哦!
今天小編給大家分享的是關(guān)于Redis緩存失效機(jī)制的介紹,很多人都不太了解,今天小編為了讓大家更加了解Redis緩存失效機(jī)制,所以給大家總結(jié)了以下內(nèi)容,一起往下看吧。一定會(huì)有所收獲的哦。
Redis緩存失效的故事要從EXPIRE這個(gè)命令說起,EXPIRE允許用戶為某個(gè)key指定超時(shí)時(shí)間,當(dāng)超過這個(gè)時(shí)間之后key對(duì)應(yīng)的值會(huì)被清除,這篇文章主要在分析Redis源碼的基礎(chǔ)上站在Redis設(shè)計(jì)者的角度去思考Redis緩存失效的相關(guān)問題。
Redis緩存失效機(jī)制
Redis緩存失效機(jī)制是為應(yīng)對(duì)緩存應(yīng)用的一種很常見的場(chǎng)景而設(shè)計(jì)的,講個(gè)場(chǎng)景:
我們?yōu)榱藴p輕后端數(shù)據(jù)庫的壓力,很開心的借助Redis服務(wù)把變化頻率不是很高的數(shù)據(jù)從DB load出來放入了緩存,因此之后的一段時(shí)間內(nèi)我們都可以直接從緩存上拿數(shù)據(jù),然而我們又希望一段時(shí)間之后,我們?cè)僦匦碌膹腄B load出當(dāng)前的數(shù)據(jù)放入緩存,這個(gè)事情怎么做呢?
問題提出來了,這個(gè)問題怎么解決呢?好吧,我們對(duì)于手頭的語言工具很熟悉,堅(jiān)信可以很快的寫出這么一段邏輯:我們記錄上次從db load數(shù)據(jù)的時(shí)間,然后每次響應(yīng)服務(wù)的時(shí)候都去判斷時(shí)間是不是過期了,要不要從db重新load了……。當(dāng)然這種方法也是可以的,然而當(dāng)我們查閱Redis command document的時(shí)候,發(fā)現(xiàn)我們做了本來不需要做的事情,Redis本身提供這種機(jī)制,我們只要借助EXPIRE命令就可以輕松的搞定這件事情:
EXPIRE key 30
上面的命令即為key設(shè)置30秒的過期時(shí)間,超過這個(gè)時(shí)間,我們應(yīng)該就訪問不到這個(gè)值了,到此為止我們大概明白了什么是緩存失效機(jī)制以及緩存失效機(jī)制的一些應(yīng)用場(chǎng)景,接下來我們繼續(xù)深入探究這個(gè)問題,Redis緩存失效機(jī)制是如何實(shí)現(xiàn)的呢?
延遲失效機(jī)制
延遲失效機(jī)制即當(dāng)客戶端請(qǐng)求操作某個(gè)key的時(shí)候,Redis會(huì)對(duì)客戶端請(qǐng)求操作的key進(jìn)行有效期檢查,如果key過期才進(jìn)行相應(yīng)的處理,延遲失效機(jī)制也叫消極失效機(jī)制。我們看看t_string組件下面對(duì)get請(qǐng)求處理的服務(wù)端端執(zhí)行堆棧:
getCommand -> getGenericCommand -> lookupKeyReadOrReply -> lookupKeyRead -> expireIfNeeded
關(guān)鍵的地方是expireIfNeed,Redis對(duì)key的get操作之前會(huì)判斷key關(guān)聯(lián)的值是否失效,這里先插入一個(gè)小插曲,我們看看Redis中實(shí)際存儲(chǔ)值的地方是什么樣子的:
typedef struct redisDb { dict *dict; /* The keyspace for this DB */ dict *expires; /* Timeout of keys with a timeout set */ dict *blocking_keys; /* Keys with clients waiting for data (BLPOP) */ dict *ready_keys; /* Blocked keys that received a PUSH */ dict *watched_keys; /* WATCHED keys for MULTI/EXEC CAS */ int id; long long avg_ttl; /* Average TTL, just for stats */} redisDb;
上面是Redis中定義的一個(gè)結(jié)構(gòu)體,dict是一個(gè)Redis實(shí)現(xiàn)的一個(gè)字典,也就是每個(gè)DB會(huì)包括上面的五個(gè)字段,我們這里只關(guān)心兩個(gè)字典,一個(gè)是dict,一個(gè)是expires:
dict是用來存儲(chǔ)正常數(shù)據(jù)的,比如我們執(zhí)行了set key "hahaha",這個(gè)數(shù)據(jù)就存儲(chǔ)在dict中。
expires使用來存儲(chǔ)關(guān)聯(lián)了過期時(shí)間的key的,比如我們?cè)谏厦娴幕A(chǔ)之上有執(zhí)行的expire key 1,這個(gè)時(shí)候就會(huì)在expires中添加一條記錄。
回過頭來看看expireIfNeeded的流程,大致如下:
從expires中查找key的過期時(shí)間,如果不存在說明對(duì)應(yīng)key沒有設(shè)置過期時(shí)間,直接返回。
如果是slave機(jī)器,則直接返回,因?yàn)镽edis為了保證數(shù)據(jù)一致性且實(shí)現(xiàn)簡(jiǎn)單,將緩存失效的主動(dòng)權(quán)交給Master機(jī)器,slave機(jī)器沒有權(quán)限將key失效。
如果當(dāng)前是Master機(jī)器,且key過期,則master會(huì)做兩件重要的事情:1)將刪除命令寫入AOF文件。2)通知Slave當(dāng)前key失效,可以刪除了。
master從本地的字典中將key對(duì)于的值刪除。
主動(dòng)失效機(jī)制
主動(dòng)失效機(jī)制也叫積極失效機(jī)制,即服務(wù)端定時(shí)的去檢查失效的緩存,如果失效則進(jìn)行相應(yīng)的操作。
我們都知道Redis是單線程的,基于事件驅(qū)動(dòng)的,Redis中有個(gè)EventLoop,EventLoop負(fù)責(zé)對(duì)兩類事件進(jìn)行處理:
一類是IO事件,這類事件是從底層的多路復(fù)用器分離出來的。
一類是定時(shí)事件,這類事件主要用來事件對(duì)某個(gè)任務(wù)的定時(shí)執(zhí)行。
看起來Redis的EventLoop和Netty以及JavaScript的EventLoop功能設(shè)計(jì)的大概類似,一方面對(duì)網(wǎng)絡(luò)I/O事件處理,一方面還可以做一些小任務(wù)。
為什么講到Redis的單線程模型,因?yàn)镽edis的主動(dòng)失效機(jī)制邏輯是被當(dāng)做一個(gè)定時(shí)任務(wù)來由主線程執(zhí)行的,相關(guān)代碼如下:
if(aeCreateTimeEvent(server.el, 1, serverCron, NULL, NULL) == AE_ERR) { redisPanic("Can't create the serverCron time event."); exit(1); }
serverCron就是這個(gè)定時(shí)任務(wù)的函數(shù)指針,adCreateTimeEvent將serverCron任務(wù)注冊(cè)到EventLoop上面,并設(shè)置初始的執(zhí)行時(shí)間是1毫秒之后。接下來,我們想知道的東西都在serverCron里面了。serverCron做的事情有點(diǎn)多,我們只關(guān)心和本篇內(nèi)容相關(guān)的部分,也就是緩存失效是怎么實(shí)現(xiàn)的,我認(rèn)為看代碼做什么事情,調(diào)用堆棧還是比較直觀的:
aeProcessEvents ->processTimeEvents ->serverCron -> databasesCron -> activeExpireCycle -> activeExpireCycleTryExpire
EventLoop通過對(duì)定時(shí)任務(wù)的處理,觸發(fā)對(duì)serverCron邏輯的執(zhí)行,最終之執(zhí)行key過期處理的邏輯,值得一提的是,activeExpireCycle邏輯只能由master來做。
更多redis知識(shí)請(qǐng)關(guān)注redis入門教程欄目。
以上就是關(guān)于Redis緩存失效機(jī)制的簡(jiǎn)略介紹,當(dāng)然詳細(xì)使用上面的不同還得要大家自己使用過才領(lǐng)會(huì)。如果想了解更多,歡迎關(guān)注億速云行業(yè)資訊頻道哦!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。