【Redis】過期鍵刪除策略和記憶體淘汰策略

cooper發表於2021-12-05

Redis 過期鍵策略和記憶體淘汰策略

設定Redis鍵過期時間

Redis有四個不同的命令來設定生存時間(鍵可以存在多久)或過期時間(鍵什麼時候會被刪除)。

EXPIRE <key> <ttl> :表示將鍵 key 的生存時間設定為 ttl 秒。

PEXPIRE <key> <ttl> :表示將鍵 key 的生存時間設定為 ttl 毫秒。

EXPIREAT <key> <timestamp> :表示將鍵 key 的生存時間設定為 timestamp 所指定的秒數時間戳。

PEXPIREAT <key> <timestamp> :表示將鍵 key 的生存時間設定為 timestamp 所指定的毫秒數時間戳。

在Redis內部實現中,前面三個設定過期時間的命令都會轉換成最後一個PEXPIREAT命令來完成。

 另外補充兩個知識點:

  一、移除鍵的過期時間

  PERSIST :表示將key的過期時間移除。

  二、返回鍵的剩餘生存時間

  TTL :以秒的單位返回鍵 key 的剩餘生存時間。

  PTTL :以毫秒的單位返回鍵 key 的剩餘生存時間。


Redis過期時間的判定

  在Redis內部,每當我們設定一個鍵的過期時間時,Redis就會將該鍵帶上過期時間存放到一個過期字典中。過期字典的鍵是一個指標,指向鍵空間某個鍵物件,值是一個long long型別的整數,這個整數儲存了鍵所指向的資料庫鍵的過期時間--一個毫秒精度的UNIX時間戳。

當我們查詢一個鍵時,Redis便首先檢查該鍵是否存在過期字典中,如果存在,那就獲取其過期時間。然後將過期時間和當前系統時間進行比對,比系統時間大,那就沒有過期;反之判定該鍵過期。

過期鍵刪除策略

定時刪除

  在設定某個key 的過期時間同時,我們建立一個定時器,讓定時器在該過期時間到來時,立即執行對其進行刪除的操作。

  優點:定時刪除對記憶體是最友好的,能夠儲存記憶體的key一旦過期就能立即從記憶體中刪除。

  缺點:對CPU最不友好,在過期鍵比較多的時候,刪除過期鍵會佔用一部分 CPU 時間,對伺服器的響應時間和吞吐量造成影響。


惰性刪除

  設定該key 過期時間後,我們不去管它,當需要該key時,我們在檢查其是否過期,如果過期,我們就刪掉它,反之返回該key。

  優點:對 CPU友好,我們只會在使用該鍵時才會進行過期檢查,對於很多用不到的key不用浪費時間進行過期檢查。

  缺點:對記憶體不友好,如果一個鍵已經過期,但是一直沒有使用,那麼該鍵就會一直存在記憶體中,如果資料庫中有很多這種使用不到的過期鍵,這些鍵便永遠不會被刪除,記憶體永遠不會釋放。甚至可以把這種情況看成是一種記憶體洩漏。


定期刪除

 每隔一段時間,我們就對一些key進行檢查,刪除裡面過期的key。

  優點:可以通過限制刪除操作執行的時長和頻率來減少刪除操作對 CPU 的影響。另外定期刪除,也能有效釋放過期鍵佔用的記憶體。

  缺點:難以確定刪除操作執行的時長和頻率。

     如果執行的太頻繁,定期刪除策略變得和定時刪除策略一樣,對CPU不友好。

     如果執行的太少,那又和惰性刪除一樣了,過期鍵佔用的記憶體不會及時得到釋放。

     另外最重要的是,在獲取某個鍵時,如果某個鍵的過期時間已經到了,但是還沒執行定期刪除,那麼就會返回這個鍵的值,這是業務不能忍受的錯誤。


Redis過期刪除策略

Redis的過期刪除策略是:惰性刪除定期刪除 兩種策略配合使用。

惰性刪除: Redis的惰性刪除策略由 db.c/expireIfNeeded 函式實現,所有鍵讀寫命令執行之前都會呼叫expireIfNeeded 函式對其進行檢查,如果過期,則刪除該鍵,然後執行鍵不存在的操作;未過期則不作操作,繼續執行原有的命令。

 定期刪除:由redis.c/activeExpireCycle 函式實現,函式以一定的頻率執行,每次執行時,都從一定數量的資料庫中取出一定數量的隨機鍵進行檢查,並刪除其中的過期鍵。

注意:並不是一次執行就檢查所有的庫,所有的鍵,而是隨機檢查一定數量的鍵。

通過過期刪除策略,對於某些永遠使用不到的鍵,並且多次定期刪除也沒有選定並刪除,那麼這些鍵同樣會一直駐留在記憶體中,又或者在Redis中存入了大量的鍵,這些操作可能導致Redis記憶體不夠用,這時候就需要Redis的記憶體淘汰策略了。


記憶體淘汰策略

設定Redis最大記憶體

  在配置檔案redis.conf 中,可以通過引數 maxmemory 來設定最大記憶體:

img

不設定該引數預設是無限制的,但是通常會設定其為實體記憶體的四分之三。


設定記憶體淘汰方式

 當現有記憶體大於 maxmemory 時,便會觸發redis主動淘汰記憶體方式,通過設定 maxmory-policy :

img


有如下幾種淘汰方式

  1. noeviction: 不移除任何key,只是返回一個寫錯誤 ,預設選項,一般不會選用。
  2. volatile-lru:利用LRU演算法移除設定過過期時間的最近最少使用的key 。這種情況一般是把 Redis 既當快取,又做持久化儲存的時候才用,不推薦。
  3. allkeys-lru:利用LRU演算法移除最近最少使用的key(包括設定過期時間和不設定過期時間的)通常使用該方式
  4. allkeys-random:當記憶體不足以容納新寫入資料時,在鍵空間中,隨機移除某個 Key,不推薦。
  5. volatile-random:當記憶體不足以容納新寫入資料時,在設定了過期時間的鍵空間中,隨機移除某個 Key。依然不推薦。
  6. volatile-ttl : 移除即將過期的key。

參考:

《Redis設計與實現》

相關文章