Redis過期數(shù)據(jù)的刪除策略詳解
1 介紹
Redis 是一個kv型數(shù)據(jù)庫,我們所有的數(shù)據(jù)都是存放在內(nèi)存中的,但是內(nèi)存是有大小限制的,不可能無限制的增量。想要把不需要的數(shù)據(jù)清理掉,一種辦法是直接刪除,這個咱們前面章節(jié)有詳細(xì)說過;另外一種就是設(shè)置過期時間,緩存過期后,由Redis系統(tǒng)自行刪除。這邊需要注意的是,緩存過期之后,并不是馬上刪除的,那Redis是怎么刪除過期數(shù)據(jù)的呢?主要通過兩個方式
- 惰性刪除
- 通過定時任務(wù),定期選取部分?jǐn)?shù)據(jù)刪除
2 Redis緩存過期命令
我們通過以下指令給指定key的緩存設(shè)置過期時間,如果都沒設(shè)置過期時間, key 將一直存在,直到我們使用 Del 的命令明確刪除掉。
# 緩存時間過期命令,參考如下 EXPIRE key seconds [ NX | XX | GT | LT]
Redis 7.0 開始,EXPIRE 添加了 NX、XX和GT、LT 選項,分別代表如下:
- NX:僅當(dāng)Key沒有過期時設(shè)置過期時間
- XX:僅當(dāng)Key已過期時設(shè)置過期時間
- GT:僅當(dāng)新到期時間大于當(dāng)前到期時間時設(shè)置到期時間
- LT:僅當(dāng)新到期時間小于當(dāng)前到期時間時設(shè)置到期時間
其中,GT、LT和NX選項是互斥的,下面是官方的測試用例:
redis> SET mykey "Hello" "OK" redis> EXPIRE mykey 10 (integer) 1 redis> TTL mykey (integer) 10 redis> SET mykey "Hello World" "OK" redis> TTL mykey (integer) -1 redis> EXPIRE mykey 10 XX (integer) 0 redis> TTL mykey (integer) -1 redis> EXPIRE mykey 10 NX (integer) 1 redis> TTL mykey (integer) 10
3 兩種過期數(shù)據(jù)的刪除方式
我們前面說過,Redis刪除過期數(shù)據(jù)主要通過以下兩個方式,我們一個個來看:
- 惰性刪除
- 通過定時任務(wù),定期選取部分?jǐn)?shù)據(jù)刪除
3.1 惰性刪除
惰性刪除比較簡單,當(dāng)客戶端請求過來查詢我們的key的時候,先對key做一下檢查,如果沒過期則返回緩存數(shù)據(jù),如果過期,則刪除緩存,重新從數(shù)據(jù)庫中獲取數(shù)據(jù)。這樣,我們就把刪除過期數(shù)據(jù)的主動權(quán)交給了訪問請求的客戶端,如果客戶端一直沒請求,那這個過期緩存可能就長時間得不到釋放。
Redis的源碼 src/db.c 中的 expireIfNeeded 方法 就是實現(xiàn)以上惰性刪除邏輯的,我們來看看:
int expireIfNeeded(redisDb *db, robj *key, int force_delete_expired) { // 對于未過期的key,直接 return 0 if (!keyIsExpired(db,key)) return 0; /* If we are running in the context of a slave, instead of * evicting the expired key from the database, we return ASAP: * the slave key expiration is controlled by the master that will * send us synthesized DEL operations for expired keys. * * Still we try to return the right information to the caller, * that is, 0 if we think the key should be still valid, 1 if * we think the key is expired at this time. */ if (server.masterhost != NULL) { if (server.current_client == server.master) return 0; if (!force_delete_expired) return 1; } /* If clients are paused, we keep the current dataset constant, * but return to the client what we believe is the right state. Typically, * at the end of the pause we will properly expire the key OR we will * have failed over and the new primary will send us the expire. */ if (checkClientPauseTimeoutAndReturnIfPaused()) return 1; /* Delete the key */ deleteExpiredKeyAndPropagate(db,key); return 1; }
3.2 定期刪除
剛才前面說過了,僅靠客戶端訪問來對過期緩存執(zhí)行刪除遠(yuǎn)遠(yuǎn)不夠,因為有的 key 過期了,但客戶端一直沒請求,那這個過期緩存可能就長時間甚至永遠(yuǎn)得不到釋放。所以除了惰性刪除,Redis 還可以通過定時任務(wù)的方式來刪除過期的數(shù)據(jù)。定時任務(wù)的發(fā)起的頻率由redis.conf配置文件中的hz來進(jìn)行配置
# 代表每1s 運行 10次 hz 10
Redis 默認(rèn)每 1 秒運行 10 次,也就是每 100 ms 執(zhí)行一次,每次隨機(jī)抽取一些設(shè)置了過期時間的 key(這邊注意不是檢查所有設(shè)置過期時間的key,而是隨機(jī)抽取部分),檢查是否過期,如果發(fā)現(xiàn)過期了就直接刪除。該定時任務(wù)的具體流程如下:
- 定時serverCron方法去執(zhí)行清理,執(zhí)行頻率根據(jù)redis.conf中的hz配置的值
- 執(zhí)行清理的時候,不是去掃描所有的key,而是去掃描所有設(shè)置了過期時間的key(redisDb.expires)
- 如果每次去把所有過期的key都拿過來,那么假如過期的key很多,就會很慢,所以也不是一次性拿取所有的key
- 根據(jù)hash桶的維度去掃描key,掃到20(可配)個key為止。假如第一個桶是15個key ,沒有滿足20,繼續(xù)掃描第二個桶,第二個桶20個key,由于是以hash桶的維度掃描的,所以第二個掃到了就會全掃,總共掃描35個key
- 找到掃描的key里面過期的key,并進(jìn)行刪除
- 刪除完檢查過期的 key 超過 25%,繼續(xù)執(zhí)行4、5步
其他注意點:
- 為何不掃描所有key進(jìn)行過期緩存元素刪除:Redis本身就是高速緩存,如果每次檢查大量的key,無論在CPU和內(nèi)存的的使用率上都會特別高,Redis集群越大,風(fēng)險越大。
- 分片模式下的刪除同步:無論定時刪除還是惰性刪除。master 會生成刪除的指令記錄到 AOF 和 slave 節(jié)點。
到此這篇關(guān)于Redis過期數(shù)據(jù)的刪除策略的文章就介紹到這了,更多相關(guān)Redis刪除策略內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
redis-copy使用6379端口無法連接到Redis服務(wù)器的問題
這篇文章主要介紹了redis-copy使用6379端口無法連接到Redis服務(wù)器的問題的相關(guān)資料,需要的朋友可以參考下2023-05-05關(guān)于Redis最常見的十道面試題總結(jié)大全
Redis作為一個高性能的內(nèi)存數(shù)據(jù)存儲系統(tǒng),具有快速讀寫、持久性、數(shù)據(jù)結(jié)構(gòu)多樣性等特點,廣泛應(yīng)用于各種應(yīng)用場景,這篇文章主要給大家介紹了關(guān)于Redis最常見的十道面試題總結(jié)的相關(guān)資料,需要的朋友可以參考下2024-07-07redis3.2配置文件redis.conf詳細(xì)說明
redis3.2配置詳解,Redis啟動的時候,可以指定配置文件,詳細(xì)說明請看本文說明2018-03-03