談談redis的過期刪除策略與內存淘汰機制

今天這邊主要說說redis內存的過期刪除策略與內存淘汰機制。

1,刪除策略

對於redis中設置了過期時間的key,我們知道對於時間到期了,這個key就會被 “刪除”,但是這個key真的是一到期就會馬上被刪除嗎?

  1. 定時刪除
    就是對於沒個key設置一個定時器,這種方式比較簡單,效果也比較好,一旦定時器計時結束,直接刪除這個key。但是唯一致命缺點就是需要維護大量定時器,cpu消耗會非常高,費性能。

  2. 惰性刪除
    這個也比較好理解,就是在我們get(key)的時候,先去判斷下這個key的過期時間,如果過期了,直接刪掉然後返回null。但是這個也會產生問題,比如我的key一直沒人用,那麼就一直不會被刪除,那麼就可能會佔用大量的redis的工作內存。

  3. 定期刪除

3.1 redis在啓動的時候讀取配置文件hz的值,默認爲10
在這裏插入圖片描述

3.2 每秒執行hz次serverCron()–>databasesCron()—>actveEXpireCyle()這三個方法,嵌套執行:

serverCron():掃描redis服務的api
databasesCron():循環掃描redis服務下每個db的api,一個redis默認情況下爲16個db
actveEXpireCyle():循環掃描每個db下面的有過期時間的key然後做相關清除操作

3.3 actveEXpireCyle()對每個expires[*]進行逐一檢測,每次執行250ms/hz

250爲每秒執行serverCron()的總時間,如果你用默認配置,那麼每次執行就是隻有25ms,如果到了25ms執行未結束也強制return,等待下一次掃描。

3.4 對某個expires[*]檢測時,隨機挑選N個key檢查

如果key超時,刪除key
如果一輪中刪除的key的數量>N*25%,說明這個db內的過期的key比較多,需要再次循環該過程執行刪除操作,依次類推
如果一輪中刪除的key的數量小於等於N25%,檢查下一個expires[ ]
current_db用於記錄actveEXpireCyle()進入哪個expires[ * ]
執行,如果時間到了,那麼下次根據current_db繼續執行

redis採用的是惰性刪除和定期刪除結合使用。

2, 淘汰機制

現在來看一個問題,如果redis的內存滿了怎麼辦,首先最容易想到的就是數據不讓進了,直接報錯?

下面來看這幾個配置:

# 指定Redis最大內存限制,Redis在啓動時會把數據加載到內存中,達到最大內存後,Redis會先嚐# 試清除已到期或即將到期的Key,
# 當此方法處理後,仍然到達最大內存設置,將無法再進行寫入操作,但仍然可以進行讀取操作。
# Redis新的vm機制,會把Key存放內存,Value會存放在swap區
# 佔用物理內存的比例,默認值爲0,,表示不限制。生產環境一般根據需求設置,通常50%以上
# maxmemory <bytes>

# The default is:
#當內存使用達到最大值時,redis使用的清除策略。有以下幾種可以選擇(明明有6種,官方配置文件裏卻說有5種可以選擇?):
# 1)volatile-lru   利用LRU算法移除設置過過期時間的key (LRU:最近使用 Least Recently Used ) 
# 2)allkeys-lru   利用LRU算法移除任何key 
# 3)volatile-lfu  利用lfu算法移除設置過期時間的key(lfu:最先被使用的,就是最久沒被使用過的)
# 4)allkeys-lfu  利用lfu算法移除任何key 
# 5)volatile-random 移除設置過過期時間的隨機key 
# 6)allkeys-random  移除隨機key 
# 7)volatile-ttl   移除即將過期的key(minor TTL) 
# 8)noeviction  不移除任何key,只是返回一個寫錯誤 。默認選項
# maxmemory-policy noeviction

# true LRU but costs more CPU. 3 is faster but not very accurate.
# LRU 和 minimal TTL 算法都不是精準的算法,但是相對精確的算法(爲了節省內存),隨意你可以選擇樣本大小進行檢測。redis默認選擇5個樣本進行檢測,你可以通過maxmemory-samples進行設置樣本數。
# maxmemory-samples 5

關於淘汰策略,這邊可以大致分爲兩類+1:
+1:noeviction 不使用任何策略,其實對於淘汰策略怎麼用都不好,比如你一個正在使用的熱點key,被淘汰機制誤刪除了,很明顯對於系統又很大的影響,而且如果對於沒有持久化的key,或者對於分佈式鎖中的lock key,刪除的話都會導致一連串系統問題。所以有不使用刪除策略,直接報錯是最好的選擇。當然前提是有相應的監控機制以及足夠的物理內存。
第一種:volatile開頭的,針對的淘汰目標是所有設置了過期時間的key
第二種:allkeys開頭的是針對所有的key

在這裏插入圖片描述
關於lru和lfu算法,可見上圖:
在指定時間內,比如我5秒,有三個key (key1,key2,key3),每次調用都會記錄一個調用時間,以及給他的調用次數+1
如果採用lru淘汰算法,則淘汰調用次數最少的,如上圖的話,可以見key2在5秒內被調用了一次,其他兩種都使用了兩次,那麼如果採用此算法,key2會被淘汰
如果採用lfu算法,則淘汰最長時間沒被使用的,可以見上面最久之前沒被使用的,是key2,4s前被使用,如果採用此算法,則key2會被淘汰。

可見:
lru算法更關注調用頻次,認爲key使用次數越多,則這個key爲活躍key,則不建議淘汰。
lfu算法更關注調用時間,認爲key越長時間沒被使用,認爲這個key是不活躍的key,建議優先淘汰。

關於redis緩存的過期刪除及內存淘汰機制基本上就上述這些!

發佈了47 篇原創文章 · 獲贊 97 · 訪問量 6萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章