Redis (REmote DIctionary Server) 是一個由Salvatore Sanfilippo寫的key-value存儲系統。
Redis過期鍵刪除策略
redisDb 結果的 expires 字典保存了數據庫中所有鍵的過期時間,我們稱這個字典爲過期字典
- 過期字典的鍵是一個指針,這個指針指向鍵空間的某個鍵對象
-
過期字典的值是一個 long long 類型的證書,用於保存毫秒精度的 UNIX 時間戳
過期鍵刪除策略的三種方案
- 定時刪除: 在設置鍵的過期時間的同時,創建一個定時器,讓定時器執行對鍵的刪除操作
- 惰性刪除: 每次取的時候先判斷 expires 對象裏面的鍵是否已經過期,如果過期,則刪除鍵,否則,返回該鍵
- 定期刪除: 每隔一段時間,程序對數據庫遍歷檢查一遍,然後刪除過期的鍵
定時刪除
定時刪除策略對內存最友好,通過使用定時器,定時刪除策略可以保證鍵在過期時間一定會被刪除,刪除後就釋放該鍵之前佔用的內存。但是,定時刪除策略的缺點是,它對 CPU 時間是最不友好的,在過期鍵比較多的情況下,刪除過期鍵這一行爲可能會佔用相當一部分 CPU 時間,在內存不緊張但是 CPU 時間非常緊張的情況下,將大量 CPU 時間浪費在刪除過期的策略上,而不是用在處理客戶端的請求上,毫無疑問是不行的。
惰性刪除
通過定時刪除的描述,你可能會想那用惰性刪除就最好了,這樣就不會浪費 CPU 時間,每次取數據的時候才判斷,如果過期才刪除它,這樣就能騰出大量的 CPU 去處理客戶端請求了。然而,這對內存卻又是最不友好的,因爲這種策略並不能保證所有鍵一定會訪問到,比如說一些取得並不頻繁的數據,就會大量堆積在內存中,如果這些內存得不到釋放,可想而知後果是多麼嚴重。
從上面兩種情況看來,這兩種刪除的方式單一使用的過程都有明顯的缺陷:
- 定時刪除佔用過多 CPU 時間,影響服務器的響應時間和吞吐量。
- 惰性刪除浪費過多內存,有內存泄露的風險
定期策略是兩種策略的一種折中辦法: - 定期策略每隔一段時間執行一次刪除過期的操作,並通過
限制刪除操作執行的時長和頻率
來減少刪除操作對CPU 時間的影響 - 定期刪除過期鍵能有效的減少過期鍵而造成的內存浪費
但是,這個問題點在於如何設定刪除操作執行的時長和頻率
?設置的太頻繁吧,就又跟定時刪除一樣,浪費大量CPU,設置得長一點吧,這又可能出現內存大量堆積。
Redis所使用的過期刪除策略
Redis實際上使用的是惰性刪除和定期刪除兩種策略,通過配合使用,服務器可以很好的平衡 CPU 和內存。
-
惰性刪除策略的實現
每次取數據的時候都會調用過濾函數(db.c/expireIfNeeded),該函數主要用來判斷鍵是否過期,如果過期,則刪除鍵,否則,則取得對應鍵的值。image.png
定期刪除鍵的策略實現
過期鍵的定期刪除策略由 redis.c/activeExpireCycle
函數實現,每當 Redis 的服務器週期性操作 redis.c/serverCron
函數執行時, activeExpireCycle 函數就會被調用,它在規定的時間內分多次遍歷服務器的各個數據庫,檢查數據庫的 expires 字典中部分鍵(相當於分頁查詢)的過期時間,並刪除它。步驟如下:
- 函數每次運行時,都從一定數量的數據庫取出一定數量的隨機鍵進行檢查,並刪除其中的過期鍵。
- 全局變量 current_db 會記錄當前 activeExpireCycle 函數的檢查進度,並在下一次 activeExpireCycle 調用時,接着上一次的進度進行處理。
- 隨着 activeExpireCycle 函數的不斷執行,服務器中的所有數據庫都會被檢查一遍,當到達最後時,把 current_db 設置爲 0,然後又重新開始,如此循環下去。