過期策略
數據刪除策略的目標
在內存占用與CPU占用之間尋找一種平衡,顧此失彼都會造成整體redis性能的下降,甚至引發服務器宕機或內存泄露 。
定時刪除
創建一個定時器,當key設置有過期時間,且過期時間到達時,由定時器任務立即執行對鍵的刪除操作
優點:節約內存,到時就刪除,快速釋放掉不必要的內存占用
缺點: CPU壓力很大,無論CPU此時負載量多高,均占用CPU,會影響redis服務器響應時間和指令吞吐量
總結:用處理器性能換取存儲空間(拿時間換空間)
Redis 默認會每秒進行十次過期掃描,過期掃描不會遍歷過期字典中所有的 key,而是
采用了一種簡單的貪心策略。
1、從過期字典中隨機 20 個 key;
2、刪除這 20 個 key 中已經過期的 key;
3、如果過期的 key 比率超過 1/4,那就重復步驟 1;
同時,為了保證過期掃描不會出現循環過度,導致線程卡死現象,算法還增加了掃描時間的上限,默認不會超過 25ms。
設想一個大型的 Redis 實例中所有的 key 在同一時間過期了,會出現怎樣的結果?
毫無疑問,Redis 會持續掃描過期字典 (循環多次),直到過期字典中過期的 key 變得稀
疏,才會停止 (循環次數明顯下降)。這就會導致線上讀寫請求出現明顯的卡頓現象。導致這
種卡頓的另外一種原因是內存管理器需要頻繁回收內存頁,這也會產生一定的 CPU 消耗。
也許你會爭辯說“掃描不是有 25ms 的時間上限了么,怎么會導致卡頓呢”?這里打個
比方,假如有 101 個客戶端同時將請求發過來了,然后前 100 個請求的執行時間都是
25ms,那么第 101 個指令需要等待多久才能執行?2500ms,這個就是客戶端的卡頓時間,
是由服務器不間斷的小卡頓積少成多導致的。
所以業務開發人員一定要注意過期時間,如果有大批量的 key 過期,要給過期時間設置
一個隨機范圍,而不能全部在同一時間過期。
# 在目標過期時間上增加一天的隨機時間
redis.expire_at(key, random.randint(86400) + expire_ts)
在一些活動系統中,因為活動是一期一會,下一期活動舉辦時,前面幾期的很多數據都
可以丟棄了,所以需要給相關的活動數據設置一個過期時間,以減少不必要的 Redis 內存占
用。如果不加注意,你可能會將過期時間設置為活動結束時間再增加一個常量的冗余時間,
如果參與活動的人數太多,就會導致大量的 key 同時過期。
掌閱服務端在開發過程中就曾出現過多次因為大量 key 同時過期導致的卡頓報警現象,
通過將過期時間隨機化總是能很好地解決了這個問題。
惰性刪除
數據到達過期時間,不做處理。等下次訪問該數據時
如果未過期,返回數據
發現已過期,刪除,返回不存在
優點:節約CPU性能,發現必須刪除的時候才刪除
缺點:內存壓力很大,出現長期占用內存的數據
總結:用存儲空間換取處理器性能(拿空間換時間)
定期刪除
周期性輪詢redis庫中的時效性數據,采用隨機抽取的策略,利用過期數據占比的方式控制刪除頻度
特點1: CPU性能占用設置有峰值,檢測頻度可自定義設置
特點2:內存壓力不是很大,長期占用內存的冷數據會被持續清理
總結:周期性抽查存儲空間(隨機抽查,重點抽查)
Redis啟動服務器初始化時,讀取配置server.hz的值,默認為10
每秒鍾執行server.hz次serverCron()
activeExpireCycle()對每個expires[*]逐一進行檢測,每次執行250ms/server.hz
對某個expires[*]檢測時,隨機挑選W個key檢測
如果key超時,刪除key
如果一輪中刪除的key的數量>W*25%,循環該過程
如果一輪中刪除的key的數量≤W*25%,檢查下一個expires[*], 0-15循環
W取值=ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP屬性值
參數current_db用於記錄activeExpireCycle() 進入哪個expires[*] 執行
如果activeExpireCycle()執行時間到期,下次從current_db繼續向下執行
等看書老錢的Redis深度歷險,在回來補充一下。