快取的有效期和淘汰策略
有效期 TTL (Time to live)
設定有效期的作用:
- 節省空間
- 做到資料弱一致性,有效期失效後,可以保證資料的一致性
Redis的過期策略
過期策略通常有以下三種:
-
定時過期
每個設定過期時間的key都需要建立一個定時器,到過期時間就會立即清除。該策略可以立即清除過期的資料,對記憶體很友好;但是會佔用大量的CPU資源去處理過期的資料,從而影響快取的響應時間和吞吐量。
setex('a', 300, 'aval') setex('b', 600, 'bval')
-
惰性過期
只有當訪問一個key時,才會判斷該key是否已過期,過期則清除。該策略可以最大化地節省CPU資源,卻對記憶體非常不友好。極端情況可能出現大量的過期key沒有再次被訪問,從而不會被清除,佔用大量記憶體。
-
定期過期
每隔一定的時間,會掃描一定數量的資料庫的expires字典中一定數量的key,並清除其中已過期的key。該策略是前兩者的一個折中方案。通過調整定時掃描的時間間隔和每次掃描的限定耗時,可以在不同情況下使得CPU和記憶體資源達到最優的平衡效果。
expires字典會儲存所有設定了過期時間的key的過期時間資料,其中,key是指向鍵空間中的某個鍵的指標,value是該鍵的毫秒精度的UNIX時間戳表示的過期時間。鍵空間是指該Redis叢集中儲存的所有鍵。
Redis中同時使用了惰性過期和定期過期兩種過期策略。
Redis過期刪除採用的是定期刪除,預設是每100ms檢測一次,遇到過期的key則進行刪除,這裡的檢測並不是順序檢測,而是隨機檢測。那這樣會不會有漏網之魚?顯然Redis也考慮到了這一點,當我們去讀/寫一個已經過期的key時,會觸發Redis的惰性刪除策略,直接回幹掉過期的key
為什麼不用定時刪除策略?
定時刪除,用一個定時器來負責監視key,過期則自動刪除。雖然記憶體及時釋放,但是十分消耗CPU資源。在大併發請求下,CPU要將時間應用在處理請求,而不是刪除key,因此沒有采用這一策略.
定期刪除+惰性刪除是如何工作的呢?
定期刪除,redis預設每個100ms檢查,是否有過期的key,有過期key則刪除。需要說明的是,redis不是每個100ms將所有的key檢查一次,而是隨機抽取進行檢查(如果每隔100ms,全部key進行檢查,redis豈不是卡死)。因此,如果只採用定期刪除策略,會導致很多key到時間沒有刪除。
於是,惰性刪除派上用場。也就是說在你獲取某個key的時候,redis會檢查一下,這個key如果設定了過期時間那麼是否過期了?如果過期了此時就會刪除。
採用定期刪除+惰性刪除就沒其他問題了麼?
不是的,如果定期刪除沒刪除key。然後你也沒即時去請求key,也就是說惰性刪除也沒生效。這樣,redis的記憶體會越來越高。那麼就應該採用記憶體淘汰機制。
快取淘汰 eviction
Redis自身實現了快取淘汰
Redis的記憶體淘汰策略是指在Redis的用於快取的記憶體不足時,怎麼處理需要新寫入且需要申請額外空間的資料。
- noeviction:當記憶體不足以容納新寫入資料時,新寫入操作會報錯。
- allkeys-lru:當記憶體不足以容納新寫入資料時,在鍵空間中,移除最近最少使用的key。
- allkeys-random:當記憶體不足以容納新寫入資料時,在鍵空間中,隨機移除某個key。
- volatile-lru:當記憶體不足以容納新寫入資料時,在設定了過期時間的鍵空間中,移除最近最少使用的key。
- volatile-random:當記憶體不足以容納新寫入資料時,在設定了過期時間的鍵空間中,隨機移除某個key。
- volatile-ttl:當記憶體不足以容納新寫入資料時,在設定了過期時間的鍵空間中,有更早過期時間的key優先移除。
redis 4.x 後支援LFU策略,最少頻率使用
-
allkeys-lfu
-
volatile-lfu
LRU
LRU(Least recently used,最近最少使用)
LRU演算法根據資料的歷史訪問記錄來進行淘汰資料,其核心思想是“如果資料最近被訪問過,那麼將來被訪問的機率也更高”。
基本思路
-
新資料插入到列表頭部;
-
每當快取命中(即快取資料被訪問),則將資料移到列表頭部;
-
當列表滿的時候,將列表尾部的資料丟棄。
LFU
LFU(Least Frequently Used 最近最少使用演算法)
它是基於“如果一個數據在最近一段時間內使用次數很少,那麼在將來一段時間內被使用的可能性也很小”的思路。
LFU需要定期衰減。
Redis淘汰策略的配置
-
maxmemory最大使用記憶體數量
-
maxmemory-policy noeviction 淘汰策略