Redis作爲內存型數據庫,在業務量過大的情況下,會出現內存不夠的情況(達到[maxmemory]設置值),當然機器內存足夠強大,數據可承受範圍會更大,但是這不是解決問題的方法。
Redis提供了兩種解決方法:
關於設置數據的超時時間這個方法,是我們經常用到的,同時設置超時時間還可以在某些場景下滿足我們的業務需要:
但是有沒有想過TTL的過期策略是什麼呢?
redis的過期策略分爲:定期刪除 和 惰性刪除
定期刪除
Redis會將每個設置了過期時間的 key 放入到一個獨立的字典中,以後會定期遍歷這個字典來刪除到期的 key。
Redis 默認會每秒進行十次過期掃描(100ms一次),過期掃描不會遍歷過期字典中所有的 key,而是採用了一種簡單的貪心策略:
這裏隨機抽取就是爲了在數據量過大的情況下,遍歷大量的key,給CPU增加負擔
惰性刪除
惰性刪除就是在客戶端訪問這個key的時候,redis對key的過期時間進行檢查,如果過期了就立即刪除,不會給你返回任何東西。通常情況下我們在日常的使用過程中查詢已經過期的key,是比較容易觸發該機制的。
定期刪除是從比較大的層面做key的過期刪除,因爲其隨機性,導致會有過期key不能及時刪除的情況發生,惰性刪除是在某些情況下對定期刪除的一種彌補策略。
什麼是LRU算法?
Redis使用的是近似LRU算法:近似LRU算法通過隨機採樣法淘汰數據,每次隨機出5(默認)個key,從裏面淘汰掉最近最少使用的key,可以通過maxmemory-samples參數修改採樣數量: 例:maxmemory-samples 10 maxmenory-samples配置的越大,淘汰的結果越接近於嚴格的LRU算法,但是同時對內存的消耗也越大。
Redis使用近似LRU算法,在基本滿足策略需要的情況,儘可能的降低了內存的消耗,CPU的佔用,在硬件滿足的情況的下,也可以通過maxmemory-samples的調整,無線接近於標準LRU算法。
Redis爲了實現近似LRU算法,給每個key增加了一個額外增加了一個24bit的字段,用來存儲該key最後一次被訪問的時間。
Redis3.0對近似LRU算法進行了一些優化。新算法會維護一個候選池(大小爲16),池中的數據根據訪問時間進行排序,第一次隨機選取的key都會放入池中,隨後每次隨機選取的key只有在訪問時間小於池中最小的時間纔會放入池中,直到候選池被放滿。當放滿後,如果有新的key需要放入,則將池中最後訪問時間最大(最近被訪問)的移除。當需要淘汰的時候,則直接從池中選取最近訪問時間最小(最久沒被訪問)的key淘汰掉就行。
1. noeviction:當內存使用超過配置的時候會返回錯誤,不會驅逐任何鍵
2. allkeys-lru:加入鍵的時候,如果過限,首先通過LRU算法驅逐最久沒有使用的鍵
3. volatile-lru:加入鍵的時候如果過限,首先從設置了過期時間的鍵集合中驅逐最久沒有使用的鍵
4. allkeys-random:加入鍵的時候如果過限,從所有key隨機刪除
5. volatile-random:加入鍵的時候如果過限,從過期鍵的集合中隨機驅逐
6. volatile-ttl:從配置了過期時間的鍵中驅逐馬上就要過期的鍵
7. volatile-lfu:從所有配置了過期時間的鍵中驅逐使用頻率最少的鍵(Reidis4之後)
8. allkeys-lfu:從所有鍵中驅逐使用頻率最少的鍵(Reidis4之後)
LFU是在Redis4.0後出現的,LRU的最近最少使用實際上並不精確,考慮下面的情況,如果在|處刪除,那麼A距離的時間最久,但實際上A的使用頻率要比B頻繁,所以合理的淘汰策略應該是淘汰B。LFU就是爲應對這種情況而生的。
A~~A~~A~~A~~A~~A~~A~~A~~A~~A~~~|
B~~~~~B~~~~~B~~~~~B~~~~~~~~~~~~B|
參考:
https://zhuanlan.zhihu.com/p/105587132
https://www.cnblogs.com/vegetableDD/p/11890570.html
https://www.bilibili.com/video/BV1Cb411j7RA?p=8
https://segmentfault.com/a/1190000017555834