在我們用 redis 存儲數據時,大多數場景都會給key設置一個過期時間,那么當key過期后,redis是如何處理的呢。大家可能會想到定時器的方案,當我們給key設置過期時間的同時設置一個定時器,到達時間后,刪除過期的key,但這種方式在內存不緊張但Cpu緊張時,將cpu時間用在刪除過期key上,無疑會對系統的吞吐量造成影響。所以redis沒有采用這種方案,而是使用了 惰性刪除+定期刪除的方式。
惰性刪除
當客戶端查詢數據時,redis會先查詢expires字典(redis內部會額外維護一個記錄<key,過期時間>的字典) ,如果key設置了過期時間並且已經過期,redis會直接將記錄刪掉,返回空記錄給客戶端。這種讀時刪除,我們稱它為`惰性刪除`。
定期刪除
惰性刪除對cpu來講是友好的,但是對內存來講並不友好,如果大量的過期key一直不被訪問,就會一直占用着內存空間,所以需要定期的刪除,減輕過期key對內存的影響。
redis默認會以每秒10次的頻率,在expires字典中隨機檢查key的過期時間,然后在數據字典中刪除已經過期的key-value。
AOF、RDB和復制功能對過期key的處理
在執行save或bgsave命令創建一個新的RDB文件時,redis會對鍵進行檢查,已過期的鍵不會保存到RDB文件中。
當啟用了rdb持久化策略,在啟用redis時,服務器會對rdb文件進行載入。如果是主庫,載入rdb文件時,會對鍵進行檢查,已過期的鍵不會載入到redis中。如果是從庫載入rdb文件時,不論key是否過期,都會被載入到redis中,但這不會對redis造成影響。因為主從服務器進行數據同步時,從數據庫的數據會被清空。
當redis使用aof持久化策略,當redis刪除一條過期key時,會同時向aof文件中追加一條del命令。在執行aof重寫的過程中,程序會對數據庫中的鍵進行檢查,已過期的建不會被保存到重寫的aof文件中。
當服務器運行在復制模式下時,從服務器的過期鍵刪除動作有主服務器控制,所以讀寫分離模式下,會出現key過期但仍有效的問題。(reidis3.2已修復)
緩存淘汰策略
maxmemory 用於指定 redis的最大可用內存。我們可以通過下面的配置將 redis的可用內存設置為 100mb。
maxmemory 100mb
如果系統對redis的使用量很大,內存被寫滿時,再有客戶端的寫入請求進來,redis會怎樣處理呢,這個時候就要提到 redis的 緩存淘汰策略了。
noeviction : 當內存超過配置內存時,會返回錯誤,不會刪除任何鍵。
allkeys-lru: 當內存不足以處理新加入的鍵時,按照lru算法驅逐最久沒有使用的鍵。(建議使用)
volitile-lru: 當內存不足以處理新加入的鍵時,按照lru算法在設置了過期時間的key中,驅逐最久沒有使用的鍵。
allkeys-random: 當內存不足以處理新加入的鍵時,隨機驅逐鍵。(不建議使用)
volitile-random: 當內存不足以處理新加入的鍵時,在設置了過期時間的key中,隨機驅逐鍵。
volitile-ttl: 當內存不足以處理新加入的鍵時,驅逐馬上要過期的鍵。
allkeys-lfu: 當內存不足以處理新加入的鍵時,按照lfu算法驅逐使用頻率最低的鍵。
volitile-lfu: 當內存不足以處理新加入的鍵時,按照lfu算法在設置了過期時間的key中,驅逐使用頻率最低的鍵。
redis的默認緩存淘汰策略是 noeviction,我們可以按照上面的說明選擇最合適的方案。
maxmemory-policy noeviction