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

前言

Redis緩存淘汰策略與Redis鍵的過時刪除策略並不徹底相同,前者是在Redis內存使用超過必定值的時候(通常這個值能夠配置)使用的淘汰策略;然後者是經過按期刪除+惰性刪除二者結合的方式進行內存淘汰的。緩存,不是存儲,沒法保證之前設置的緩存絕對存在。由於緩存容量是有上限的,即便set值的時候不設置過時時間,在內存不夠的時候,會根據內存淘汰策略刪除一些緩存。設置過時時間的key是如何刪除的?過時後會當即釋放內存嗎?redis

過時刪除策略

  • 按期刪除

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時間友好方面,不如"惰性刪除"
難點:合理設置刪除操做的執行時長(每次刪除執行多長時間)和執行頻率(每隔多長時間作一次刪除),這個要根據服務器運行狀況來定了dom

  • 惰性刪除

過時的key並不必定會立刻刪除,還會佔用着內存。 當你真正查詢這個key時,redis會檢查一下,這個設置了過時時間的key是否過時了? 若是過時了就會刪除,返回空。這就是惰性刪除。ide

優勢:刪除操做只發生在從數據庫取出key的時候發生,並且只刪除當前key,因此對CPU時間的佔用是比較少的,並且此時的刪除是已經到了非作不可的地步(若是此時還不刪除的話,咱們就會獲取到了已通過期的key了)
缺點:若大量的key在超出超時時間後,好久一段時間內,都沒有被獲取過,那麼可能發生內存泄露(無用的垃圾佔用了大量的內存)性能

  • 定時刪除

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

優勢:保證內存被儘快釋放
缺點:若過時key不少,刪除這些key會佔用不少的CPU時間,在CPU時間緊張的狀況下,CPU不能把全部的時間用來作要緊的事兒,還須要去花時間刪除這些key,定時器的建立耗時,若爲每個設置過時時間的key建立一個定時器(將會有大量的定時器產生),性能影響嚴重
結論:此方法基本上沒人用spa

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;
    }
}