把Redis用作LRU緩存
當Redis被用作緩存時浊仆,當你添加新的數(shù)據(jù)時誓军,通常可以很方便的使它自動的淘汰舊的數(shù)據(jù)面睛。這個行為在開發(fā)者社區(qū)中很知名,因為它是流行的memcached系統(tǒng)中一個默認的行為尊搬。
LRU實際上只是支持淘汰的方法之一叁鉴。本頁覆蓋了更多的Redismaxmemory
指令的通用話題,它用于限制內(nèi)存使用總數(shù)為一個固定的值佛寿,并且也深入介紹了Redis中的LRU算法使用幌墓,實際上是精確的LRU算法的近似方法。
從Redis4.0版本開始狗准,一個新的LFU(最不經(jīng)常使用)淘汰政策被引入克锣。它在本文檔中一個獨立的部分中被介紹。
最大內(nèi)存配置指令
maxmemory
配置指令被用于配置Redis的數(shù)據(jù)集使用一個特定的內(nèi)存總量腔长∠睿可以使用redis.conf
文件來配置指令,或者稍后使用CONFIG SET命令實時的配置捞附。
例如巾乳,為了配置內(nèi)存限制為100MB,可以在redis.conf
文件中使用下面的指令鸟召。
maxmemory 100mb
設(shè)置maxmemory
為0會導(dǎo)致沒有內(nèi)存限制胆绊。在64位系統(tǒng)中默認是沒有限制的,但是在32位系統(tǒng)中使用的隱式內(nèi)存限制是3GB欧募。
當即將到指定的內(nèi)存時压状,可以在不同的行為(策略)之間做出選擇。對于那些可能會導(dǎo)致更多內(nèi)存使用的命令Redis可以只返回錯誤跟继,或者在每次添加新的數(shù)據(jù)時种冬,可以淘汰一些舊的數(shù)據(jù)從而讓內(nèi)存回到一個特定的限制值。
回收策略
當maxmemory
限制到達時舔糖,Redis執(zhí)行的準確的行為是使用maxmemory-policy
配置的指令娱两。
下面的策略是可用的:
- 不回收:當?shù)竭_限制的內(nèi)存,客戶端嘗試執(zhí)行可能會導(dǎo)致使用更多內(nèi)存的命令(大部分是寫命令金吗,但是DEL和其他一些列外)時十兢,返回錯誤。
- alleys-lru: 嘗試先移除最近最少使用(LRU)的鍵來回收鍵摇庙,為新添加的數(shù)據(jù)制造內(nèi)存空間旱物。
- volatile-lru:嘗試移除最近最少使用(LRU)的鍵來回收鍵,但是僅在有過期時間的鍵中卫袒,為新添加的數(shù)據(jù)制造內(nèi)存空間异袄。
- alleys-random: 隨機回收鍵,為新添加的數(shù)據(jù)制造空間玛臂。
- volatile-random:隨機回收鍵烤蜕,為新添加的數(shù)據(jù)制造空間封孙,但是僅淘汰擁有過期時間的鍵。
- volatile-ttl:使用過期時間淘汰鍵讽营,并且嘗試先淘汰具有較短生存期(TTL)的鍵虎忌,為新添加的數(shù)據(jù)創(chuàng)造空間。
如果沒有匹配先決條件的鍵可以被回收時橱鹏,策略 volatile-lru, volatile-random 和 volatile-ttl 的行為像noeviction膜蠢。
挑選合適的回收策略是重要的,依賴于你的應(yīng)用的訪問模式莉兰,盡管你可以在應(yīng)用運行時重新配置策略挑围,并且使用Redis的INfO來監(jiān)視緩存丟失和命中的數(shù)量以便于調(diào)整你的設(shè)置。
一般來說的經(jīng)驗法則:
- 當你期待受歡迎的請求是冪律分布時糖荒,也就是說杉辙,你期待元素的子集將會比其他子集被更頻繁的訪問時使用allkeys-lru策略。當你不確定時捶朵,這個一個好的選擇蜘矢。
- 如果你有一個所有的鍵被連續(xù)不斷掃描的循環(huán)訪問時,或者當你期待分布是統(tǒng)一時综看,使用allkeys-random策略(所有的元素以相同的概率被訪問)品腹。
- 如果想要通過在創(chuàng)建緩存對象時使用不同的TTL來提示Redis哪些是過期的候選者,那么使用volatile-ttl红碑。
volatile-lru和volatile-random策略在你想使用一個單實例同時用于緩存和擁有一系列持久化鍵時非常有用舞吭。然而,運行兩個Redis實例來解決這個問題通常是一個更好的主意析珊。
值得注意的是镣典,給一個鍵設(shè)置過期時間是需要占用內(nèi)存的,因而使用一個類似于allkeys-lru的策略更有內(nèi)存效率唾琼,因為在有內(nèi)存壓力時給一個鍵設(shè)置一個過期時間然后回收是不必要的。
回收進程如何工作
重要的是理解回收處理過程是這樣運作的:
- 客戶端運行了一個新的命令澎剥,導(dǎo)致更多的數(shù)據(jù)被添加锡溯。
- Redis檢查內(nèi)存使用量,如果超過了
maxmemory
限制哑姚,它就會依照策略回收鍵祭饭。 - 執(zhí)行一個新的命令,重復(fù)以上叙量。
因此我們持續(xù)的跨越內(nèi)存限制的邊界倡蝙,通過超出它,然后通過回收鍵而回到限制以下绞佩。
如果一個鍵導(dǎo)致大量的內(nèi)存被使用(就像一個大的集合交叉保存到一個新鍵上)寺鸥,在一段時間內(nèi)內(nèi)存限制可以被顯著的超過猪钮。
近似LRU算法
Redis的LRU算法不是一個精確的實現(xiàn)。這意味著Redis不能夠選出最佳候選人來回收胆建,也就是烤低,過去訪問最多的訪問權(quán)限。相反笆载,它是嘗試運行一個近似的LRU算法扑馁,通過取樣一小部分鍵,然后回收樣本中最合適(擁有最古老訪問時間)的那一個凉驻。
然而腻要,從Redis3.0版本開始算法已經(jīng)被改進成候選人池供回收。這提高了算法的性能涝登,使其能夠更接近于真實LRU算法的行為雄家。
Redis LRU算法的重要之處是,可以通過改變樣本的數(shù)量來調(diào)整算法的精度缀拭,以檢查每一次的回收咳短。這個參數(shù)受下面的配置指令控制:
maxmemory-samples 5
Redis不用真正的LRU實現(xiàn)的原因是它會消耗更多的內(nèi)存。然而蛛淋,這種近似對于使用Redis的應(yīng)用實際上是等價的咙好。下面就是使用Redis LRU近似算法與使用真實LRU的對比圖。
生成上述圖像的測試用一個給定數(shù)字的鍵填充了一個Redis服務(wù)褐荷。這些鍵從第一個到最后一個被訪問勾效,因此,最早的鍵是LRU算法回收的最好的候選人叛甫。稍后层宫,添加了超過50%的鍵,強迫超過一半的舊的鍵被回收其监。
你可以看到圖像中有3種類型的點萌腿,組成3個明顯的區(qū)域。
- 淺灰色的區(qū)域是被回收的對象抖苦。
- 灰色的區(qū)域是沒有被回收的對象毁菱。
- 綠色的區(qū)域是被添加的對象。
在理論上LRU實現(xiàn)期待的是锌历,在舊的鍵中贮庞,最早的那一半將會被過期。但Redis的LRU算法將僅有概率的過期舊的鍵究西。
如你所見窗慎,與Redis2.8相比,Redis3.0使用5個樣本時做的要更好,但是大多數(shù)最新訪問的對象仍然在Redis2.8中保留了下來遮斥。Redis3.0使用10個樣本時的近似值已經(jīng)非常接近于Redis3.0的理論上的性能峦失。
注意,LRU僅是一個模型伏伐,用于預(yù)測一個給定的鍵將來被訪問的可能性宠进。此外,如果你的數(shù)據(jù)訪問模式很接近于冪律藐翎,在集合中的鍵的大部分訪問使用LRU近似算法將會處理的很好材蹬。
在模擬中我們發(fā)現(xiàn)使用冪律訪問模式時,真LRU算法和Redis近似算法的差異非常小或者不存在吝镣。
然而堤器,為了接近真的LRU,你可以提升樣本量到10末贾,這樣會使用一點額外的CPU資源闸溃,然后檢查緩存丟失率會有什么不同。
可以通過CONFIG SET maxmemory-samples <count>
命令拱撵,在生產(chǎn)環(huán)境中使用不同的樣本值做實驗辉川,這非常簡單。
新的LFU模式
從Redis4.0開始拴测,可以使用一個新的最少使用頻率回收模式乓旗。在某些下這個模式可以工作的更好(提供一個更好的命中/丟失率),因為使用LFU集索,Redis將會嘗試追蹤項目的訪問頻率屿愚,所以使用頻率非常小的將會被回收,同時使用非常頻繁的會有更多的機會被保存在內(nèi)存中务荆。
如果你在思考LRU妆距,一個最近訪問過但是實際上幾乎從未被請求的項目,將不會被過期函匕,因此有一個風險是回收一個未來有很多機會被訪問的鍵娱据。LFU不會有這個問題,并且通常應(yīng)該對不同的訪問模式適配的更好盅惜。
配置LFU有以下幾種模式:
-
volatile-lfu
使用近似LFU算法回收擁有過期時間的鍵 -
allkeys-lfu
使用近似LFU算法回收所有鍵
LFU類似于LRU:它使用一個被稱為莫里斯計數(shù)器的概率計數(shù)器中剩,以便評估對象的訪問頻率,每個對象僅使用少量的字節(jié)酷窥,組合一個衰減周期,因此計數(shù)器隨著時間流逝而減少:在某個時間點我們不再認為這個鍵是被頻繁訪問的伴网,即使是在過去蓬推,因此這個算法可以適應(yīng)訪問模式的改變。
這些信息的取樣過程跟LRU的取樣過程(在本文檔前面的部分已經(jīng)解釋過)很類似澡腾,以便選擇一個候選對象回收沸伏。
然而糕珊,與LRU不同的是,LFU有確定的調(diào)節(jié)參數(shù):例如毅糟,如果一個項目不再被訪問红选,需要以多快的頻率降低它的等級?為了更好的適配特定案例的算法姆另,它也可以調(diào)節(jié)莫里斯計數(shù)器的范圍喇肋。
Redis4.0被默認設(shè)置為:
- 讓計數(shù)器飽和,大概100萬請求迹辐。
- 每分鐘把計數(shù)器衰減一次
那些是合理的值并經(jīng)過測試試驗過的蝶防,但是用戶可能想玩一下配置以選擇最佳值。
在源碼發(fā)行版的redis.conf
文件中可以找到如何調(diào)整這些參數(shù)的的介紹明吩,不過簡而言之间学,它們是:
lfu-log-factor 10
lfu-decay-time 1
衰減時間是一個很明顯的,當采樣和發(fā)現(xiàn)超過這個值時印荔,它是一個計數(shù)器必須衰減的分鐘數(shù)低葫。一個特別的值0
意味著:每次掃描時計數(shù)器都衰減,用途不是很大仍律。
計數(shù)器對數(shù)因子
改變需要多少次命中才能充滿頻率計數(shù)器嘿悬,取值范圍在0-255. 較高的因子,需要更多的訪問以達到最大值染苛。較低的因子鹊漠,是低訪問計數(shù)器的更好的解決方案,符合下面的表格:
+--------+------------+------------+------------+------------+------------+
| factor | 100 hits | 1000 hits | 100K hits | 1M hits | 10M hits |
+--------+------------+------------+------------+------------+------------+
| 0 | 104 | 255 | 255 | 255 | 255 |
+--------+------------+------------+------------+------------+------------+
| 1 | 18 | 49 | 255 | 255 | 255 |
+--------+------------+------------+------------+------------+------------+
| 10 | 10 | 18 | 142 | 255 | 255 |
+--------+------------+------------+------------+------------+------------+
| 100 | 8 | 11 | 49 | 143 | 255 |
+--------+------------+------------+------------+------------+------------+
因此茶行,基本上來講躯概,這個因子是分別低訪問量 VS 高訪問量之間更好的一種權(quán)衡。更多的信息可以在redis.conf
文件自身的描述中看到畔师。
因為LFU是一個新的特征娶靡,我們都很感激對它在你的使用場景下與LRU相比表現(xiàn)如何的反饋。