Redis 鍵的過期刪除策略及緩存淘汰策略


前言

Redis緩存淘汰策略與Redis鍵的過期刪除策略並不完全相同,前者是在Redis內存使用超過一定值的時候(一般這個值可以配置)使用的淘汰策略;而后者是通過定期刪除+惰性刪除兩者結合的方式進行內存淘汰的。緩存,不是存儲,無法保證以前設置的緩存絕對存在。因為緩存容量是有上限的,即使set值的時候不設置過期時間,在內存不夠的時候,會根據內存淘汰策略刪除一些緩存。設置過期時間的key是如何刪除的?過期后會立即釋放內存嗎?

過期刪除策略

  • 定期刪除

Redis過期Key清理的機制對清理的頻率和最大時間都有限制,在盡量不影響正常服務的情況下,進行過期Key的清理,以達到長時間服務的性能最優。redis會把設置了過期時間的key放在單獨的字典中,每隔一段時間執行一次刪除(在redis.conf配置文件設置hz,1s刷新的頻率)過期key的操作。

具體的算法如下:

  1. Redis配置項hz定義了serverCron任務的執行周期,默認為10,即CPU空閑時每秒執行10次;
  2. 每次過期key清理的時間不超過CPU時間的25%,即若hz=1,則一次清理時間最大為250ms,若hz=10,則一次清理時間最大為25ms;
  3. 清理時依次遍歷所有的db;
  4. 從db中隨機取20個key,判斷是否過期,若過期,則逐出;
  5. 若有5個以上key過期,則重復步驟4,否則遍歷下一個db;
  6. 在清理過程中,若達到了25%CPU時間,退出清理過程;

這是一個基於概率的簡單算法,基本的假設是抽出的樣本能夠代表整個key空間,redis持續清理過期的數據直至將要過期的key的百分比降到了25%以下。這也意味着在長期來看任何給定的時刻已經過期但仍占據着內存空間的key的量最多為每秒的寫操作量除以4。

  • 由於算法采用的隨機取key判斷是否過期的方式,故幾乎不可能清理完所有的過期Key;
  • 調高hz參數可以提升清理的頻率,過期key可以更及時的被刪除,但hz太高會增加CPU時間的消耗,為了保證不會循環過度,導致卡頓,掃描時間上限默認不超過25ms。

根據以上原理,系統中應避免大量的key同時過期,給要過期的key設置一個隨機范圍。

優點:通過限制刪除操作的時長和頻率,來減少刪除操作對CPU時間的占用,處理"定時刪除"的缺點,定期刪除過期key,處理"惰性刪除"的缺點
缺點:在內存友好方面,不如"定時刪除" 在CPU時間友好方面,不如"惰性刪除"
難點:合理設置刪除操作的執行時長(每次刪除執行多長時間)和執行頻率(每隔多長時間做一次刪除),這個要根據服務器運行情況來定了

  • 惰性刪除

過期的key並不一定會馬上刪除,還會占用着內存。 當你真正查詢這個key時,redis會檢查一下,這個設置了過期時間的key是否過期了? 如果過期了就會刪除,返回空。這就是惰性刪除。

優點:刪除操作只發生在從數據庫取出key的時候發生,而且只刪除當前key,所以對CPU時間的占用是比較少的,而且此時的刪除是已經到了非做不可的地步(如果此時還不刪除的話,我們就會獲取到了已經過期的key了)
缺點:若大量的key在超出超時時間后,很久一段時間內,都沒有被獲取過,那么可能發生內存泄露(無用的垃圾占用了大量的內存)

  • 定時刪除

在設置key的過期時間的同時,為該key創建一個定時器,讓定時器在key的過期時間來臨時,對key進行刪除。

優點:保證內存被盡快釋放
缺點:若過期key很多,刪除這些key會占用很多的CPU時間,在CPU時間緊張的情況下,CPU不能把所有的時間用來做要緊的事兒,還需要去花時間刪除這些key,定時器的創建耗時,若為每一個設置過期時間的key創建一個定時器(將會有大量的定時器產生),性能影響嚴重
結論:此方法基本上沒人用

Redis采用的過期策略

  • 惰性刪除+定期刪除

持久化對過期key的處理

  • RDB對過期key的處理

過期key對RDB沒有任何影響

1)從內存數據庫持久化數據到RDB文件,持久化key之前,會檢查是否過期,過期的key不進入RDB文件

2)從RDB文件恢復數據到內存數據庫,數據載入數據庫之前,會對key先進行過期檢查,如果過期,不導入數據庫(主庫情況)

  • AOF對過期key的處理

過期key對AOF沒有任何影響

1)從內存數據庫持久化數據到AOF文件:當key過期后,還沒有被刪除,此時進行執行持久化操作(該key是不會進入aof文件的,因為沒有發生修改命令)當key過期后,在發生刪除操作時,程序會向aof文件追加一條del命令(在將來的以aof文件恢復數據的時候該過期的鍵就會被刪掉)

2)AOF重寫:重寫時,會先判斷key是否過期,已過期的key不會重寫到aof文件

內存淘汰策略

當redis內存超出物理內存限制時,會和磁盤產生swap,這種情況性能極差,一般是不允許的。通過設置 maxmemory 限制最大使用內存。超出限制時,根據redis提供的幾種內存淘汰機制讓用戶自己決定如何騰出新空間以提供正常的讀寫服務。

  • noeviction:當內存使用超過配置的時候會返回錯誤,不會驅逐任何鍵(默認策略,不建議使用)
  • allkeys-lru:加入鍵的時候,如果過限,首先通過LRU算法驅逐最久沒有使用的鍵
  • volatile-lru:加入鍵的時候如果過限,首先從設置了過期時間的鍵集合中驅逐最久沒有使用的鍵(不建議使用)
  • allkeys-random:加入鍵的時候如果過限,從所有key隨機刪除
  • volatile-random:加入鍵的時候如果過限,從過期鍵的集合中隨機驅逐(不建議使用)
  • volatile-ttl:從配置了過期時間的鍵中驅逐馬上就要過期的鍵
  • volatile-lfu:從所有配置了過期時間的鍵中驅逐使用頻率最少的鍵
  • allkeys-lfu:從所有鍵中驅逐使用頻率最少的鍵

LRU算法實現

public class LRUCache<K,V> extends LinkedHashMap<K,V> {
    private int cacheSize;
    public LRUCache(int cacheSize){
        super(10,0.75f,true);
        //設置hashmap大小,true是讓linkedhashmap按照訪問順序排序
        this.cacheSize = cacheSize;
    }

    @Override
    protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
        //當map中數量大於指定緩存個數的時候,自動刪除最老的數據
        return size()>cacheSize;
    }
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM