面試官問:Redis 緩存淘汰策略有哪些?
我們知道:Redis是基于內(nèi)存的,面試官問:
- 生產(chǎn)環(huán)境Redis內(nèi)存如何分配?
- Redis鍵過期了如何刪除?
- ......
本小節(jié)不僅適用于工作,也是面試的高頻問題。
文章導(dǎo)讀
Redis內(nèi)存分析
1.Redis默認(rèn)內(nèi)存是多少?
在 64bit 系統(tǒng)下,默認(rèn)不限制內(nèi)存大小,不設(shè)置內(nèi)存大小和maxmemory = 0表示不限制 Redis 內(nèi)存使用
2.如何查看Redis最大內(nèi)存是多少?
命令行:
127.0.0.1:6379> config get maxmemory
1) "maxmemory"
2) "0"
配置文件 redis.conf:
# maxmemory <bytes>
3.如何查看Redis內(nèi)存使用情況?
127.0.0.1:6379> info memory
4.如何配置和修改?
臨時(shí)方案,通過命令修改:
127.0.0.1:6379> config set maxmemory 104857600
OK
127.0.0.1:6379> config get maxmemory
1) "maxmemory"
2) "104857600"
永久方案,通過配置文件:
5.生產(chǎn)環(huán)境如何配置?
建議:一般取物理內(nèi)存的3/4
Redis過期鍵刪除?
我們知道,redis一般會(huì)設(shè)置過期時(shí)間。那么這些鍵過期了是立刻從內(nèi)存中刪除嗎?
通常,鍵刪除會(huì)有不同的策略。
1.立刻刪除
立即刪除能保證過期鍵值會(huì)在過期后馬上被刪除,其所占用的內(nèi)存也會(huì)隨之釋放。但是刪除操作會(huì)占用cpu的時(shí)間,造成CPU額外的壓力。
redis.conf 中,通過調(diào)整過期鍵的檢測頻率:
# The range is between 1 and 500, however a value over 100 is usually not
# a good idea. Most users should use the default of 10 and raise this up to
# 100 only in environments where very low latency is required.
hz 10
但是這會(huì)產(chǎn)生大量的性能消耗,同時(shí)也會(huì)影響數(shù)據(jù)的讀取操作。
2.惰性刪除
數(shù)據(jù)到達(dá)過期時(shí)間,不做處理。等下次訪問該數(shù)據(jù)時(shí):
- 如果未過期,返回?cái)?shù)據(jù) ;
- 發(fā)現(xiàn)已過期,刪除,返回不存在。
惰性刪除策略的缺點(diǎn)是,它對(duì)內(nèi)存是最不友好的。如果一個(gè)鍵已經(jīng)過期,而這個(gè)鍵又仍然保留在redis中,那么只要這個(gè)過期鍵不被刪除,它所占用的內(nèi)存就不會(huì)釋放。
#開啟憜性淘汰
lazyfree-lazy-eviction=yes
3.定期刪除
這種方案有效規(guī)避上述兩種極端情況, 定期刪除策略的難點(diǎn)是確定刪除操作執(zhí)行的時(shí)長和頻率:
- 如果刪除操作執(zhí)行得太頻繁或者執(zhí)行的時(shí)間太長,定期刪除策略就會(huì)退化成立即刪除策略。
- 如果刪除操作執(zhí)行得太少,或者執(zhí)行的時(shí)間太短,定期刪除策略又會(huì)和惰性刪除束略一樣,出現(xiàn)浪費(fèi)內(nèi)存的情況。
- 因此,如果采用定期刪除策略的話,服務(wù)器必須根據(jù)情況,合理地設(shè)置刪除操作的執(zhí)行時(shí)長和執(zhí)行頻率。
Redis內(nèi)存淘汰策略
基于上述的了解,假如:
- 定期刪除時(shí),從來沒有被抽查到
- 惰性刪除時(shí),也從來沒有被點(diǎn)中使用過
上述兩個(gè)步驟,依然會(huì)有大量過期的key堆積在內(nèi)存中,導(dǎo)致redis內(nèi)存空間緊張或者很快耗盡。
因此,有沒有一個(gè)更好的兜底方案......?這就是要講的淘汰策略
1.LRU和LFU區(qū)別?
(1) LRU(Least Recently Used,最近最少使用頁面置換算法)
假設(shè)我們有一個(gè)容量為3的LRU緩存,訪問數(shù)據(jù)的順序如下:
- 訪問數(shù)據(jù)1,緩存中現(xiàn)在有:[1]
- 訪問數(shù)據(jù)2,緩存中現(xiàn)在有:[1, 2]
- 訪問數(shù)據(jù)3,緩存中現(xiàn)在有:[1, 2, 3]
- 再次訪問數(shù)據(jù)1,緩存中現(xiàn)在有:[2, 3, 1](因?yàn)?被重新訪問,它被移到了列表的末尾)
- 訪問數(shù)據(jù)4,由于緩存已滿,最不常用的數(shù)據(jù)2將被淘汰,緩存中現(xiàn)在有:[3, 1, 4]
原理:如果數(shù)據(jù)最近被訪問過,那么在不久的將來它很可能再次被訪問。因此,LRU會(huì)淘汰最長時(shí)間未被訪問的數(shù)據(jù)。
適用場景:適用于最近被訪問的數(shù)據(jù)在未來某個(gè)時(shí)間點(diǎn)很可能再次被訪問。
(2) LFU(Least Frequently Used,最近最不常用頁面置換算法)
假設(shè)我們有一個(gè)容量為3的LFU緩存,訪問數(shù)據(jù)的順序如下:
- 訪問數(shù)據(jù)1,計(jì)數(shù)器:{1: 1}
- 訪問數(shù)據(jù)2,計(jì)數(shù)器:{1: 1, 2: 1}
- 訪問數(shù)據(jù)1,計(jì)數(shù)器:{1: 2, 2: 1}
- 訪問數(shù)據(jù)3,計(jì)數(shù)器:{1: 2, 2: 1, 3: 1}
- 訪問數(shù)據(jù)1,計(jì)數(shù)器:{1: 3, 2: 1, 3: 1}
- 訪問數(shù)據(jù)4,由于緩存已滿,訪問次數(shù)最少的數(shù)據(jù)2將被淘汰,計(jì)數(shù)器:{1: 3, 3: 1, 4: 1}
原理:LFU算法會(huì)跟蹤每個(gè)頁面在特定時(shí)間段內(nèi)被訪問的頻率。當(dāng)需要淘汰頁面時(shí),LFU算法會(huì)淘汰在該時(shí)間段內(nèi)訪問次數(shù)最少的頁面。
適用場景:LFU算法適用于那些訪問模式可能隨時(shí)間變化的場景,或者訪問頻率能夠較好地反映頁面重要性的情況。
(3) 小結(jié)
- LRU關(guān)注數(shù)據(jù)的最近訪問時(shí)間,淘汰最長時(shí)間未被訪問的數(shù)據(jù)。
- LFU關(guān)注數(shù)據(jù)的訪問頻率,淘汰訪問次數(shù)最少的數(shù)據(jù)。
2.Redis有哪些淘汰策略?
redis.config 配置文件中,
# volatile-lru -> Evict using approximated LRU, only keys with an expire set.
# allkeys-lru -> Evict any key using approximated LRU.
# volatile-lfu -> Evict using approximated LFU, only keys with an expire set.
# allkeys-lfu -> Evict any key using approximated LFU.
# volatile-random -> Remove a random key having an expire set.
# allkeys-random -> Remove a random key, any key.
# volatile-ttl -> Remove the key with the nearest expire time (minor TTL)
# noeviction -> Don't evict anything, just return an error on write operations.
解釋下:
- volatile-lru:使用近似的最近最少使用(LRU)算法淘汰鍵。但是,只有那些設(shè)置了過期時(shí)間的鍵(即“volatile”鍵)才會(huì)被考慮淘汰。
- allkeys-lru:使用近似的LRU算法淘汰任何鍵,無論它們是否設(shè)置了過期時(shí)間。
- volatile-lfu:使用近似的最少頻率使用(LFU)算法淘汰鍵。同樣,只有設(shè)置了過期時(shí)間的鍵會(huì)被考慮。
- allkeys-lfu:使用近似的LFU算法淘汰任何鍵,不考慮它們是否設(shè)置了過期時(shí)間。
- volatile-random:隨機(jī)淘汰一個(gè)設(shè)置了過期時(shí)間的鍵。
- allkeys-random:隨機(jī)淘汰任何鍵,不論它們是否設(shè)置了過期時(shí)間。
- volatile-ttl:淘汰具有最短剩余生存時(shí)間(TTL)的鍵,即那些最接近過期時(shí)間的鍵。
- noeviction:不淘汰任何鍵。當(dāng)內(nèi)存達(dá)到最大容量時(shí),Redis將不會(huì)進(jìn)行任何淘汰操作,而是在寫入新數(shù)據(jù)時(shí)返回錯(cuò)誤。
3.生產(chǎn)如何選擇淘汰策略?
在生產(chǎn)環(huán)境中選擇緩存淘汰策略時(shí),通常需要根據(jù)應(yīng)用的具體需求和數(shù)據(jù)特性來定。這里給出常見案例:
(1) 電商平臺(tái)的商品推薦
電商平臺(tái)需要為用戶展示個(gè)性化的商品推薦,其中熱門商品的訪問頻率較高。可選擇:LFU(Least Frequently Used)
redis-cli config set maxmemory-policy allkeys-lfu
因?yàn)長FU策略可以保留訪問頻率高的商品,確保推薦列表中展示用戶最可能感興趣的商品。
(2) 金融交易平臺(tái)的實(shí)時(shí)數(shù)據(jù)
金融交易平臺(tái)需要提供實(shí)時(shí)的股票價(jià)格和交易數(shù)據(jù),數(shù)據(jù)的實(shí)時(shí)性至關(guān)重要。過期的時(shí)價(jià)被淘汰。
可選擇:TTL(Time To Live)結(jié)合LRU(Least Recently Used)
redis-cli config set maxmemory-policy volatile-lru
TTL確保數(shù)據(jù)在一定時(shí)間后自動(dòng)過期,而LRU保證最近訪問的數(shù)據(jù)被優(yōu)先保留。
(3) 電信運(yùn)營商的用戶數(shù)據(jù)管理
電信運(yùn)營商需要處理和緩存大量用戶的通話記錄、短信記錄等,用戶通常更關(guān)心最近的通信記錄。
可選擇:LRU(Least Recently Used)
redis-cli config set maxmemory-policy allkeys-lru
因?yàn)長RU策略可以確保最近生成的通話記錄和短信記錄被優(yōu)先緩存。
(4) 社交媒體平臺(tái)的用戶動(dòng)態(tài)
社交媒體平臺(tái)需要為用戶展示好友的最新動(dòng)態(tài)和帖子,用戶通常對(duì)最新動(dòng)態(tài)感興趣。
可選擇:LRU
redis-cli config set maxmemory-policy allkeys-lru
因?yàn)長RU可以保證最新的帖子被優(yōu)先展示。
好了,今天就聊到這里,讀者可依據(jù)實(shí)際情況擇優(yōu)選擇策略。