深入了解Redis(5)-內存回收

  • 2020 年 9 月 23 日
  • 筆記

  了解redis內存回收之前,需要先了解過期鍵刪除策略。

過期鍵刪除策略

1.定時刪除

  在設置鍵的過期時間的同時,創建一個timer,在定時器在鍵的過期時間到達時,立即執行對鍵的刪除操作。內存友好型策略,一旦鍵過期,就會被刪除,並釋放所佔用的內存,Cpu 不友好,當一批數量比較多的鍵過期時,正好遇上Cpu 緊張的時段,這時候需要的是Cpu處理能力,而不是內存。另外當前 Redis 時間事件(無序鏈表O(N))無法高效處理大量時間事件,所以定時刪除並不是一種好的定時刪除策略。

2.惰性刪除

  不管過期的鍵,在這種策略下,當鍵在鍵空間中被取出時,首先檢查取出的鍵是否過期,若過期刪除該鍵,否則,返回該鍵。很明顯,惰性刪除依賴過期鍵的被動訪問,對於內存不友好,如果
一些鍵長期沒有被訪問,會造成內存泄露。redis非常依賴內存,所以這也不是一個很好的策略。

3.定期刪除

  每隔一段時間,程序就對數據庫進行一次檢查,刪除裏面的過期鍵。至於要刪除多少過期鍵,以及要檢查多少個數據庫, 則由算法決定。

 

  目前redis採用的是定期刪除+惰性刪除策略。定期刪除,redis默認每個100ms檢查,是否有過期的key,有過期key則刪除。需要說明的是,redis不是每個100ms將所有的key檢查一次,而是隨機抽取進行檢查(如果每隔100ms,全部key進行檢查,redis豈不是卡死)。因此,如果只採用定期刪除策略,會導致很多key到時間沒有刪除。
於是,惰性刪除派上用場。也就是說在你獲取某個key的時候,redis會檢查一下,這個key如果設置了過期時間那麼是否過期了?如果過期了此時就會刪除。但是存在一種情況如果定期刪除沒刪除key。然後你也沒即時去請求key,也就是說惰性刪除也沒生效。這樣,redis的內存會越來越高。那麼就應該採用內存淘汰機制

 

內存淘汰策略

名稱 描述
volatile-lru 已設置過期時間的數據集中挑選最近最少使用的數據淘汰
volatile-lfu 從已設置過期時間的數據集中挑選最不經常使用的數據淘汰
volatile-ttl 從已設置過期時間的數據集中挑選將要過期的數據淘汰
volatile-random 從已設置過期時間的數據集中挑選任意數據淘汰
allkeys-lru 當內存不足寫入新數據時淘汰最近最少使用的Key
allkeys-random 當內存不足寫入新數據時隨機選擇key淘汰
allkeys-lfu 當內存不足寫入新數據時移除最不經常使用的Key
no-eviction 當內存不足寫入新數據時,寫入操作會報錯,同時不刪除數據
  • volatile為前綴的策略都是從已過期的數據集中進行淘汰。
  • allkeys為前綴的策略都是面向所有key進行淘汰。
  • LRU(least recently used)最近最少用到的。
  • LFU(Least Frequently Used)最不常用的。
  • 它們的觸發條件都是Redis使用的內存達到閾值時。

  因為 C 語言並不具備自動的內存回收功能, 所以 Redis 在自己的對象系統中構建了一個引用計數技術實現的內存回收機制, 通過這一機制, 程序可以通過跟蹤對象的引用計數信息, 在適當的時候自動釋放對象並進行內存回收。

typedef struct redisObject {

    // ...

    // 引用計數
    int refcount;

    // ...

} robj;

對象的引用計數信息會隨着對象的使用狀態而不斷變化:

  • 在創建一個新對象時, 引用計數的值會被初始化為 1 ;
  • 當對象被一個新程序使用時, 它的引用計數值會被增一;
  • 當對象不再被一個程序使用時, 它的引用計數值會被減一;
  • 當對象的引用計數值變為 0 時, 對象所佔用的內存會被釋放。