共計 3214 個字符,預計需要花費 9 分鐘才能閱讀完成。
這篇文章將為大家詳細講解有關 Redis 中過期策略是怎么樣的,丸趣 TV 小編覺得挺實用的,因此分享給大家做個參考,希望大家閱讀完這篇文章后可以有所收獲。
保存過期時間
Redis 可以為每個 key 設置過期時間,會將每個設置了過期時間的 key 放入一個獨立的字典中?!鞠嚓P推薦: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 函數過程如下圖
另外因為每個被訪問的鍵都可能被刪除,所以每個命令都必須能同時處理鍵存在以及不存在的情況。
下圖表示 get 命令的執行過程
定期刪除策略的實現
過期鍵的定期刪除策略由 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 中過期策略是怎么樣的”這篇文章就分享到這里了,希望以上內容可以對大家有一定的幫助,使各位可以學到更多知識,如果覺得文章不錯,請把它分享出去讓更多的人看到。