把 Redis 當作緩存使用時,有時你能夠方便的讓它在新數據時自動逐出舊數據。這一點你們都比較清楚,由於 memcached 默認也會這麼幹redis
Redis 僅支持 LRU 逐出策略。下文主要講述 Redis maxmemory 指令,這個指令用於限定內存使用量,以及講述了 Redis 使用到的 LRU 算法,這是一種近似LRU算法。算法
maxmemory 配置指令緩存
maxmemory 指令用於限定內存使用量。能夠在 redis.conf 文件中設置,也能夠經過 CONFIG SET 命令在運行時設置。dom
例如在 redis.conf 文件中添加以下指令將內存限定在 100M 之內memcached
maxmemory 100mb性能
設置成 0 時表示無限制。64位系統下默認無限制,32位系統則強制指定爲 3GBspa
當內存使用達到限定值時,能夠選擇幾種不一樣的策略。例如 Redis 能夠在調用指令時直接返回錯誤(這些指令會致使更多內存使用),或者是逐出老數據,給新數據納出空間,讓內存佔用保持在限定一下。對象
逐出策略ip
具體的逐出策略經過 maxmemory-policy 指令進行配置,主要有以下策略:內存
noeviction:調用某些指令時返回錯誤(主要是絕大多數的寫指令,DEL 和 部分其餘指令不包括)
allkeys-lru:對全鍵進行LRU
volatile-lru:對指定了過時時間(expire set)的鍵進行LRU
allkeys-random:對全鍵進行隨機逐出
volatile-random:對指定了過時時間的鍵隨機逐出
volatile-ttl:對指定了過時時間,而且 TTL 較短的鍵進行逐出
volatile-* 系列指令在無鍵值知足條件時(例如未設置過時時間),表現爲 noeviction
不一樣的應用選擇不一樣的逐出策略,固然你能夠根據命中率(INFO指令)在運行時動態調整策略。
能夠參考如下的經驗法則:
allkeys-lru,預期的請求符合長尾理論。或是啥都不懂時配成這個不會太差
allkeys-random,會持續輪詢全部的鍵。或者預期的請求符合均勻分佈
volatile-ttl,在生成緩存對象時指定不一樣的 ttl 值,因此你得控制好
你在單實例上同時存儲緩存數據,以及一些持久化數據時,volatile-lru 和 volatile-random 會比較適合。可是一般建議緩存數據和持久化數據用不一樣的實例存儲。
另外,對一個鍵設置過時時間會佔用額外的內存,因此在內存壓力較大時 allkeys-lru 的內存使用率會較好。
逐出過程是如何實現的
最好從如下幾個方面來了解逐出過程
客戶端運行了一個消耗內存的指令
Redis 檢查內存佔用後發現超限,執行逐出策略
執行一個新的指令,如此循環
即反覆的讓 Redis 的內存佔用在限定值上下波動,來觀察和驗證逐出策略
當一個指令消耗較多內存時,必定時間範圍內能夠觀察到明顯的內存超限
近似LRU算法
Redis 使用的 LRU 算法是一個近似實現,即逐出Key並不必定真正訪問最少的鍵。它採用的方式是,對逐出範圍內的鍵進行採樣,而後對樣本進行逐出。什麼鬼。
在 Redis 3.0中有了一些改進,在提高性能的同時,讓近似LRU的結果更加接近真實LRU。
Redis LRU挺重要的一點是,你能夠調整算法精度,即調整每次逐出時的取樣數。能夠經過這個指令進行調整:
maxmemory-samples 5
Redis 使用 近似LRU 的目的主要仍是爲了節省內存,對於應用來講,近似與真實,其實是等效的。
在 Redis 中填充滿指定數目的數據,順序訪問全部的鍵,在LRU下,第一個鍵是最佳逐出對象。而後增長50%的鍵值,逐出一半的老數據。
圖中的三種點造成了三條不一樣的條紋
淺灰色表示已經逐出的
灰色表示未被逐出的
綠色表示新增的
理論LRU的結果徹底符合預期,前一半的老數據逐出。Redis LRU 則是機率上的逐出老數據。
能夠看到,取樣數爲5時,Redis 3.0 比 Redis 2.8 效果要好不少,2.8逐出了很多剛剛被訪問過的數據。取樣數爲10時,Redis 3.0 的表現跟理論LRU就很是接近了。
若是請求符合長尾法則,那麼真實LRU與Redis LRU之間表現基本無差別。
你能夠在增長必定CPU消耗的狀況下,提升取樣數,而後檢查命中率是否有變化
在生產環境,經過 CONFIG SET maxmemory-samples <count> 指令能夠方便的設置取樣數。