Redis過(guò)期數(shù)據(jù)是否會(huì)被立馬刪除
引言
當(dāng) key 達(dá)到過(guò)期時(shí)間,Redis 就會(huì)馬上刪除么?
先說(shuō)結(jié)論:并不會(huì)立馬刪除。
Redis 有兩種刪除過(guò)期數(shù)據(jù)的策略:
- 定期選取部分?jǐn)?shù)據(jù)刪除;
- 惰性刪除;
該命令在 Redis 2.4 版本,過(guò)期時(shí)間并不是很精確,它可能在零到一秒之間。
從 Redis 2.6 開始,過(guò)期錯(cuò)誤為 0 到 1 毫秒。
EXPIRE key seconds [ NX | XX | GT | LT]
指令可以將指定的 key 設(shè)置過(guò)期時(shí)間,如果沒(méi)有設(shè)置過(guò)期時(shí)間, key 將一直存在,除非我們明確將其刪除,比如執(zhí)行 DEL
指令。
所謂”狡兔死,走狗烹“,沒(méi)用了就干掉,跟 35 歲就“畢業(yè)”是一個(gè)道理。
好慌……
從 Redis 版本 7.0.0 開始:EXPIRE
添加了選項(xiàng):NX
、XX
和GT
、LT
選項(xiàng)。
- NX:當(dāng) key 沒(méi)有過(guò)期時(shí)才設(shè)置過(guò)期時(shí)間;
- XX:只有 key 已過(guò)期的時(shí)候才設(shè)置過(guò)期時(shí)間;
- GT:僅當(dāng)新的到期時(shí)間大于當(dāng)前到期時(shí)間時(shí)才設(shè)置過(guò)期時(shí)間;
- LT:僅在新到期時(shí)間小于當(dāng)前到期時(shí)間才設(shè)置到過(guò)期時(shí)間。
過(guò)期與持久化
?主從或者集群架構(gòu)中,兩臺(tái)機(jī)器的時(shí)鐘嚴(yán)重不同步,會(huì)有什么問(wèn)題么?
key 過(guò)期信息是用 Unix 絕對(duì)時(shí)間戳表示的。
為了讓過(guò)期操作正常運(yùn)行,機(jī)器之間的時(shí)間必須保證穩(wěn)定同步,否則就會(huì)出現(xiàn)過(guò)期時(shí)間不準(zhǔn)的情況。
比如兩臺(tái)時(shí)鐘嚴(yán)重不同步的機(jī)器發(fā)生 RDB 傳輸, slave 的時(shí)間設(shè)置為未來(lái)的 2000 秒,假如在 master 的一個(gè) key 設(shè)置 1000 秒存活,當(dāng) Slave 加載 RDB 的時(shí)候 key 就會(huì)認(rèn)為該 key 過(guò)期(因?yàn)?slave 機(jī)器時(shí)間設(shè)置為未來(lái)的 2000 s),并不會(huì)等待 1000 s 才過(guò)期。
機(jī)器時(shí)鐘不同步導(dǎo)致過(guò)期混亂
惰性刪除
惰性刪除很簡(jiǎn)單,就是當(dāng)有客戶端的請(qǐng)求查詢?cè)?nbsp;key
的時(shí)候,檢查下 key
是否過(guò)期,如果過(guò)期,則刪除該 key
。
比如當(dāng) Redis 收到客戶端的GET movie:小澤#瑪……利亞.rmvb
請(qǐng)求,就會(huì)先檢查 key = movie:小澤#瑪……利亞.rmvb
是否已經(jīng)過(guò)期,如果過(guò)期那就刪除。
刪除過(guò)期數(shù)據(jù)的主動(dòng)權(quán)交給了每次訪問(wèn)請(qǐng)求。
該實(shí)現(xiàn)通過(guò) expireIfNeeded
函數(shù)實(shí)現(xiàn),源碼路徑:src/db.c
。
int?expireIfNeeded(redisDb?*db,?robj?*key,?int?force_delete_expired)?{ ???//?key?沒(méi)有過(guò)期,return?0 ????if?(!keyIsExpired(db,key))?return?0; ????if?(server.masterhost?!=?NULL)?{ ????????if?(server.current_client?==?server.master)?return?0; ????????if?(!force_delete_expired)?return?1; ????} ????if?(checkClientPauseTimeoutAndReturnIfPaused())?return?1; ????/*?Delete?the?key?*/ ????deleteExpiredKeyAndPropagate(db,key); ????return?1; }
定期刪除
僅僅靠客戶端訪問(wèn)來(lái)判斷 key 是否過(guò)期才執(zhí)行刪除肯定不夠,因?yàn)橛械?key 過(guò)期了,但未來(lái)再也沒(méi)人訪問(wèn),這些數(shù)據(jù)要怎么刪除呢?
不能讓這些數(shù)據(jù)「占著茅坑不拉屎」。
所謂定期刪除,也就是 Redis 默認(rèn)每 1 秒運(yùn)行 10 次(每 100 ms 執(zhí)行一次),每次隨機(jī)抽取一些設(shè)置了過(guò)期時(shí)間的 key,檢查是否過(guò)期,如果發(fā)現(xiàn)過(guò)期了就直接刪除。
注意:并不是一次運(yùn)行就檢查所有的庫(kù),所有的鍵,而是隨機(jī)檢查一定數(shù)量的鍵。
具體步驟如下:
定時(shí)刪除
- 從所有設(shè)置了過(guò)期時(shí)間的 key 集合中隨機(jī)選擇 20 個(gè) key;
- 刪除「步驟 1」發(fā)現(xiàn)的所有過(guò)期 key 數(shù)據(jù);
- 「步驟 2 」結(jié)束,過(guò)期的 key 超過(guò) 25%,則繼續(xù)執(zhí)行「步驟 1」。
刪除的源碼 expire.c 的 activeExpireCycle 函數(shù)實(shí)現(xiàn)。
這也就意味著在任何時(shí)候,過(guò)期 key 的最大數(shù)量等于每秒最大寫入操作量除以 4。
?為啥不檢查所有設(shè)置過(guò)期時(shí)間的 key?
你想呀,假設(shè) Redis 里存放了 100 w 個(gè) key,都設(shè)置了過(guò)期時(shí)間,每隔 100 毫秒就檢查 100 w 個(gè) key,CPU 全浪費(fèi)在檢查過(guò)期 key 上了,Redis 也就廢了。
注意了:不管是定時(shí)刪除,還是惰性刪除。當(dāng)數(shù)據(jù)刪除后,master
會(huì)生成刪除的指令記錄到 AOF
和 slave
節(jié)點(diǎn)。
碼哥,如果過(guò)期的數(shù)據(jù)太多,定時(shí)刪除無(wú)法刪除完全(每次刪除完過(guò)期的 key 還是超過(guò) 25%),同時(shí)這些 key 也再也不會(huì)被客戶端請(qǐng)求,也就是無(wú)法走惰性刪除,會(huì)怎樣?
會(huì)不會(huì)導(dǎo)致 Redis 內(nèi)存耗盡,怎么破?
這個(gè)問(wèn)題問(wèn)得好,答案是走內(nèi)存淘汰機(jī)制。
以上就是Redis過(guò)期數(shù)據(jù)是否會(huì)被立馬刪除的詳細(xì)內(nèi)容,更多關(guān)于Redis過(guò)期數(shù)據(jù)的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
基于 Redis 的 JWT令牌失效處理方案(實(shí)現(xiàn)步驟)
當(dāng)用戶登錄狀態(tài)到登出狀態(tài)時(shí),對(duì)應(yīng)的JWT的令牌需要設(shè)置為失效狀態(tài),這時(shí)可以使用基于Redis 的黑名單方案來(lái)實(shí)現(xiàn)JWT令牌失效,本文給大家分享基于 Redis 的 JWT令牌失效處理方案,感興趣的朋友一起看看吧2024-03-03淺談我是如何用redis做實(shí)時(shí)訂閱推送的
這篇文章主要介紹了淺談我是如何用redis做實(shí)時(shí)訂閱推送的,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-03-03Redis操作相關(guān)命令之查看、停止、啟動(dòng)命令
這篇文章主要介紹了Redis操作相關(guān)命令之查看、停止、啟動(dòng)命令,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-09-09