Redis內存回收機制主要體現在以下兩個方面:
- 刪除到達時間的鍵對象。
- 內存使用達到maxmemory上限時觸發內存溢出控制策略。
1.刪除過期鍵對象
Redis所有的鍵都可以設置過期屬性,內部保存在過期字典中。由于進程內保存了大量的鍵,維護每個鍵精準的過期刪除機制會導致消耗大量的CPU,對于單線程的Redis來說成本過高,因此Redis采用惰性刪除和定時任務刪除機制實現過期鍵的內存回收。
- 惰性刪除:惰性刪除用于當客戶端讀取帶有超時屬性的鍵時,如果已經超過鍵設置的過期時間,會執行刪除操作并返回空,這種策略是出于節省CPU成本考慮,不需要單獨維護TTL鏈表來處理過期鍵的刪除。但是單獨用這種方式存在內存泄露的問題,當過期鍵一直沒有訪問將無法得到及時刪除,從而導致內存不能及時釋放。正因為如此,Redis還提供另一種定時任務刪除機制作為惰性刪除的補充。
- 定時任務刪除:Redis內部維護一個定時任務,默認每秒運行10次(通過配置hz控制)。定時任務中刪除過期鍵邏輯采用了自適應算法,根據鍵的過期比例,使用快慢兩種速率模式回收鍵。
比如:
- 定時任務在每個數據庫空間隨機檢查20個鍵,當發現過期時刪除對應的鍵。
- 如果超過檢查數25%的鍵過期,循環執行回收邏輯直到不足25%或運行超時為止,慢模式下超時時間為25ms。
- 如果之前回收鍵邏輯超時,則在Redis觸發內部事件之前再次以快模式運行回收過期鍵任務,快模式下超時時間為1ms且2s內只能運行1次。
- 快慢兩種模式內部刪除邏輯相同,只是執行的超時時間不同。
2. 內存溢出控制策略
當Redis所用內存達到maxmemory上限時會觸發相應的溢出控制策略。具體策略受maxmemory-policy參數控制,Redis支持6種策略,如下所示:
- noeviction:默認策略,當內存不足以容納新寫入數據時,新寫入操作會報錯。應該沒人用吧。
- allkeys-lru:當內存不足以容納新寫入數據時,在鍵空間中,移除最近最少使用的 Key。推薦使用,目前項目在用這種。
- allkeys-random:當內存不足以容納新寫入數據時,在鍵空間中,隨機移除某個 Key。應該也沒人用吧,你不刪最少使用 Key,去隨機刪。
- volatile-lru:當內存不足以容納新寫入數據時,在設置了過期時間的鍵空間中,移除最近最少使用的 Key。這種情況一般是把 Redis 既當緩存,又做持久化存儲的時候才用。不推薦。
- volatile-random:當內存不足以容納新寫入數據時,在設置了過期時間的鍵空間中,隨機移除某個 Key。依然不推薦。
- volatile-ttl:當內存不足以容納新寫入數據時,在設置了過期時間的鍵空間中,有更早過期時間的 Key 優先移除。不推薦。如果沒有對應的鍵,則回退到noeviction策略。