Redis的過期策略以及內(nèi)存淘汰機(jī)制詳解
在談Redis過期概念時(shí),先拋出幾個(gè)問題:
- 1:Redis 給緩存數(shù)據(jù)設(shè)置過期時(shí)間?
- 2:Redis 是如何判斷數(shù)據(jù)是否過期的呢?
- 3:大量 key 集中過期怎么辦?
那么代入問題,根據(jù)概念思考這幾個(gè)問題吧
Redis有三種數(shù)據(jù)過期策略:定時(shí)刪除,惰性刪除,定期刪除
???一、過期策略
1、惰性刪除
當(dāng)讀/寫一個(gè)已經(jīng)過期的key時(shí),會(huì)觸發(fā)惰性刪除策略,判斷key是否過期,如果過期了直接刪除掉這個(gè)key
簡(jiǎn)而言之:就是當(dāng)被讀寫的時(shí)候,再判斷是否過期再刪除
對(duì)于過期的key不作任何處理,當(dāng)獲取key時(shí)檢查key是否過期,過期就刪除,否則直接返回。
- 優(yōu)點(diǎn):刪除key操作只在取出key時(shí)發(fā)生,只刪除當(dāng)前key,占用CPU少。
- 缺點(diǎn):當(dāng)大量key超出過期時(shí)間后未被使用,會(huì)占用大量?jī)?nèi)存
2、定時(shí)刪除
由于惰性刪除策略無法保證冷數(shù)據(jù)被及時(shí)的刪掉,所以Redis會(huì)定期(默認(rèn)每100ms)主動(dòng)淘汰一批已過期的key,這里的一批只是部分過期的key,所以可能會(huì)出現(xiàn)部分key已經(jīng)過期但是還沒有被清理掉的情況,導(dǎo)致內(nèi)存沒有被及時(shí)釋放
簡(jiǎn)而言之:每隔一定時(shí)間刪除
在設(shè)置key的過期時(shí)間時(shí)設(shè)置定時(shí)器,當(dāng)key過期時(shí)通過定時(shí)器刪除key。
- 優(yōu)點(diǎn):保證過期的key被及時(shí)刪除。
- 缺點(diǎn):在key過多時(shí),刪除key會(huì)占用cpu資源,對(duì)服務(wù)器的響應(yīng)時(shí)間和吞吐量造成影響。同時(shí)為每個(gè)key設(shè)置定時(shí)器有性能消耗
3、定期刪除
redis默認(rèn)每隔100ms就隨機(jī)抽取一些設(shè)置了過期時(shí)間的key,檢查其是否過期,如果有過期就刪除。注意這里是隨機(jī)抽取的。為什么要隨機(jī)呢?你想一想假如 redis 存了幾十萬個(gè) key ,每隔100ms就遍歷所有的設(shè)置過期時(shí)間的 key 的話,就會(huì)給 CPU 帶來很大的負(fù)載
簡(jiǎn)而言之:隨機(jī)每隔一定時(shí)間刪除
定時(shí)刪除和惰性刪除的這種方案,每隔一段時(shí)間檢查redis中過期的key,并通過限制刪除執(zhí)行的時(shí)長(zhǎng)和頻率。
- 優(yōu)點(diǎn):刪除key時(shí)限制了刪除操作的時(shí)長(zhǎng)和頻率,減少了對(duì)CPU的影響。即使刪除了過期key,減少了內(nèi)存的占用。
- 缺點(diǎn):如果定期刪除太頻繁,或者執(zhí)行時(shí)間太長(zhǎng),會(huì)退化為定時(shí)刪除,占用CPU資源。如果刪除執(zhí)行時(shí)間太短,或者執(zhí)行頻率低,會(huì)退化為惰性刪除,出現(xiàn)內(nèi)存浪費(fèi)。
Redis使用的是定期刪除+惰性刪除的策略,在合理使用CPU和避免內(nèi)存浪費(fèi)之間平衡
定期刪除+惰性刪除存在的問題
如果某個(gè)key過期后,定期刪除沒刪除成功,然后也沒再次去請(qǐng)求key,也就是說惰性刪除也沒生效。這時(shí),如果大量過期的key堆積在內(nèi)存中,redis的內(nèi)存會(huì)越來越高,導(dǎo)致redis的內(nèi)存塊耗盡。那么就應(yīng)該采用內(nèi)存淘汰機(jī)制
二、內(nèi)存淘汰機(jī)制
???1、內(nèi)存淘汰策略
Redis Key沒設(shè)置過期時(shí)間為什么被Redis主動(dòng)刪除了?
當(dāng)Redis已用內(nèi)存超過maxmemory限定時(shí),就會(huì)觸發(fā)主動(dòng)清理策略
在 redis.conf 中有一行配置:
# maxmemory-policy noeviction
Redis的默認(rèn)淘汰策略是noeviction
執(zhí)行流程如下
主動(dòng)清理策略在Redis4.0之前一共實(shí)現(xiàn)了8種內(nèi)存淘汰策略
a)針對(duì)設(shè)置了過期時(shí)間的key做處理:
- 1、volatile-ttl:在設(shè)置了過期時(shí)間的鍵值對(duì)中,移除即將過期的鍵值對(duì)。
- 2、volatile-random:在設(shè)置了過期時(shí)間的鍵值對(duì)中,隨機(jī)移除某個(gè)鍵值對(duì)。
- 3、volatile-lru:在設(shè)置了過期時(shí)間的鍵值對(duì)中,移除最近最少使用的鍵值對(duì)。
- 4、volatile-lfu:在設(shè)置了過期時(shí)間的鍵值對(duì)中,移除最近最不頻繁使用的鍵值對(duì)
b)針對(duì)所有的key做處理:
- 5、allkeys-random:在所有鍵值對(duì)中,隨機(jī)移除某個(gè)key。
- 6、allkeys-lru:在所有的鍵值對(duì)中,移除最近最少使用的鍵值對(duì)。
- 7、allkeys-lfu:在所有的鍵值對(duì)中,移除最近最不頻繁使用的鍵值對(duì)
c)不處理:
- 8、noeviction:不進(jìn)行淘汰數(shù)據(jù)。不會(huì)刪除任何數(shù)據(jù),拒絕所有寫入操作并返回客戶端錯(cuò)誤信息"(error) OOM command not allowed when used memory",此時(shí)Redis只響應(yīng)讀操作
一旦緩存被寫滿,再有寫請(qǐng)求進(jìn)來,Redis就不再提供服務(wù),而是直接返回錯(cuò)誤。Redis 用作緩存時(shí),實(shí)際的數(shù)據(jù)集通常都是大于緩存容量的,總會(huì)有新的數(shù)據(jù)要寫入緩存,這個(gè)策略本身不淘汰數(shù)據(jù),也就不會(huì)騰出新的緩存空間,我們不把它用在 Redis 緩存中
???2、內(nèi)存淘汰算法
從內(nèi)測(cè)淘汰策略分類上,我們可以得知,除了隨機(jī)刪除和不刪除之外,主要有兩種淘汰算法:LRU 算法和 LFU 算法
- LRU算法(Least Recently Used,最近最少使用):淘汰很久沒被訪問過的數(shù)據(jù),以最近一次訪問時(shí)間作為參考
- LFU算法(Least Frequently Used,最不經(jīng)常使用):淘汰最近一段時(shí)間被訪問次數(shù)最少得數(shù)據(jù),以次數(shù)作為參考
絕大多數(shù)情況,使用LRU算法,當(dāng)存在大量熱點(diǎn)緩存數(shù)據(jù)時(shí),LFU可能更好點(diǎn)
三、Lazy-Free機(jī)制
Lazy-Free 特性是 Redis 4.0 開始引入的,指的是讓 Redis 采用異步方式延遲釋放 key 使用的內(nèi)存,將該操作交給單獨(dú)的子線程處理,避免阻塞主線程
目的是減少刪除鍵時(shí)對(duì)主線程的影響,從而提高 Redis 的整體性能。
Lazy Free 主要有兩種應(yīng)用場(chǎng)景:
- 主動(dòng)刪除:使用 UNLINK 命令代替 DEL 命令來刪除鍵。UNLINK 命令會(huì)在后臺(tái)異步地釋放內(nèi)存
- 被動(dòng)刪除:在某些情況下,如過期鍵的刪除或達(dá)到最大內(nèi)存限制時(shí)的緩存淘汰,Redis 會(huì)嘗試異步地釋放內(nèi)存。
Lazy Free 與緩存淘汰的關(guān)系
雖然 Lazy Free 不是緩存淘汰機(jī)制的一部分,但在緩存淘汰過程中,Lazy Free 可以用來優(yōu)化緩存淘汰操作的執(zhí)行方式,減少對(duì) Redis 性能的影響。具體來說:
1、減少主線程阻塞:
在緩存淘汰策略中,當(dāng) Redis 需要?jiǎng)h除鍵來釋放內(nèi)存時(shí),使用 Lazy Free 可以減少主循環(huán)的阻塞時(shí)間。這是因?yàn)閯h除操作是在后臺(tái)線程中完成的,而不是立即執(zhí)行
2、提高性能:
Lazy Free 可以幫助提高 Redis 的性能,特別是在高負(fù)載的情況下,因?yàn)樗鼫p少了刪除操作對(duì)主線程的影響。
3、與緩存淘汰策略的交互:
當(dāng) Redis 需要根據(jù)緩存淘汰策略刪除鍵時(shí),如果啟用了 Lazy Free,那么這些刪除操作可能會(huì)被異步執(zhí)行,這有助于減少對(duì)客戶端請(qǐng)求的延遲影響
例子:假設(shè) Redis 的緩存淘汰策略配置為 allkeys-lru,并且啟用了 Lazy Free
當(dāng) Redis 達(dá)到最大內(nèi)存限制時(shí),它會(huì)根據(jù) LRU 策略選擇一些鍵來刪除。
如果這些鍵滿足 Lazy Free 的條件(例如,使用了 UNLINK 命令或配置了相應(yīng)的 Lazy Free 選項(xiàng)),那么這些鍵的刪除操作將在后臺(tái)異步執(zhí)行,而不是立即在主線程中執(zhí)行
也就是說如果沒有Lazy Free,執(zhí)行緩存淘汰策略時(shí),刪除鍵的操作將會(huì)同步執(zhí)行,可能會(huì)阻塞主線程,影響其他客戶端的請(qǐng)求
四、相關(guān)問題
好了,來解決上面拋出的問題
1:Redis 給緩存數(shù)據(jù)設(shè)置過期時(shí)間?
(1)Redis的內(nèi)存是有限的
- 如果不對(duì)緩存數(shù)據(jù)設(shè)置過期時(shí)間,那內(nèi)存占用就會(huì)一直增長(zhǎng),最終可能會(huì)導(dǎo)致 OOM 問題。
- 通過設(shè)置合理的過期時(shí)間,Redis 會(huì)自動(dòng)刪除暫時(shí)不需要的數(shù)據(jù),為新的緩存數(shù)據(jù)騰出空間
(2)某些業(yè)務(wù)場(chǎng)景需要某些數(shù)據(jù)在一段時(shí)間后過期
- 比如我們的短信驗(yàn)證碼可能只在 1 分鐘內(nèi)有效,用戶登錄的 Token 可能只在 1 天內(nèi)有效
- 如果使用傳統(tǒng)的數(shù)據(jù)庫來處理的話,一般都是自己判斷過期,這樣更麻煩并且性能要差很多
2:Redis 是如何判斷數(shù)據(jù)是否過期的呢?
- Redis 通過一個(gè)叫做過期字典(可以看作是 hash 表)來保存數(shù)據(jù)過期的時(shí)間。過期字典的鍵指向 Redis 數(shù)據(jù)庫中的某個(gè) key(鍵)
- 過期字典的值是一個(gè) long類型的整數(shù),這個(gè)整數(shù)保存了 key 所指向的數(shù)據(jù)庫鍵的過期時(shí)間(毫秒精度的 UNIX 時(shí)間戳)
- 在查詢一個(gè) key 的時(shí)候,Redis 首先檢查該 key 是否存在于過期字典中(時(shí)間復(fù)雜度為 O(1)),如果不在就直接返回,在的話需要判斷一下這個(gè) key 是否過期,過期直接刪除 key 然后返回 null。
3:大量 key 集中過期怎么辦?
如果存在大量 key 集中過期的問題,可能會(huì)使 Redis 的請(qǐng)求延遲變高。可以采用下面的可選方案來應(yīng)對(duì):
- 盡量避免 key 集中過期,在設(shè)置鍵的過期時(shí)間時(shí)盡量隨機(jī)一點(diǎn)。
- 對(duì)過期的 key 開啟 lazyfree 機(jī)制(修改 redis.conf 中的 lazyfree-lazy-expire參數(shù)即可),這樣會(huì)在后臺(tái)異步刪除過期的 key,不會(huì)阻塞主線程的運(yùn)行。
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
幾分鐘教你掌握Redis簡(jiǎn)單動(dòng)態(tài)字符串SDS
這篇文章主要為大家介紹了幾分鐘教你掌握Redis簡(jiǎn)單動(dòng)態(tài)字符串SDS方法,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-01-01Redis?中使用?list,streams,pub/sub?幾種方式實(shí)現(xiàn)消息隊(duì)列的問題
這篇文章主要介紹了Redis?中使用?list,streams,pub/sub?幾種方式實(shí)現(xiàn)消息隊(duì)列,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-03-03深入解析Redis中常見的應(yīng)用場(chǎng)景
這篇文章主要給大家介紹了關(guān)于Redis中常見的應(yīng)用場(chǎng)景的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧。2017-09-09redis 億級(jí)數(shù)據(jù)讀取的實(shí)現(xiàn)
本文主要介紹了redis 億級(jí)數(shù)據(jù)讀取的實(shí)現(xiàn),億級(jí)數(shù)據(jù)規(guī)模下實(shí)現(xiàn)高效的數(shù)據(jù)讀取成為了許多企業(yè)和開發(fā)者面臨的重大挑戰(zhàn),下面就來介紹一下,感興趣的可以了解一下2024-08-08