首頁  >  文章  >  資料庫  >  一文聊聊Redis中的過期策略

一文聊聊Redis中的過期策略

青灯夜游
青灯夜游轉載
2022-01-07 19:05:072081瀏覽

這篇文章帶大家介紹一下Redis中的過期策略,看看惰性刪除策略、定期刪除策略的實作方法,希望對大家有幫助!

一文聊聊Redis中的過期策略

儲存過期時間

#Redis可以設定每個key過期時間,會將每個設定了過期時間的key放入一個獨立的字典。 【相關推薦:Redis影片教學

typedef struct redisDb { 
int id; //id是数据库序号,为0-15(默认Redis有16个数据库) 
long avg_ttl; //存储的数据库对象的平均ttl(time to live),用于统计 
dict *dict; //存储数据库所有的key-value 
dict *expires; //存储key的过期时间 
dict *blocking_keys;//blpop 存储阻塞key和客户端对象 
dict *ready_keys;//阻塞后push 响应阻塞客户端 存储阻塞后push的key和客户端对象 dict *watched_keys;//存储watch监控的的key和客户端对象 
} redisDb;

dict 用來維護一個Redis 資料庫中包含的所有Key-Value 鍵值對,expires則用來維護一個Redis 資料庫中設定了失效時間的鍵(即key與失效時間的映射)。 注意這裡的失效時間是用毫秒的時間戳表示的,例如2022-01-02 22:45:02過期則value為1641134702000

當我們使用expire指令設定一個key的失效時間時,Redis 首先到dict 這個字典表中尋找要設定的key是否存在,如果存在就將這個key和失效時間加到expires 這個字典表。

當我們使用setex指令向系統插入資料時,Redis 首先將 Key 和 Value 加入 dict 這個字典表中,然後將 Key 和失效時間加入 expires 這個字典表中。 注意setex只能用於字串

簡單地總結來說就是,設定了失效時間的key和具體的失效時間全部都維護在 expires 這個字典表中。

設定過期時間

expire的使用

expire指令的使用方法如下: expire key ttl(單位秒)

127.0.0.1:6379> expire name 2 #2秒失效 
(integer) 1 
127.0.0.1:6379> get name 
(nil) 
127.0.0.1:6379> set name zhangfei 
OK 
127.0.0.1:6379> ttl name #永久有效 
(integer) -1 
127.0.0.1:6379> expire name 30 #30秒失效 
(integer) 1 
127.0.0.1:6379> ttl name #还有24秒失效 
(integer) 24 
127.0.0.1:6379> ttl name #失效 
(integer) -2

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

expire 指令用於將鍵key的生存時間設定為ttl

pexpire 指令用於將鍵key的生存時間設定為ttl毫秒

expireat 指令用於將鍵key的過期時間設定為timestamp所指定的數時間戳

#pexpireat 指令用於將鍵key的過期時間設定為timestamp所指定的毫秒數時間戳

注意expire、pexpire、expireat最終實作都是透過pexpireat實現的,也就是說無論客戶端執行哪個指令,都會將Redis轉換成pexpireat指令執行。所以expires字典中存的時間是用毫秒時間戳表示的鍵的過期時間。

過期策略

如果一個鍵過期了,那什麼時候被刪除呢?

有三種過期策略

  • 定時刪除:在設定鍵的過期時間的同時,建立一個定時器,讓定時器在鍵的過期時間來臨時,立即執行對鍵的刪除操作。 (建立定時器刪除
  • 惰性刪除:放任鍵的過期不管,但是每次從鍵空間中取得鍵時,都檢查取得的鍵是否過期,如果過期的話,就刪除該鍵;如果沒有過期,就返回該鍵。 (使用的時候刪除
  • 定期刪除:每隔一段時間,程式就會對資料庫進行一次檢查,刪除裡面過期的鍵。至於要刪除多少過期鍵,以及要檢查多少個資料庫,則有演算法決定。 (定期掃描刪除

#定時刪除

  • 優點

1、對記憶體最友善:透過使用定時器,可以保證過期的鍵會盡可能快地被刪除,釋放所佔記憶體

  • 缺點
##1、對cpu最不友善:在過期鍵比較多的情況下,刪除過期鍵此行為可能會佔用相當一部分cpu的時間,對伺服器的回應時間和吞吐量造成影響。

惰性刪除

    優點
1、對cpu最友善:只有在取出鍵的時候才會對過期鍵進行檢查,即不需要cpu定期掃描,也不需要建立大量的定時器。

    缺點
1、對記憶體最不友善:如果一個鍵已經過期,但是後面不會被存取的話,那麼就一直保留在資料庫中。如果這樣的鍵過多,無疑會佔用很大的記憶體。

定期刪除

定期刪除是上面的定時刪除和惰性刪除的一中折中方案。

    優點
1、定期刪除每隔一段時間執行一次過期鍵操作,並透過限制刪除操作執行的長度和頻率來減少刪除操作對cpu時間的影響。

2、透過刪除過期鍵,能有效的減少因為過期鍵而帶來的記憶體浪費

    缺點難以確定刪除操作執行的時長和頻率
1、如果刪除操作執行得太頻繁,或是執行的時間太長,定期刪除策略就會退化成定時刪除,以至於佔用太多cpu的執行時間。

2、如果刪除操作執行的時間太少,或執行時間太短,定期刪除策略又會和惰性刪除一樣,出現記憶體浪費。

Redis的過期策略

Redis使用是惰性刪除定期刪除兩種策略:透過配好使用這兩種策略,伺服器可以很好地在合理使用cpu時間和避免浪費記憶體空間之間取得平衡。

惰性刪除策略的實現

過期鍵的惰性刪除刪除策略由db.c/expireIfNeeded函數實現,所有讀寫資料庫的Redis命令在執行之前都會呼叫expireIfNeed函數對輸入鍵進行檢查:

  • 如果鍵已經過期,那麼expireIfNeeded函數將鍵刪除
  • 如果鍵未過期,那麼expireIfNeeded函數不做操作

指令呼叫expireIfNeeded函數程序如下圖

一文聊聊Redis中的過期策略

#另外因為每個被存取的鍵都可能被刪除,所以每個指令都必須能同時處理鍵存在以及不存在的情況。 下圖表示get指令的執行過程

一文聊聊Redis中的過期策略

有定期刪除策略的實作

##過期鍵的定期刪除策略由redis.c/activeExpireCycle函數實現,每當Redis的伺服器週期性操作redis.c/serverCron函數執行時,activeExpireCycle函數就會被調用,它在規定時間內,分多次遍歷伺服器中各個資料庫。

Redis 預設每秒進行 10 次過期掃描,過期掃描不會遍歷過期字典中所有的 key, 而是採用了一種簡單的貪心策略,步驟如下。

(1)從過期字典中隨機選出 20個 key。

(2)刪除這 20 個 key 中已經過期的 key。

(3)如果過期的 key的比例超過 1/4,那就重複步驟 (1)。同時,為了確保過期掃描不會出現循環過度,導致結程卡死的現象,演算法也增加了掃描時間的上限,預設不會超過 25ms。

假設一個大型的Redis 實例中所有的key 在同一時間過期了,會出現怎樣的結果呢?

消耗cpu

Redis會持續掃描過期字典(循環多次),直到過期字典中過期的key變得稀疏,才會停止(循環次數明顯下降)。

導致請求卡頓或逾時

當客戶端請求到來時,伺服器如果剛好進入過期掃描狀態,客戶端的請求將會等待至少25ms 後才會進行處理,如果客戶端將超時時間設定得比較短,例如​​10ms,那麼就會出現大量的連線因為超時而關閉,業務端就會出現很多異常

##所以一定要注意過期時間,如果有大批量的key過期,要給過期時間設定一個隨機範圍,而不能全部在同一時間過期。

更多程式相關知識,請造訪:

程式設計入門

! !

以上是一文聊聊Redis中的過期策略的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:juejin.cn。如有侵權,請聯絡admin@php.cn刪除