當Redis被當做緩存來使用,當你新增數據時,讓它自動地回收舊數據是件很方便的事情。這個行為在開發(fā)者社區(qū)非常有名铺坞,因為它是流行的memcached系統(tǒng)的默認行為。
LRU是Redis唯一支持的回收方法洲胖。本頁面包括一些常規(guī)話題济榨,Redis的maxmemory指令用于將可用內存限制成一個固定大小,還包括了Redis使用的LRU算法绿映,這個實際上只是近似的LRU擒滑。
Maxmemory配置指令
maxmemory
配置指令用于配置Redis存儲數據時指定限制的內存大小。通過redis.conf可以設置該指令叉弦,或者之后使用CONFIG SET命令來進行運行時配置丐一。
例如為了配置內存限制為100mb,以下的指令可以放在redis.conf
文件中淹冰。
maxmemory 100mb
設置maxmemory為0代表沒有內存限制
库车。對于64位的系統(tǒng)這是個默認值,對于32位的系統(tǒng)默認內存限制為3GB
樱拴。
當指定的內存限制大小達到時凝颇,需要選擇不同的行為,也就是策略
疹鳄。 Redis可以僅僅對命令返回錯誤,這將使得內存被使用得更多芦岂,或者回收一些舊的數據來使得添加數據時可以避免內存限制瘪弓。
回收策略
當maxmemory限制達到的時候Redis會使用的行為由 Redis的maxmemory-policy配置指令來進行配置。
以下的策略是可用的:
*noeviction
:返回錯誤當內存限制達到并且客戶端嘗試執(zhí)行會讓更多內存被使用的命令(大部分的寫入指令禽最,但DEL和幾個例外)
-
allkeys-lru
: 嘗試回收最少使用的鍵(LRU)腺怯,使得新添加的數據有空間存放袱饭。 -
volatile-lru
: 嘗試回收最少使用的鍵(LRU),但僅限于在過期集合的鍵,使得新添加的數據有空間存放呛占。 -
allkeys-random
: 回收隨機的鍵使得新添加的數據有空間存放虑乖。 -
volatile-random
: 回收隨機的鍵使得新添加的數據有空間存放,但僅限于在過期集合的鍵晾虑。 -
volatile-ttl
: 回收在過期集合的鍵疹味,并且優(yōu)先回收存活時間(TTL)較短的鍵,使得新添加的數據有空間存放。
如果沒有鍵滿足回收的前提條件的話帜篇,策略volatile-lru, volatile-random以及volatile-ttl就和noeviction 差不多了糙捺。
選擇正確的回收策略是非常重要的,這取決于你的應用的訪問模式笙隙,不過你可以在運行時進行相關的策略調整洪灯,并且監(jiān)控緩存命中率和沒命中的次數,通過RedisINFO
命令輸出以便調優(yōu)竟痰。
一般的經驗規(guī)則:
-
使用allkeys-lru策略
:當你希望你的請求符合一個冪定律分布签钩,也就是說,你希望部分的子集元素將比其它其它元素被訪問的更多坏快。如果你不確定選擇什么铅檩,這是個很好的選擇。. -
使用allkeys-random
:如果你是循環(huán)訪問假消,所有的鍵被連續(xù)的掃描柠并,或者你希望請求分布正常(所有元素被訪問的概率都差不多)。 -
使用volatile-ttl
:如果你想要通過創(chuàng)建緩存對象時設置TTL值富拗,來決定哪些對象應該被過期臼予。
allkeys-lru
和 volatile-random
策略對于當你想要單一的實例實現(xiàn)緩存及持久化一些鍵時很有用。不過一般運行兩個實例是解決這個問題的更好方法啃沪。
為了鍵設置過期時間也是需要消耗內存的粘拾,所以使用allkeys-lru這種策略更加高效,因為沒有必要為鍵取設置過期時間當內存有壓力時创千。
回收進程如何工作
理解回收進程如何工作是非常重要的:
- 一個客戶端運行了新的命令缰雇,添加了新的數據。
- Redis檢查內存使用情況追驴,如果大于maxmemory的限制, 則根據設定好的策略進行回收械哟。
- 一個新的命令被執(zhí)行,等等殿雪。
- 不斷地穿越內存限制的邊界暇咆,通過不斷達到邊界然后不斷地回收回到邊界以下。
近似LRU算法
Redis的LRU算法并非完整的實現(xiàn)。這意味著Redis并沒辦法選擇最佳候選來進行回收爸业,也就是最久未被訪問的鍵其骄。相反它會嘗試運行一個近似LRU的算法,通過對少量keys進行取樣扯旷,然后回收其中一個最好的key(被訪問時間較早的)拯爽。
不過從Redis 3.0算法已經改進為回收鍵的候選池子。這改善了算法的性能钧忽,使得更加近似真是的LRU算法的行為毯炮。
Redis LRU有個很重要的點,你通過調整每次回收時檢查的采樣數量惰瓜,以實現(xiàn)調整算法的精度否副。這個參數可以通過以下的配置指令調整:
maxmemory-samples 5
Redis為什么不使用真實的LRU實現(xiàn)是因為這需要太多的內存。不過近似的LRU算法對于應用而言應該是等價的崎坊。使用真實的LRU算法與近似的算法可以通過下面的圖像對比备禀。
用于生成圖像的Redis服務被填充了指定數量的鍵。這些鍵將被從頭到尾訪問奈揍,所以當使用LRU算法時第一個鍵是最佳的回收候選鍵曲尸。接著添加超過50%的鍵,用于強制舊鍵被回收男翰。
你可以看到三種點在圖片中, 形成了三種帶.
- 淺灰色帶是已經被回收的對象另患。
- 灰色帶是沒有被回收的對象。
- 綠色帶是被添加的對象蛾绎。
- 在LRU實現(xiàn)的理論中昆箕,我們希望的是,在舊鍵中的第一半將會過期租冠。Redis的LRU算法則是概率的過期舊的鍵鹏倘。
你可以看到,在都是五個采樣的時候Redis 3.0比Redis 2.8要好顽爹,Redis2.8中在最后一次訪問之間的大多數的對象依然保留著纤泵。使用10個采樣大小的Redis 3.0的近似值已經非常接近理論的性能。
注意LRU只是個預測鍵將如何被訪問的模型镜粤。另外捏题,如果你的數據訪問模式非常接近冪定律,大部分的訪問將集中在一個鍵的集合中肉渴,LRU的近似算法將處理得很好公荧。
在模擬實驗的過程中,我們發(fā)現(xiàn)如果使用冪定律的訪問模式同规,則真實的LRU算法和近似的Redis算法幾乎沒有差別稚矿。
當然你可以提升采樣大小到10庸诱,消耗更多的CPU時間以實現(xiàn)更真實的LRU算法,同時查看下是否讓你的緩存命中率有差別晤揣。
通過CONFIG SET maxmemory-samples
命令在生產環(huán)境上設置不同的采樣大小是非常簡單的。