Redis過期刪除策略

壹頁書發表於2016-05-25
轉載自:
http://blueswind8306.iteye.com/blog/2240088


最近線上遇到Redis記憶體達到maxmemory限制後,資料淘汰過慢導致拖慢應用請求的問題。後來仔細看了一下Redis的各種資料淘汰策略,總結一下。 

首先,Redis有三種刪除key的時機,它們對應不同的淘汰策略: 
  1. 當讀/寫一個已經過期的key時,會觸發惰性刪除策略,直接刪除掉這個過期key。
  2. 由於惰性刪除策略無法保證冷資料被及時刪掉,所以Redis會定期主動淘汰一批已過期的key。
  3. 當前已用記憶體超過maxmemory限定時,觸發主動清理策略。

下面詳細說一下定期主動淘汰策略和主動清理策略,以及它們所對應的配置引數的含義。 
  • 定期主動淘汰策略 
首先,這裡的“定期”指的是Redis定期呼叫databasesCron()函式時觸發的清理策略,這個定期的頻率由配置檔案中的hz引數決定,代表了一秒鐘內,後臺任務期望被呼叫的次數。Redis-3.0.0中的預設值是10,代表每秒鐘呼叫10次後臺任務。 

hz調大將會提高Redis主動淘汰的頻率,如果你的Redis儲存中包含很多冷資料佔用記憶體過大的話,可以考慮將這個值調大,但Redis作者建議這個值不要超過100。我們實際線上將這個值調大到100,觀察到CPU會增加2%左右,但對冷資料的記憶體釋放速度確實有明顯的提高(透過觀察keyspace個數和used_memory大小)。 

除了主動淘汰的頻率外,Redis對每次淘汰任務執行的最大時長也有一個限定,這樣保證了每次主動淘汰不會過多阻塞應用請求,以下是這個限定計算公式: 

#define ACTIVE_EXPIRE_CYCLE_SLOW_TIME_PERC 25 /* CPU max % for keys collection */  
...  
timelimit = 1000000*ACTIVE_EXPIRE_CYCLE_SLOW_TIME_PERC/server.hz/100;  

可以看出timelimit和server.hz是一個倒數的關係,也就是說hz配置越大,timelimit就越小。換句話說是每秒鐘期望的主動淘汰頻率越高,則每次淘汰最長佔用時間就越短。這裡每秒鐘的最長淘汰佔用時間是固定的250ms(1000000*ACTIVE_EXPIRE_CYCLE_SLOW_TIME_PERC/100),而淘汰頻率和每次淘汰的最長時間是透過hz引數控制的。 

具體的淘汰過程為:在redis.c/activeExpireCycle()函式中,針對每個db有一個迴圈,每次從db->expires集合中隨機取出20個key,如果有超過5個key過期淘汰,則繼續迴圈。也就是說如果超過25%的key過期淘汰,則繼續淘汰,直到隨機抽取的key的過期率低於25%,或者整個迴圈時間超過timelimit的最大限定。則結束整個淘汰過程。 

從以上的分析看,當redis中的過期key比率沒有超過25%之前,提高hz可以明顯提高掃描key的最小個數。假設hz為10,則一秒內最少掃描200個key(一秒呼叫10次*每次最少隨機取出20個key),如果hz改為100,則一秒內最少掃描2000個key;另一方面,如果過期key比率超過25%,則掃描key的個數無上限,但是cpu時間每秒鐘最多佔用250ms。 

  • maxmemory的主動清理策略 
當mem_used記憶體已經超過maxmemory的設定,對於所有的讀寫請求,都會觸發redis.c/freeMemoryIfNeeded(void)函式以清理超出的記憶體。注意這個清理過程是阻塞的,直到清理出足夠的記憶體空間。所以如果在達到maxmemory並且呼叫方還在不斷寫入的情況下,可能會反覆觸發主動清理策略,導致請求會有一定的延遲。 

清理時會根據使用者配置的maxmemory-policy來做適當的清理(一般是LRU或TTL),這裡的LRU或TTL策略並不是針對redis的所有key,而是以配置檔案中的maxmemory-samples個key作為樣本池進行抽樣清理。 

maxmemory-samples在redis-3.0.0中的預設配置為5,如果增加,會提高LRU或TTL的精準度,redis作者測試的結果是當這個配置為10時已經非常接近全量LRU的精準度了,並且增加maxmemory-samples會導致在主動清理時消耗更多的CPU時間。 


建議: 
儘量不要觸發maxmemory,最好在mem_used記憶體佔用達到maxmemory的一定比例後,需要考慮調大hz以加快淘汰,或者進行叢集擴容。
如果能夠控制住記憶體,則可以不用修改maxmemory-samples配置;如果Redis本身就作為LRU cache服務(這種服務一般長時間處於maxmemory狀態,由Redis自動做LRU淘汰),可以適當調大maxmemory-samples。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/29254281/viewspace-2106910/,如需轉載,請註明出處,否則將追究法律責任。

相關文章