眾所周知Redis針對每一個key都能單獨設置過期時間,那么Redis是怎么處理這些key的過期時間的呢?當同一時間有大量Key同時到期時,Redis又是怎么處理的呢?會不會影響到我的線上業務呢?如果Redis存儲數據超出物理限制了,又是怎么處理的呢?本文將詳細為你介紹Redis的過期&淘汰策略。
過期策略
首先針對每一個設置了過期時間的key,Redis都會將其放入一個統一的字典中進行管理。具體管理策略分為以下兩種:
定時掃描策略:Redis會定時掃描存儲含有過期時間key字典,遍歷刪除已經過期的key。
惰性刪除策略:當客Redis讀一個key的,Redis首先會校驗key的過期時間,如果已經過期,將會對其進行過期刪除操作。
定時掃描策略
Redis會對設置了過期時間的key字典定時進行一次過期掃描,掃描采取的是貪心策略,具體實現如下:
- 從過期字典中隨機挑選一批key(有說20個的);
- 遍歷這一批key,並刪除已經過期的key;
- 如果過期的key超過一定比例(有說1/4的),重復步驟1。
當有大量key同時過期時,將會導致Redis重復執行掃描並刪除的任務,這將導致Redis的讀寫請求出現延遲、阻塞的現象。所以要盡量避免大批量key同時過期的情況,如果存在大批量的過期key,最好在目標過期時間上,設置一個合理的隨機時間范圍。
惰性過期策略
從定時掃描策略的實現步驟中,我們可以看到,其實內存中還可能存在已經過期的key。這時為了解決這一問題,Redis引入了惰性過期這一策略,通過在取值的時候做過期校驗,刪除過期key,這樣能保證每一個key的有效性,避免了臟數據的產生。
從節點過期策略
為了保證主從數據一致性,Redis從節點不會執行定掃掃描策略去主動刪除key。但是主節點在刪除過期key的時候,會向主節點的AOF日志文件添加一條del操作指令,隨后將該指令同步到從節點,從節點通過執行del指令以此來達到刪除從節點過期key的目的。
淘汰策略
當Redis內存的使用達到限制時,Redis會將多余的key寫入到磁盤中,然后從磁盤中讀取key進行操作,這樣無疑就加大了IO開銷。為了避免這一問題,Redis也提供了幾種數據淘汰策略供我們選擇:
- noeviction:阻塞寫請求,其他請求可用
- volatile-lru:淘汰過期key集合中,最少被使用的key
- volatile-ttl:淘汰過期key集合中,ttl最小的key
- volatile-random:淘汰過期key集合中,隨機key
- allkeys-lru:淘汰所有key中,最少被使用key
- allkeys-random:淘汰所有key中,隨機key
刪除策略
我們知道Redis在key過期時候會刪除過期key,在淘汰key的時候也會刪除key。但是具體是怎么刪除的呢?
直接刪除
通過del指令直接,可以直接刪除指定key,並釋放key相關的對象。
懶刪除
在大部分情況下del指定都是很快的,但是當需要刪除一個很大的key對象是,del指令就會產生明顯延遲,導致線程卡頓。所以需要使用unlink指令對其進行懶刪除。
理解unlink其實可以將整個Redis看做一個鏈表(當然Redis並不是鏈表,此處只是為了方便理解unlink)。當執行unlink的時候,會將該key所在的對象從鏈表中移除。等待Redis的異步線程來進行內存釋放。
Redis內部並不是只有一個主線程,還有其他異步線程,通常我們所說的Redis是單線程,指的是其網絡請求模塊為單線程,即一個線程處理所有網絡請求。所以在非特指的情況下,Redis是還是單線程。