參考博客1
參考博客2
Redis 是可以通過 expire 設(shè)置過期時間的,但是如果一個鍵過期了,那什么時候被刪除呢?
1.過期策略
有三種過期策略:定時刪除,惰性刪除,定期刪除。策略雖有三種,但是 redis 只用了后兩種。
1.1. 定時刪除
在設(shè)置鍵的過期時間的同時,創(chuàng)建一個定時器,讓定時器在鍵的過期時間來臨時,立即執(zhí)行對鍵的刪除操作。(創(chuàng)建定時器刪除)
優(yōu)點:
1、對內(nèi)存最友好:通過使用定時器,可以保證過期的鍵會盡可能快地被刪除,釋放所占內(nèi)存
缺點:
1、對cpu最不友好:在過期鍵比較多的情況下,刪除過期鍵這一行為可能會占用相當(dāng)一部分cpu的時間,對服務(wù)器的響應(yīng)時間和吞吐量造成影響。
1.2. 惰性刪除
放任鍵的過期不管,但是每次從鍵空間中獲取鍵時,都檢查取得的鍵是否過期,如果過期的話,就刪除該鍵;如果沒有過期,就返回該鍵。(使用的時候刪除)
優(yōu)點:
1、對cpu最友好:只有在取出鍵的時候才會對過期鍵進行檢查,即不需要cpu定期掃描,也不需要創(chuàng)建大量的定時器。
缺點:
1、對內(nèi)存最不友好:如果一個鍵已經(jīng)過期,但是后面不會被訪問到的話,那么就一直保留在數(shù)據(jù)庫中。如果這樣的鍵過多,無疑會占用很大的內(nèi)存。
1.3. 定期刪除
每隔一段時間,程序就對數(shù)據(jù)庫進行一次檢查,刪除里面過期的鍵。至于要刪除多少過期鍵,以及要檢查多少個數(shù)據(jù)庫,則有算法決定。(定期掃描刪除)
定期刪除是上面的定時刪除和惰性刪除的一中折中方案。
優(yōu)點:
1、定期刪除每隔一段時間執(zhí)行一次過期鍵操作,并通過限制刪除操作執(zhí)行的時長和頻率來減少刪除操作對cpu時間的影響。
2、通過刪除過期鍵,能有效的減少因為過期鍵而帶來的內(nèi)存浪費
缺點:
難以確定刪除操作執(zhí)行的時長和頻率
1、如果刪除操作執(zhí)行得太頻繁,或者執(zhí)行的時間太長,定期刪除策略就會退化成定時刪除,以至于占用太多cpu的執(zhí)行時間。
2、如果刪除操作執(zhí)行的時間太少,或執(zhí)行時間太短,定期刪除策略又會和惰性刪除一樣,出現(xiàn)內(nèi)存浪費。
2. redis 的過期策略
redis 使用了三種過期刪除策略的后兩種,惰性刪除(被動刪除) 和 定期刪除(主動刪除)。
1.惰性刪除
只有key被操作時(如GET),REDIS才會被動檢查該key是否過期,如果過期則刪除之并且返回NIL。
過期鍵的惰性刪除刪除策略由db.c/expireIfNeeded函數(shù)實現(xiàn),所有讀寫數(shù)據(jù)庫的Redis命令在執(zhí)行之前都會調(diào)用expireIfNeed函數(shù)對輸入鍵進行檢查:如果鍵已經(jīng)過期,那么expireIfNeeded函數(shù)將鍵刪除;如果鍵未過期,那么expireIfNeeded函數(shù)不做操作
2.主動刪除
主動刪除也分為兩種情況,一種是定期,一種是內(nèi)存占用量超過閾值觸發(fā)
2.1 定期
過期鍵的定期刪除策略由redis.c/activeExpireCycle函數(shù)實現(xiàn),每當(dāng)Redis的服務(wù)器周期性操作redis.c/serverCron函數(shù)執(zhí)行時,activeExpireCycle函數(shù)就會被調(diào)用,它在規(guī)定時間內(nèi),分多次遍歷服務(wù)器中各個數(shù)據(jù)庫。
Redis 默認每秒進行 10 次過期掃描,過期掃描不會遍歷過期字典中所有的 key, 而是采用了一種簡單的貪心策略,步驟如下。
(1)從過期字典中隨機選出 100個 key。
(2)刪除這 100 個 key 中已經(jīng)過期的 key。
(3)如果過期的 key的比例超過 1/4,那就重復(fù)步驟 (1)。 同時,為了保證過期掃描不會出現(xiàn)循環(huán)過度,導(dǎo)致結(jié)程卡死的現(xiàn)象,算法還增加了掃描時間的上限,默認不會超過 25ms。
在 Redis 2.6 版本中, 程序規(guī)定 serverCron 每秒運行 10 次, 平均每 100 毫秒運行一次。 從 Redis 2.8 開始, 用戶可以通過修改 hz 選項來調(diào)整 serverCron 的每秒執(zhí)行次數(shù), 具體信息請參考 redis.conf 文件中關(guān)于 hz 選項的說明
2.2 內(nèi)存閾值觸發(fā)
當(dāng)前已用內(nèi)存超過maxmemory限定時,觸發(fā)主動清理策略
volatile-lru:只對設(shè)置了過期時間的key進行LRU(默認值,Least Recently Used的縮寫,即最近最少使用)
allkeys-lru : 刪除lru算法的key
volatile-random:隨機刪除即將過期key
allkeys-random:隨機刪除
volatile-ttl : 刪除即將過期的
noeviction : 永不過期,返回錯誤當(dāng)mem_used內(nèi)存已經(jīng)超過maxmemory的設(shè)定,對于所有的讀寫請求,都會觸發(fā)redis.c/freeMemoryIfNeeded(void)函數(shù)以清理超出的內(nèi)存。注意這個清理過程是阻塞的,直到清理出足夠的內(nèi)存空間。所以如果在達到maxmemory并且調(diào)用方還在不斷寫入的情況下,可能會反復(fù)觸發(fā)主動清理策略,導(dǎo)致請求會有一定的延遲。
當(dāng)mem_used內(nèi)存已經(jīng)超過maxmemory的設(shè)定,對于所有的讀寫請求,都會觸發(fā)redis.c/freeMemoryIfNeeded(void)函數(shù)以清理超出的內(nèi)存。注意這個清理過程是阻塞的,直到清理出足夠的內(nèi)存空間。所以如果在達到maxmemory并且調(diào)用方還在不斷寫入的情況下,可能會反復(fù)觸發(fā)主動清理策略,導(dǎo)致請求會有一定的延遲。
清理時會根據(jù)用戶配置的maxmemory-policy來做適當(dāng)?shù)那謇恚ㄒ话闶荓RU或TTL),這里的LRU或TTL策略并不是針對redis的所有key,而是以配置文件中的maxmemory-samples個key作為樣本池進行抽樣清理。