Redis緩存失效的故事要從EXPIRE這個命令提及,EXPIRE容許用戶爲某個key指定超時時間,當超過這個時間以後key對應的值會被清除,這篇文章主要在分析Redis源碼的基礎上站在Redis設計者的角度去思考Redis緩存失效的相關問題。redis
Redis緩存失效機制是爲應對緩存應用的一種很常見的場景而設計的,講個場景:數據庫
咱們爲了減輕後端數據庫的壓力,很開心的藉助Redis服務把變化頻率不是很高的數據從DB load出來放入了緩存,所以以後的一段時間內咱們均可以直接從緩存上拿數據,然而咱們又但願一段時間以後,咱們再從新的從DB load出當前的數據放入緩存,這個事情怎麼作呢?
問題提出來了,這個問題怎麼解決呢?好吧,咱們對於手頭的語言工具很熟悉,堅信能夠很快的寫出這麼一段邏輯:咱們記錄上次從db load數據的時間,而後每次響應服務的時候都去判斷時間是否是過時了,要不要從db從新load了……。固然這種方法也是能夠的,然而當咱們查閱Redis command document的時候,發現咱們作了原本不須要作的事情,Redis自己提供這種機制,咱們只要藉助EXPIRE命令就能夠輕鬆的搞定這件事情:後端
EXPIRE key 30
上面的命令即爲key設置30秒的過時時間,超過這個時間,咱們應該就訪問不到這個值了,到此爲止咱們大概明白了什麼是緩存失效機制以及緩存失效機制的一些應用場景,接下來咱們繼續深刻探究這個問題,Redis緩存失效機制是如何實現的呢?緩存
延遲失效機制即當客戶端請求操做某個key的時候,Redis會對客戶端請求操做的key進行有效期檢查,若是key過時才進行相應的處理,延遲失效機制也叫消極失效機制。咱們看看t_string組件下面對get請求處理的服務端端執行堆棧:網絡
getCommand -> getGenericCommand -> lookupKeyReadOrReply -> lookupKeyRead -> expireIfNeeded
關鍵的地方是expireIfNeed,Redis對key的get操做以前會判斷key關聯的值是否失效,這裏先插入一個小插曲,咱們看看Redis中實際存儲值的地方是什麼樣子的:函數
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中定義的一個結構體,dict是一個Redis實現的一個字典,也就是每一個DB會包括上面的五個字段,咱們這裏只關心兩個字典,一個是dict,一個是expires:工具
回過頭來看看expireIfNeeded的流程,大體以下:oop
主動失效機制也叫積極失效機制,即服務端定時的去檢查失效的緩存,若是失效則進行相應的操做。this
咱們都知道Redis是單線程的,基於事件驅動的,Redis中有個EventLoop,EventLoop負責對兩類事件進行處理:spa
看起來Redis的EventLoop和Netty以及JavaScript的EventLoop功能設計的大概相似,一方面對網絡I/O事件處理,一方面還能夠作一些小任務。
爲何講到Redis的單線程模型,由於Redis的主動失效機制邏輯是被當作一個定時任務來由主線程執行的,相關代碼以下:
if(aeCreateTimeEvent(server.el, 1, serverCron, NULL, NULL) == AE_ERR) { redisPanic("Can't create the serverCron time event."); exit(1); }
serverCron就是這個定時任務的函數指針,adCreateTimeEvent將serverCron任務註冊到EventLoop上面,並設置初始的執行時間是1毫秒以後。接下來,咱們想知道的東西都在serverCron裏面了。serverCron作的事情有點多,咱們只關心和本篇內容相關的部分,也就是緩存失效是怎麼實現的,我認爲看代碼作什麼事情,調用堆棧仍是比較直觀的:
aeProcessEvents ->processTimeEvents ->serverCron -> databasesCron -> activeExpireCycle -> activeExpireCycleTryExpire
EventLoop經過對定時任務的處理,觸發對serverCron邏輯的執行,最終之執行key過時處理的邏輯,值得一提的是,activeExpireCycle邏輯只能由master來作。
Redis對緩存失效的處理機制大概分爲兩種,一種是客戶端訪問key的時候消極的處理,一種是主線程按期的積極地去執行緩存失效清理邏輯,上面文章對於一些細節尚未展開介紹,可是對於Redis緩存失效實現機制這個話題,本文留下幾個問題:
《Redis源碼》