欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Redis過期Key刪除策略和內(nèi)存淘汰策略的實(shí)現(xiàn)

 更新時(shí)間:2024年02月19日 09:04:19   作者:Surpass余sheng軍  
當(dāng)內(nèi)存使用達(dá)到上限,就無法存儲更多數(shù)據(jù)了,為了解決這個(gè)問題,Redis內(nèi)部會有兩套內(nèi)存回收的策略,過期Key刪除策略和內(nèi)存淘汰策略,本文就來詳細(xì)的介紹一下這兩種方法,感興趣的可以了解一下

Redis之所以性能強(qiáng),最主要的原因就是基于內(nèi)存存儲,然而單節(jié)點(diǎn)的Redis其內(nèi)存大小不宜過大,否則會影響持久化或主從同步的性能。

Redis內(nèi)存滿了,會發(fā)生什么?

  • 在Redis的運(yùn)行內(nèi)存達(dá)到了某個(gè)閾值,就會觸發(fā)內(nèi)存淘汰機(jī)制  =>  防止把內(nèi)存撐爆,這個(gè)閾值就是我們設(shè)置的最大運(yùn)行內(nèi)存。 

我們可以通過修改redis.conf配置文件來設(shè)置Redis的最大內(nèi)存,配置項(xiàng)為maxmemory:

  • Redis默認(rèn)情況下是沒有對最大內(nèi)存大小做限制的,默認(rèn)情況下Redis就是根據(jù)你當(dāng)前的服務(wù)器里面,當(dāng)前最多可以申請到的內(nèi)存大小來去做限制! 
# 格式:
# maxmemory <bytes>
# 例如:
maxmemory 1gb

當(dāng)內(nèi)存使用達(dá)到上限,就無法存儲更多數(shù)據(jù)了,因此,為了解決這個(gè)問題,Redis內(nèi)部會有兩套內(nèi)存回收的策略:

  • 內(nèi)存過期策略
  • 內(nèi)存淘汰策略

內(nèi)存過期策略 - 過期key處理 - 過期刪除策略

如何設(shè)置過期時(shí)間?

  • expire key n秒     
  • pexpire key  n毫秒     
  • set   key  value  ex  n秒   
  • set  key  value nx  n毫秒

查看某個(gè)key剩余的存活時(shí)間:TTL  key 

  • 我們可以通過expire / EX命令給Redis的key設(shè)置TTL(過期時(shí)間 / 存活時(shí)間),單位:秒,當(dāng)key的TTL到期以后,即當(dāng)過期時(shí)間到了以后,再次訪問該key時(shí)返回的是nil,說明這個(gè)Key已經(jīng)不存在了,對應(yīng)的內(nèi)存也得到釋放,從而起到內(nèi)存回收的目的。
# 寫入一條數(shù)據(jù)
set num 123
# 設(shè)置20秒過期時(shí)間
expire num 20
# 寫入一條數(shù)據(jù)并設(shè)置20s過期時(shí)間
set num EX 20

Redis是如何知道一個(gè)key是否過期呢?

  • Redis本身是一個(gè)典型的key-value的鍵值型內(nèi)存存儲數(shù)據(jù)庫,因此所有的key-value都保存在Dict結(jié)構(gòu)中,在其redisDb結(jié)構(gòu)體中,有兩個(gè)Dict,也就是哈希表:一個(gè)用來記錄KEY-VALUE鍵值對(當(dāng)然存的不是真正的Key-Value,存儲的其實(shí)是RedisObject對應(yīng)的內(nèi)存地址的指針),另一個(gè)用來記錄key的TTL。

過期字典存儲在 redisDb 結(jié)構(gòu)中,如下: 

來看下redisDb的底層源碼:

typedef struct redisDb {
    dict dict;                 / The keyspace for this DB , 也就是存放KEY和VALUE的哈希表*/
    dict *expires;              /* 同樣是哈希表,但保存的是設(shè)置了TTL的KEY,及其到期時(shí)間*/
    dict *blocking_keys;        /* Keys with clients waiting for data (BLPOP)*/
    dict *ready_keys;           /* Blocked keys that received a PUSH */
    dict *watched_keys;         /* WATCHED keys for MULTI/EXEC CAS /
    int id;                     / Database ID, 0 ~ 15 /
    long long avg_ttl;          / Average TTL, just for stats /
    unsigned long expires_cursor; / Cursor of the active expire cycle. */
    list *defrag_later;         /* List of key names to attempt to defrag one by one, gradually. */
} redisDb;

每當(dāng)我們對一個(gè)key設(shè)置了過期時(shí)間后,Redis會把該key帶上過期時(shí)間存儲到一個(gè)過期字典(expires dict)中,也就是說「過期字典」保存了數(shù)據(jù)庫中所有 key 的過期時(shí)間。 

當(dāng)我們查詢一個(gè) key 時(shí),Redis 首先檢查該 key 是否存在于過期字典中:

  • 如果不在,則正常讀取鍵值;
  • 如果存在,則會獲取該 key 的過期時(shí)間,然后與當(dāng)前系統(tǒng)時(shí)間進(jìn)行比對,如果比系統(tǒng)時(shí)間大,那就沒有過期,否則判定該 key 已過期    =>   查詢到對應(yīng)的TTL,加以判斷即可。

是不是TTL到期就立即刪除了呢? 

TTL(Time To Live)的含義是存活時(shí)間。 

  • Redis并不會在Key過期時(shí)立刻刪除KEY,因?yàn)橐獙?shí)現(xiàn)這樣的效果就必須給每一個(gè)過期Key設(shè)置一個(gè)定時(shí)器,并監(jiān)控這些Key的過期狀態(tài),然后去做判斷,在key過期的那一刻給它立刻刪掉   =>  定時(shí)刪除,它的優(yōu)點(diǎn)就是保證過期key會被盡快刪除,也就是內(nèi)存可以盡快得到釋放,因此,定時(shí)刪除對內(nèi)存是最友好的;
  • 如果說我們的key比較少那還好,但是如果我們的key非常的多,達(dá)到數(shù)十萬甚至數(shù)百萬,那么這些key如果我們都給它設(shè)置這樣一個(gè)定時(shí)器,無論是對CPU還是對內(nèi)存都會帶來極大的負(fù)擔(dān),這樣一來,就會嚴(yán)重影響到Redis服務(wù)本身的一個(gè)性能,所以說這個(gè)是沒有辦法接受的,因此,我們在實(shí)際應(yīng)用當(dāng)中,Redis采用的并不是立即刪除,而是惰性刪除  + 周期刪除  =>   Redis 使用的過期刪除策略是「惰性刪除+定期刪除」這兩種策略配和使用,刪除的對象是已過期的 key。

Redis的過期KEY刪除策略有兩種:

  • 惰性刪除

  • 周期刪除或定期刪除

惰性刪除

  • 顧名思義就是TTL過期后不會立刻刪除,惰性刪除策略的做法是,不主動刪除過期鍵,而是在訪問使用一個(gè)key的時(shí)候,判斷當(dāng)前key有沒有設(shè)置TTL過期時(shí)間,如果有,則檢查該key的存活時(shí)間,如果發(fā)現(xiàn)key已經(jīng)過期才執(zhí)行刪除操作,如果沒有過期,不做任何處理,然后返回正常的鍵值對給客戶端。 

惰性刪除策略的優(yōu)缺點(diǎn):

優(yōu)點(diǎn):

  • 因?yàn)槊看卧L問時(shí),才會檢查該key是否過期,因此惰性刪除策略可以節(jié)省CPU資源,對CPU時(shí)間最友好。

缺點(diǎn):

  • 如果一個(gè)key已經(jīng)過期,而這個(gè)key又仍然保留在數(shù)據(jù)庫中,那么只要這個(gè)過期key一致沒有被訪問,它所占用的內(nèi)存就不會釋放,會造成一定的內(nèi)存空間浪費(fèi),所以惰性刪除策略對內(nèi)存不友好   =>   這不就是會導(dǎo)致內(nèi)存泄漏嗎???

周期刪除 / 定期刪除策略

  • 顧名思義就是通過一個(gè)定時(shí)任務(wù),每隔一段時(shí)間周期性的從數(shù)據(jù)庫中抽取一定數(shù)量的key進(jìn)行檢查,并刪除其中的過期key。

Redis默認(rèn)會每秒進(jìn)行10次過期檢查(此配置可以通過Redis的配置文件redis.conf進(jìn)行配置,配置鍵為hz,它的默認(rèn)值是hz 10),每次檢查數(shù)據(jù)庫并不是遍歷過期字典中的所有key,而是從數(shù)據(jù)庫中隨機(jī)抽取一定數(shù)量的key進(jìn)行過期檢查:

  • 從過期字典中隨機(jī)抽取20個(gè)key;
  • 檢查這20個(gè)key是否過期,并刪除已過期的key;
  • 如果本輪檢查的已過期key的數(shù)量,超過5個(gè)(5 / 20 = 1 / 4 = 25%),也就是「已過期 key 的數(shù)量」占比「隨機(jī)抽取 key 的數(shù)量」大于 25%,則繼續(xù)隨機(jī)抽查,重復(fù)步驟1;如果已過期的key的比例小于25%,則停止繼續(xù)刪除過期key,退出本輪檢查,然后等待下一輪再檢查。 

可以看到,定期刪除是一個(gè)循環(huán)的流程。

Redis為了保證定期刪除不會出現(xiàn)循環(huán)過度,導(dǎo)致線程卡死現(xiàn)象,為此增加了定期刪除循環(huán)流程的時(shí)間上限,默認(rèn)不會超過25ms,超出時(shí)間限制則退出。 

定期刪除策略的優(yōu)缺點(diǎn)

優(yōu)點(diǎn):

  • 定期刪除是Redis的主動刪除策略,它可以確保過期key能夠及時(shí)被刪除

缺點(diǎn):

  • 會占用CPU資源去掃描key,可能會影響到Redis的性能 

可以看到,惰性刪除策略和定期刪除策略都有各自的優(yōu)缺點(diǎn),所以Redis選擇「惰性刪除+定期刪除」這兩種策略配和使用,以求在合理使用 CPU 時(shí)間和避免內(nèi)存浪費(fèi)之間取得平衡。 

如果過期鍵沒有被訪問,而定期刪除又跟不上新鍵產(chǎn)生的速度,內(nèi)存不就慢慢耗盡了嗎? 

內(nèi)存淘汰策略

內(nèi)存淘汰:

  • 就是當(dāng)Redis的內(nèi)存使用達(dá)到設(shè)置的閾值時(shí),Redis就會主動挑選部分key刪除以釋放更多內(nèi)存的流程,這就叫做內(nèi)存淘汰機(jī)制。
  • 內(nèi)存淘汰策略是解決內(nèi)存過大的問題。

內(nèi)存淘汰時(shí)機(jī)

當(dāng)內(nèi)存達(dá)到閾值時(shí)執(zhí)行內(nèi)存淘汰,但問題是Redis什么時(shí)候會去判斷內(nèi)存是否達(dá)到閾值呢?

  • Redis每次執(zhí)行任何命令時(shí),都會判斷內(nèi)存是否達(dá)到閾值。

當(dāng)Redis內(nèi)存不足時(shí)會怎么做?

  • 這取決于配置的內(nèi)存淘汰策略,Redis支持很多種內(nèi)存淘汰策略,例如LRU、LFU、Random,但默認(rèn)的策略是直接決絕新的寫入請求,而如果設(shè)置了其它策略,則會在每次執(zhí)行命令后判斷內(nèi)存占用是否達(dá)到閾值,如果達(dá)到閾值則會基于配置的內(nèi)存淘汰策略嘗試進(jìn)行內(nèi)存淘汰,直到占用內(nèi)存小于閾值為止。 

Redis 內(nèi)存淘汰策略有哪些? 

Redis支持內(nèi)存淘汰,配置參數(shù)maxmemory-policy決定了內(nèi)存淘汰策略,這個(gè)參數(shù)一共有8個(gè)枚舉值,也就是說Redis內(nèi)存淘汰策略共有8種,這八種策略大體分為「不進(jìn)行數(shù)據(jù)淘汰」和「進(jìn)行數(shù)據(jù)淘汰」兩類策略:

1. 不進(jìn)行數(shù)據(jù)淘汰的策略

  • noevictionRedis3.0之后,默認(rèn)的內(nèi)存淘汰策略) :禁止刪除數(shù)據(jù),它表示當(dāng)Redis的運(yùn)行內(nèi)存超過最大設(shè)置內(nèi)存時(shí),也就是當(dāng)Redis內(nèi)存滿時(shí),不淘汰任何鍵值對數(shù)據(jù),而是不再提供服務(wù),不允許寫入新數(shù)據(jù),Redis的寫命令會直接返回錯(cuò)誤信息(但是讀命令還是可以正常返回)。

2. 進(jìn)行數(shù)據(jù)淘汰的策略

針對「進(jìn)行數(shù)據(jù)淘汰」這一類策略,又可以細(xì)分為「在設(shè)置了過期時(shí)間的數(shù)據(jù)中進(jìn)行淘汰」和「在所有數(shù)據(jù)范圍內(nèi)進(jìn)行淘汰」這兩類策略。 在設(shè)置了過期時(shí)間的數(shù)據(jù)中進(jìn)行淘汰:

  • volatile-random:隨機(jī)淘汰設(shè)置了過期時(shí)間的任意鍵值 - 從已設(shè)置過期時(shí)間的數(shù)據(jù)集中任意選擇數(shù)據(jù)淘汰;
  • volatile-ttl從已設(shè)置過期時(shí)間的數(shù)據(jù)集中挑選將要過期的數(shù)據(jù)淘汰:比較key的剩余TTL值,TTL越小越先被淘汰。
  • volatile-lru(Redis3.0 之前,默認(rèn)的內(nèi)存淘汰策略):LRU(Least Recently Used),最近最久未使用,利用LRU算法淘汰所有設(shè)置了TTL過期時(shí)間的鍵值中,最久未使用的鍵值;
  • volatile-lfu(Redis 4.0 后新增的內(nèi)存淘汰策略):LFU(Least Frequently Used),最少頻率使用,淘汰所有設(shè)置了TTL過期時(shí)間的鍵值中,最少使用的鍵值;

在所有數(shù)據(jù)范圍內(nèi)進(jìn)行淘汰:

  • allkeys-random:對全體key,隨機(jī)進(jìn)行淘汰;
  • allkeys-lruLRU(Least Recently Used),最近最久未使用,淘汰全體鍵值中最久未使用的鍵值;
  • allkeys-lfuRedis 4.0 后新增的內(nèi)存淘汰策略)::LFU(Least Frequently Used),最少頻率使用,淘汰整個(gè)鍵值中最少使用的鍵值,即訪問頻率最低的那個(gè)key-value。

比較容易混淆的有兩個(gè)算法:

  • LRU(Least Recently Used),最近最久未使用(根據(jù)訪問時(shí)間淘汰),會選擇淘汰最近最少使用的數(shù)據(jù),用當(dāng)前時(shí)間減去最后一次訪問時(shí)間,這個(gè)值越大則淘汰優(yōu)先級越高。
  • LFU(Least Frequently Used),最少頻率使用(根據(jù)訪問頻率淘汰),LFU 算法是根據(jù)數(shù)據(jù)訪問次數(shù)來淘汰數(shù)據(jù)的,它的核心思想是“如果數(shù)據(jù)過去被訪問多次,那么將來被訪問的頻率也更高”,所以, LFU 算法會統(tǒng)計(jì)每個(gè)key的訪問頻率,值越小淘汰優(yōu)先級越高。 

Redis 4.0開始支持基于LFU算法的淘汰策略! 

Redis為什么新增了LFU淘汰策略?

為什么Redis 4.0有了LFU?

  • 比如Redis中的一個(gè)鍵,之前一直都沒有被訪問過,最近突然被訪問了一次,如果使用LRU淘汰策略就很難被淘汰,因?yàn)長RU會把它定義為熱鍵;
  • 而使用LFU淘汰策略該key就可能很快被淘汰,因?yàn)長RU優(yōu)先淘汰最近未被使用的,而LFU淘汰的是最近訪問頻率最低的。
  • LFU比LRU淘汰更精確,有助于提升Redis的緩存命中率。 

Redis怎么知道某個(gè)KEY的最后一次訪問時(shí)間或者是訪問頻率呢? 

  • redisObject結(jié)構(gòu)體當(dāng)中的lru就是記錄最近一次訪問時(shí)間和訪問頻率的,以低8位無符號數(shù)字來記錄邏輯訪問次數(shù)。
  • 邏輯訪問次數(shù)又是怎么回事呢?8位無符號數(shù)字最大才255,訪問次數(shù)超過255怎么辦?

邏輯訪問次數(shù)是如何計(jì)算的?

  • 由于記錄訪問次數(shù)的只有8bit,即便是無符號數(shù),最大值只有255,不可能記錄真實(shí)的訪問次數(shù),因此LFU的訪問次數(shù)之所以叫做邏輯訪問次數(shù),是因?yàn)椴⒉皇敲看蝛ey被訪問都計(jì)數(shù),Redis統(tǒng)計(jì)的其實(shí)是邏輯訪問次數(shù),這其中是一個(gè)計(jì)算公式,會根據(jù)當(dāng)前的訪問次數(shù)做計(jì)算,結(jié)果要么是次數(shù) + 1,要么是次數(shù)不變,且最大不超過255,除此以外,邏輯訪問次數(shù)還有一個(gè)衰減周期,訪問次數(shù)會隨時(shí)間衰減,默認(rèn)為1分鐘,即每隔1分鐘邏輯訪問次數(shù)會 -1,這樣邏輯訪問次數(shù)就能基本反映出一個(gè)key的訪問熱度了。

 顯然LFU的基于訪問頻率的統(tǒng)計(jì)更符合我們的淘汰目標(biāo),因此官方推薦使用LFU算法。 

內(nèi)存淘汰用到的是LRU算法嗎?

  • 嗯...Redis使用的是近似LRU算法,傳統(tǒng)LRU算法的實(shí)現(xiàn)需要一個(gè)雙向鏈表來記錄數(shù)據(jù)最近被訪問的順序,最新操作的鍵會被移動到表頭,當(dāng)需要內(nèi)存淘汰時(shí),只需要刪除鏈表尾部的數(shù)據(jù)即可,因?yàn)殒湵砦膊康脑鼐痛碜罹梦幢皇褂玫脑亍?nbsp;
  • 但是Redis中的KEY可能有數(shù)百萬甚至更多,出于節(jié)省內(nèi)存的考慮,Redis的LRU算法并非完整的實(shí)現(xiàn),Redis的算法并不是真正的LRU,而是一種基于抽樣的近似LRU算法!
  • Redis采用的是抽樣法,即每次抽樣一定數(shù)量(maxmemory-samples)的key,然后和目前維持的淘汰候選池綜合比較,然后基于內(nèi)存策略做排序,找出淘汰優(yōu)先級最高的,刪除這個(gè)key,這就使得算法的結(jié)果更接近于真正的LRU算法了,特別是在抽樣值較高的情況下(例如10),可以達(dá)到與真正的LRU接近的結(jié)果。

當(dāng)Redis作為緩存使用的時(shí)候,推薦使用allkeys-lru淘汰策略,該策略會將最近最久未使用的key淘汰,像這種key后期命中的概率也最低,所以將其淘汰。 

到此這篇關(guān)于Redis過期Key刪除策略和內(nèi)存淘汰策略的實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)Redis過期Key刪除策略和內(nèi)存淘汰策略內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Redis 命令整理并說明如何使用

    Redis 命令整理并說明如何使用

    這篇文章主要介紹了Redis 命令整理并說明如何使用的相關(guān)資料,需要的朋友可以參考下
    2017-02-02
  • Redis的RDB持久化與AOF持久化詳解

    Redis的RDB持久化與AOF持久化詳解

    這篇文章主要介紹了Redis的RDB持久化與AOF持久化詳解,Redis是許多公司都在使用的一款高性能、非關(guān)系型數(shù)據(jù)庫,其中最為重要的一個(gè)特性就是它支持持久化,本文將深入介紹Redis持久化原理,包括RDB和AOF兩種方式的實(shí)現(xiàn),需要的朋友可以參考下
    2023-07-07
  • 基于Redis實(shí)現(xiàn)分布式單號及分布式ID(自定義規(guī)則生成)

    基于Redis實(shí)現(xiàn)分布式單號及分布式ID(自定義規(guī)則生成)

    一些業(yè)務(wù)背景下,業(yè)務(wù)要求單號需要有區(qū)分不同的前綴,那么在分布式的架構(gòu)下如何自定義單號而且還能保證唯一呢?本文就來詳細(xì)的介紹一下
    2021-09-09
  • 淺談Redis哨兵模式高可用解決方案

    淺談Redis哨兵模式高可用解決方案

    Redis高可用有兩種模式:哨兵模式和集群模式,本文基于哨兵模式搭建一主兩從三哨兵Redis高可用服務(wù),感興趣的可以了解一下
    2022-03-03
  • redis 限制內(nèi)存使用大小的實(shí)現(xiàn)

    redis 限制內(nèi)存使用大小的實(shí)現(xiàn)

    這篇文章主要介紹了redis 限制內(nèi)存使用大小的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-05-05
  • redis加鎖的三種方式小結(jié)

    redis加鎖的三種方式小結(jié)

    本文主要介紹了redis加鎖的三種方式小結(jié),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-01-01
  • redis分布式鎖的問題與解決方法

    redis分布式鎖的問題與解決方法

    這篇文章主要給大家介紹了關(guān)于redis分布式鎖的問題與解決方法,文中通過示例代碼介紹的非常詳細(xì),對大家學(xué)習(xí)或者使用redis具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-07-07
  • 淺談Redis的異步機(jī)制

    淺談Redis的異步機(jī)制

    命令操作、系統(tǒng)配置、關(guān)鍵機(jī)制、硬件配置等會影響 Redis 的性能,還要提前準(zhǔn)備好應(yīng)對異常的方案,本文主要介紹了Redis的異步機(jī)制,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-05-05
  • 解決 Redis 數(shù)據(jù)傾斜、熱點(diǎn)等問題

    解決 Redis 數(shù)據(jù)傾斜、熱點(diǎn)等問題

    ?單臺機(jī)器的硬件配置有上限制約,一般我們會采用分布式架構(gòu)將多臺機(jī)器組成一個(gè)集群,這篇文章主要介紹了解決 Redis 數(shù)據(jù)傾斜、熱點(diǎn)等問題,需要的朋友可以參考下
    2022-12-12
  • 深入理解redis刪除策略和淘汰策略

    深入理解redis刪除策略和淘汰策略

    每隔一段時(shí)間就掃描一定數(shù)據(jù)的設(shè)置了過期時(shí)間的key,并清除其中已過期的keys,本文主要介紹了深入理解redis刪除策略和淘汰策略,感興趣的可以了解一下
    2024-08-08

最新評論