Redis過期策略及實現原理-Redis面試題

haicoder_ibai發表於2021-04-03

本文參考 嗨客網 Redis面試題

Redis面試題 Redis過期策略及實現原理

描述

我們在使用 Redis 時,一般會設定一個過期時間,當然也有不設定過期時間的,也就是永久不過期。當我們設定了過期時間,Redis 是如何判斷是否過期,以及根據什麼策略來進行刪除的。

redis過期時間設定

語法

EXPIRE KEY time

SETEX KEY_NAME TIMEOUT VALUE

說明

除了 字串 自己獨有設定過期時間的方法外,其他方法都需要依靠 EXPIRE 方法來設定時間,如果沒有設定時間,那快取就是永不過期。

如果設定了過期時間,之後又想讓快取永不過期,使用 persist KEY

三種過期策略

定時刪除

含義

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

優點

該方法可以保證記憶體被儘快釋放。

缺點

若過期 KEY 很多,刪除這些 KEY 會佔用很多的 CPU 時間,在 CPU 時間緊張的情況下,CPU 不能把所有的時間用來做要緊的事兒,還需要去花時間刪除這些 KEY。

定時器的建立耗時,若為每一個設定過期時間的 KEY 建立一個定時器(將會有大量的定時器產生),效能影響嚴重。

懶漢式刪除

含義

KEY 過期的時候不刪除,每次通過 KEY 獲取值的時候去檢查是否過期,若過期,則刪除,返回 null。

優點

刪除操作只發生在通過 KEY 取值的時候,而且只刪除當前 KEY,所以對 CPU 時間的佔用是比較少的,而且此時的刪除是已經到了非做不可的地步(如果此時還不刪除的話,我們就會獲取到了已經過期的 KEY 了)。

缺點

若大量的 KEY 在超出超時時間後,很久一段時間內,都沒有被獲取過,那麼可能發生記憶體洩露(無用的垃圾佔用了大量的記憶體)。

定期刪除

含義

每隔一段時間執行一次刪除過期 KEY 操作。

優點

通過限制刪除操作的時長和頻率,來減少刪除操作對 CPU 時間的佔用。

缺點

在記憶體友好方面,不如 ”定時刪除”(會造成一定的記憶體佔用,但是沒有懶漢式那麼佔用記憶體),在 CPU 時間友好方面,不如 ”懶漢式刪除”(會定期的去進行比較和刪除操作,cpu 方面不如懶漢式,但是比定時好)。

難點是合理設定刪除操作的執行時長(每次刪除執行多長時間)和執行頻率(每隔多長時間做一次刪除)(這個要根據伺服器執行情況來定了),每次執行時間太長,或者執行頻率太高對 cpu 都是一種壓力。每次進行定期刪除操作執行之後,需要記錄遍歷迴圈到了哪個標誌位,以便下一次定期時間來時,從上次位置開始進行迴圈遍歷。

說明

memcached 只是用了惰性刪除,而 redis 同時使用了惰性刪除與定期刪除,這也是二者的一個不同點(可以看做是 redis 優於 memcached 的一點)。

對於懶漢式刪除而言,並不是只有獲取 KEY 的時候才會檢查 KEY 是否過期,在某些設定 KEY 的方法上也會檢查,比如 SETNEX 命令,因為 SETNX 命令是在 KEY 不存在的情況下才設定,因為,如果不做過期 KEY 檢查,那麼直接設定,就會與我們原來的意思相違背。

定時任務

單執行緒的 redis,如何知道要執行定時任務?

redis 是單執行緒的,執行緒不但要處理定時任務,還要處理客戶端請求,執行緒不能阻塞在定時任務或處理客戶端請求上,那麼,redis 是如何知道何時該執行定時任務的呢?

Redis 的定時任務會記錄在一個稱為最小堆的資料結構中。這個堆中,最快要執行的任務排在堆的最上方。在每個迴圈週期,Redis 都會將最小堆裡面已經到點的任務立即進行處理。處理完畢後,將最快要執行的任務還需要的時間記錄下來,這個時間就是接下來處理客戶端請求的最大時長,若達到了該時長,則暫時不處理客戶端請求而去執行定時任務。

配置

Redis 中定期刪除使用的是統一的一個定時器,定時器執行的時長預設為 10,具體配置如下:

嗨客網(www.haicoder.net)

提高它的值將會佔用更多的 cpu,當然相應的 redis 將會更快的處理同時到期的許多 key,以及更精確的去處理超時。 hz 的取值範圍是 1~500,通常不建議超過 100,只有在請求延時非常低的情況下可以將值提升到 100。

Redis採用的過期策略

說明

Redis 採用的是懶漢式刪除+定期刪除。

懶漢式刪除流程

  1. 在進行 GET 或 SETNX 等操作時,先檢查 KEY 是否過期;

  2. 若過期,刪除 KEY,然後執行相應操作;

  3. 若沒過期,直接執行相應操作;

定期刪除流程

簡單而言,對指定 N 個庫的每一個庫隨機刪除小於等於指定 M 個過期 KEY,具體流程如下:

  1. 遍歷每個資料庫(就是 redis.conf 中配置的 ”database” 數量,預設為 16)

  2. 檢查當前庫中的指定個數個 KEY(預設是每個庫檢查 20 個 KEY,注意相當於該迴圈執行 20 次,迴圈體是下邊的描述)

  3. 如果當前庫中沒有一個 KEY 設定了過期時間,直接執行下一個庫的遍歷隨機

  4. 獲取一個設定了過期時間的 KEY,檢查該 KEY 是否過期,如果過期,刪除 KEY 判斷定期刪除操作是否已經達到指定時長,若已經達到,直接退出定期刪除。

對於定期刪除,在程式中有一個全域性變數 current_db 來記錄下一個將要遍歷的庫,假設有 16 個庫,我們這一次定期刪除遍歷了 10 個,那此時的 current_db 就是 11,下一次定期刪除就從第 11 個庫開始遍歷,假設 current_db 等於 15 了,那麼之後遍歷就再從 0 號庫開始(此時 current_db==0)。

更多

原文連結連結

其他目錄

嗨客網更多精選文章,可以搜尋公眾號:嗨客網

本作品採用《CC 協議》,轉載必須註明作者和本文連結

相關文章