聊聊 Redis 的過時鍵刪除策略

文章首發於公衆號:蘑菇睡不着,歡迎來看看

前言

  Redis 中都是鍵值對的存儲形式,鍵都是字符串類型的,而值有不少種類型,如 string、list、hash、set、sorted set等類型。當設置鍵值對時咱們還應該爲其設置過時時間,經過 expire 以及 pexpire 命令;還能夠經過 setnx 命令設置。那麼,當設置過時時間以後,究竟是怎麼將過時的鍵值對刪除的那?想知道答案的話,咱們就一塊兒看看 Redis 的過時鍵刪除策略。
  在說刪除策略以前有個點帶你們先了解下,那就是若是肯定一個鍵是否過時,這裏我總結了下: redis

1) 檢查這個鍵是否在過時字典中,若是存在,那麼取出這個鍵的過時時間。(過時字典存儲的是每一個鍵的過時時間,字典中 key 是 鍵, value 是 long 類型的過時時間)
2) 拿到過時時間以後,和當前 UNIX 時間戳比較,若是大於,則鍵過時。數據庫

以上就是判斷一個鍵是否過時的方法。接下來講說當鍵過時了怎麼去刪除。 服務器

目前來講有三種刪除策略:函數

  • 定時刪除:在設置鍵的過時時間時,建立一個定時器,當到達鍵過時時間時經過定時器去刪除鍵
  • 惰性刪除:惰性刪除並非當到達過時時間時去刪除,而是每次獲取鍵時,會判斷是否過時,若是過時則刪除,並返回空;沒過時,就返回鍵值
  • 按期刪除:每隔一段時間,就對數據庫中的鍵進行檢查,若是過時則刪除。至於要刪除多少何時刪除,則是經過具體程序決定

下面來詳細介紹每一種刪除策略。學習

定時刪除

定時刪除策略
優勢是:對內存友好。由於經過定時器,當一個鍵到達過時時間時就會立馬被刪除,直接就釋放了內存。
缺點是:對 CPU 不友好。由於若是過時鍵比較多,那麼刪除這些過時鍵會佔用至關一部分CPU時間,若是CPU時間很是緊張的話,還將CPU時間用在刪除和當前任務無關的過時鍵上,會對服務器的響應時間以及吞吐量形成影響。
所以,經過 定時刪除 策略來時間過時鍵的刪除不太現實。ip

惰性刪除

惰性刪除策略優勢:對 CPU 時間友好。程序只會在取出鍵時纔會判斷是否刪除,而且只做用到當前鍵上,其餘過時鍵不會花費 CPU 時間去處理。
惰性刪除策略缺點:對內存不友好。由於只有鍵被使用時纔會去檢查是否刪除,若是有大量的鍵一直不被使用,那麼這些鍵就算過時了也不會被刪除,會一直佔用着內存。這種能夠理解爲是一種內存泄漏——大量無用的數據一直佔用着內存,而且不會被刪除。內存

按期刪除

相比較定時刪除對CPU的不友好,惰性刪除的對內存不友好。按期刪除採用了一種折中的方式:字符串

  • 按期刪除策略每隔一段時間執行一次刪除過時鍵操做,並經過限制刪除操做執行的時長和頻率來減小刪除操做對CPU時間的影響。
  • 而且,經過按期刪除過時鍵,有效的減小了過時鍵帶來的內存浪費。

但刪除的時長和頻率比較難定義,由於:同步

  • 若是頻率過高或者時長太長,那麼會佔用大量的CPU時長。
  • 若是太短又會出現內存浪費的狀況。

所以。若是採用按期刪除策略的話須要經過具體的業務場景來定義時長和頻率。string

Redis實際使用的是惰性刪除+按期刪除的策略。

經過這兩種方式能夠很好的利用CPU時間以及避免內存浪費的狀況。接下來說講惰性刪除以及按期刪除的實現。

惰性刪除策略的實現

惰性刪除策略由 expireIfNeeded 函數實現,全部讀寫數據庫的 Redis 命令在執行以前都會調用 exipreIfNeeded 函數對輸入鍵進行檢查。

  • 若是鍵過時,會將鍵刪除並返回空。
  • 若是鍵沒有過時,則不作操做。

按期刪除策略的實現

按期刪除策略由 activeExpireCucle 函數實現,被調用時,它在規定的時間內,分屢次遍歷服務器中的各個數據庫,從數據庫的 expires 字典中隨機檢查一部分鍵的過時時間,並刪除其中的過時鍵。

  • 函數每次運行時,都是從必定數量的數據庫鍵中隨機取必定數量的鍵進行檢查,並刪除其中的過時鍵。
  • 有一個全局變量 current_db 會記錄當前 activeExpireCycle 函數檢查的進度,而且下一次 函數執行時,接着上一次的進度進行處理。如,當前 activeExpireCycle 函數執行到了 10, 講 current_db = 10;而後下一次函數執行時,從 current_db 取到 10 繼續執行。
  • 當全部的數據庫鍵都被檢查完時, current_db = 0。

AOF、RDB 和複製功能對過時鍵的處理

生成 RDB 文件

  在執行 SAVE 命令或 BGSAVE 命令建立一個新的 RDB 文件時,程序會對數據庫中的鍵進行檢查,已過時的鍵不會被保存到新的 RDB 文件中。
  如:redis中包含 r一、r二、r3 三個鍵,而且 r1 已通過期,那麼程序只會講 r2 和 r3 保存到 RDB 文件中。
  所以,過時鍵不會對新的 RDB 文件形成影響。

載入 RDB 文件

  在啓動 redis 服務器時,若是服務器開啓了 RDB 功能,那麼服務器將對 RDB 文件進行載入;

  • 若是服務器以主服務器模式運行,那麼在載入 RDB 文件時,過時的鍵會被過濾掉,不會被載入到redis數據庫中。
  • 若是以從服務器模式運行,那麼不管鍵是否過時都會被載入到數據庫中。但,由於主從服務器在進行數據同步時,從服務器就會被清空,因此,通常來講,過時鍵對從服務器也不會形成影響。

AOF 文件寫入

  當服務器開啓 AOF 的運行模式時,若是某個鍵過時了,但沒有被惰性或按期刪除,那麼 AOF 不會理會。若是被惰性或按期刪除了, AOF 會在文件末尾追加一條 DEL 命令,來顯示地記錄該鍵已被刪除。

AOF 重寫

  當 AOF 重寫時,過時的鍵不會被載入到 redis 數據庫中。

複製

  當服務器在 複製 模式下時,從服務器的過時鍵刪除動做都是由主服務器來進行的。

  • 主服務器在刪除一個過時鍵以後,會顯示地向全部從服務器發送一個 DEL 命令,告知從服務器刪除這個過時鍵。
  • 從服務器在執行客戶端發送的讀命令時,即便碰到過時的鍵也不會刪除,而是繼續的正常操做。
  • 從服務器只有在接到主服務器發來的 DEL 命令以後,纔會刪除過時鍵。

最後

Redis 的過時鍵刪除策略是 惰性刪除 + 按期刪除,這也既能夠合理的控制 CPU 使用 還能夠 減小內存的浪費。

關於更多 Java 知識以及刷題分享,能夠來公衆號 蘑菇睡不着 看看,你們一塊兒學習。

你越主動就會越主動,咱們下期見~

相關文章
相關標籤/搜索