單線程Redis內部的過期key是怎么處理的?會不會同一時刻過期key太多,導致來不及刪除?
【過期key集合】
Redis會將每個設置了過期時間的key放入一個獨立的字典里,以后會定時遍歷這個字典來刪除到期的key。
除了定時遍歷,還會使用惰性策略,即客戶端訪問這個key時,Redis發現這個key過期了,那就立即刪除。
【定時掃描】
Redis默認每秒進行10次過期掃描,過期掃描不會遍歷過期字典中所有的key,而是采取了一種策略:
1.從過期字典中隨機選擇20個key;
2.刪除這20個key中已經過期的key;
3.如果過期的key的比例超過1/4,那就重復步驟(1)。
同時為了保證過期掃描不會出現循環過渡,導致線程卡死,算法還增加了掃描時間的上限,默認不會超過25ms。
如果在同一時期,有大量的key過期,那么Redis會持續掃描過期字典,直到過期字典中過期的key變得稀疏,才會停止,這就會導致線上讀寫請求出現明顯的卡頓。另外,這種時候內存管理器也會頻繁回收內存頁,這也會產生一定的CPU消耗。
當客戶端請求到來,服務器如果正好進入過期掃描狀態,客戶端的請求將會等待至少25ms才能進行處理,如果客戶端將超時時間設置的比較短,那么就會出現大量的鏈接因為超時而關閉。
而且,此時還無法從Redis的slowlog中看到慢查詢的記錄,因為慢查詢指的是邏輯處理過程慢,不包含等待時間。
對於一些定時結束的任務或者邏輯,且參加的人很多,如果業務上允許,最好是能夠在過期時間上加一個隨機時間戳,比如在目標過期時間上增加1天的隨機時間。這樣能夠有效避免上述情形。
【從節點的過期策略】
從節點不會進行過期掃描,從節點對過期的處理是被動的。主節點在key到期時,會在AOF文件中增加一條del指令,同步到從節點從而讓從節點刪除過期key。
指令同步是異步進行的,所以如果主節點過期的key的del指令沒有及時同步到從節點的話,就會出現主從數據不一致,主節點沒有的數據在從節點還在。