溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

Redis的怎么清理沒(méi)用的數(shù)據(jù)

發(fā)布時(shí)間:2021-08-16 21:31:55 來(lái)源:億速云 閱讀:288 作者:chen 欄目:大數(shù)據(jù)

本篇內(nèi)容主要講解“Redis的怎么清理沒(méi)用的數(shù)據(jù)”,感興趣的朋友不妨來(lái)看看。本文介紹的方法操作簡(jiǎn)單快捷,實(shí)用性強(qiáng)。下面就讓小編來(lái)帶大家學(xué)習(xí)“Redis的怎么清理沒(méi)用的數(shù)據(jù)”吧!

我們數(shù)據(jù)平臺(tái)中有使用Redis來(lái)給線上提供低延時(shí)(20毫秒以內(nèi))的高并發(fā)讀寫(xiě)請(qǐng)求,其中***的Redis使用了阿里云的Redis集群(256G),存儲(chǔ)的記錄超過(guò)10億,Key的有效期設(shè)置為15天,每天寫(xiě)入的記錄大概5000萬(wàn)左右,QPS大概在6萬(wàn)左右。由于過(guò)期Key的產(chǎn)生速度大于Redis自動(dòng)清理的速度,因此在Redis中會(huì)有大量過(guò)期Key未被及時(shí)清理。

為什么有過(guò)期的Key未被清理呢?這個(gè)得先熟悉一下Redis的刪除策略。

Redis常用的刪除策略有以下三種:

  • 被動(dòng)刪除(惰性刪除):當(dāng)讀/寫(xiě)一個(gè)已經(jīng)過(guò)期的Key時(shí),會(huì)觸發(fā)惰性刪除策略,直接刪除掉這個(gè)Key;

  • 主動(dòng)刪除(定期刪除):Redis會(huì)定期巡檢,來(lái)清理過(guò)期Key;

  • 當(dāng)內(nèi)存達(dá)到maxmemory配置時(shí)候,會(huì)觸發(fā)Key的刪除操作;

另外,還有一種基于觸發(fā)器的刪除策略,因?yàn)閷?duì)Redis壓力太大,一般沒(méi)人使用。

這里先介紹后兩種刪除策略(網(wǎng)上有很多說(shuō)明)。

主動(dòng)刪除(定期刪除)

在 Redis 中,常規(guī)操作由 redis.c/serverCron 實(shí)現(xiàn),它主要執(zhí)行以下操作:

  • 更新服務(wù)器的各類(lèi)統(tǒng)計(jì)信息,比如時(shí)間、內(nèi)存占用、數(shù)據(jù)庫(kù)占用情況等。

  • 清理數(shù)據(jù)庫(kù)中的過(guò)期鍵值對(duì)。

  • 對(duì)不合理的數(shù)據(jù)庫(kù)進(jìn)行大小調(diào)整。

  • 關(guān)閉和清理連接失效的客戶端。

  • 嘗試進(jìn)行 AOF 或 RDB 持久化操作。

  • 如果服務(wù)器是主節(jié)點(diǎn)的話,對(duì)附屬節(jié)點(diǎn)進(jìn)行定期同步。

  • 如果處于集群模式的話,對(duì)集群進(jìn)行定期同步和連接測(cè)試。

Redis 將 serverCron 作為時(shí)間事件來(lái)運(yùn)行,從而確保它每隔一段時(shí)間就會(huì)自動(dòng)運(yùn)行一次, 又因?yàn)?serverCron 需要在 Redis  服務(wù)器運(yùn)行期間一直定期運(yùn)行, 所以它是一個(gè)循環(huán)時(shí)間事件:serverCron 會(huì)一直定期執(zhí)行,直到服務(wù)器關(guān)閉為止。

在 Redis 2.6 版本中, 程序規(guī)定 serverCron 每秒運(yùn)行 10 次, 平均每 100 毫秒運(yùn)行一次。 從 Redis 2.8 開(kāi)始,  用戶可以通過(guò)修改 hz選項(xiàng)來(lái)調(diào)整 serverCron 的每秒執(zhí)行次數(shù), 具體信息請(qǐng)參考 redis.conf 文件中關(guān)于 hz 選項(xiàng)的說(shuō)明。

也叫定時(shí)刪除,這里的“定期”指的是Redis定期觸發(fā)的清理策略,由位于src/redis.c的activeExpireCycle(void)函數(shù)來(lái)完成。

serverCron是由redis的事件框架驅(qū)動(dòng)的定位任務(wù),這個(gè)定時(shí)任務(wù)中會(huì)調(diào)用activeExpireCycle函數(shù),針對(duì)每個(gè)db在限制的時(shí)間REDIS_EXPIRELOOKUPS_TIME_LIMIT內(nèi)遲可能多的刪除過(guò)期key,之所以要限制時(shí)間是為了防止過(guò)長(zhǎng)時(shí)間  的阻塞影響redis的正常運(yùn)行。這種主動(dòng)刪除策略彌補(bǔ)了被動(dòng)刪除策略在內(nèi)存上的不友好。

因此,Redis會(huì)周期性的隨機(jī)測(cè)試一批設(shè)置了過(guò)期時(shí)間的key并進(jìn)行處理。測(cè)試到的已過(guò)期的key將被刪除。典型的方式為,Redis每秒做10次如下的步驟:

  • 隨機(jī)測(cè)試100個(gè)設(shè)置了過(guò)期時(shí)間的key

  • 刪除所有發(fā)現(xiàn)的已過(guò)期的key

  • 若刪除的key超過(guò)25個(gè)則重復(fù)步驟1

這是一個(gè)基于概率的簡(jiǎn)單算法,基本的假設(shè)是抽出的樣本能夠代表整個(gè)key空間,redis持續(xù)清理過(guò)期的數(shù)據(jù)直至將要過(guò)期的key的百分比降到了25%以下。這也意味著在任何給定的時(shí)刻已經(jīng)過(guò)期但仍占據(jù)著內(nèi)存空間的key的量最多為每秒的寫(xiě)操作量除以4.

Redis-3.0.0中的默認(rèn)值是10,代表每秒鐘調(diào)用10次后臺(tái)任務(wù)。

除了主動(dòng)淘汰的頻率外,Redis對(duì)每次淘汰任務(wù)執(zhí)行的***時(shí)長(zhǎng)也有一個(gè)限定,這樣保證了每次主動(dòng)淘汰不會(huì)過(guò)多阻塞應(yīng)用請(qǐng)求,以下是這個(gè)限定計(jì)算公式:

#define ACTIVE_EXPIRE_CYCLE_SLOW_TIME_PERC 25 /* CPU max % for keys collection */  …  timelimit = 1000000*ACTIVE_EXPIRE_CYCLE_SLOW_TIME_PERC/server.hz/100;

hz調(diào)大將會(huì)提高Redis主動(dòng)淘汰的頻率,如果你的Redis存儲(chǔ)中包含很多冷數(shù)據(jù)占用內(nèi)存過(guò)大的話,可以考慮將這個(gè)值調(diào)大,但Redis作者建議這個(gè)值不要超過(guò)100。我們實(shí)際線上將這個(gè)值調(diào)大到100,觀察到CPU會(huì)增加2%左右,但對(duì)冷數(shù)據(jù)的內(nèi)存釋放速度確實(shí)有明顯的提高(通過(guò)觀察keyspace個(gè)數(shù)和used_memory大小)。

可以看出timelimit和server.hz是一個(gè)倒數(shù)的關(guān)系,也就是說(shuō)hz配置越大,timelimit就越小。換句話說(shuō)是每秒鐘期望的主動(dòng)淘汰頻率越高,則每次淘汰最長(zhǎng)占用時(shí)間就越短。這里每秒鐘的最長(zhǎng)淘汰占用時(shí)間是固定的250ms(1000000*ACTIVE_EXPIRE_CYCLE_SLOW_TIME_PERC/100),而淘汰頻率和每次淘汰的最長(zhǎng)時(shí)間是通過(guò)hz參數(shù)控制的。

從以上的分析看,當(dāng)redis中的過(guò)期key比率沒(méi)有超過(guò)25%之前,提高h(yuǎn)z可以明顯提高掃描key的最小個(gè)數(shù)。假設(shè)hz為10,則一秒內(nèi)最少掃描200個(gè)key(一秒調(diào)用10次*每次最少隨機(jī)取出20個(gè)key),如果hz改為100,則一秒內(nèi)最少掃描2000個(gè)key;另一方面,如果過(guò)期key比率超過(guò)25%,則掃描key的個(gè)數(shù)無(wú)上限,但是cpu時(shí)間每秒鐘最多占用250ms。

當(dāng)REDIS運(yùn)行在主從模式時(shí),只有主結(jié)點(diǎn)才會(huì)執(zhí)行上述這兩種過(guò)期刪除策略,然后把刪除操作”del key”同步到從結(jié)點(diǎn)。

maxmemory

當(dāng)前已用內(nèi)存超過(guò)maxmemory限定時(shí),觸發(fā)主動(dòng)清理策略,這些策略可以配置(參數(shù)maxmemory-policy),包括以下幾個(gè):

volatile-lru:從已設(shè)置過(guò)期時(shí)間的數(shù)據(jù)集(server.db[i].expires)中挑選最近最少使用的數(shù)據(jù)淘汰

volatile-ttl:從已設(shè)置過(guò)期時(shí)間的數(shù)據(jù)集(server.db[i].expires)中挑選將要過(guò)期的數(shù)據(jù)淘汰

volatile-random:從已設(shè)置過(guò)期時(shí)間的數(shù)據(jù)集(server.db[i].expires)中任意選擇數(shù)據(jù)淘汰

allkeys-lru:從數(shù)據(jù)集(server.db[i].dict)中挑選最近最少使用的數(shù)據(jù)淘汰

allkeys-random:從數(shù)據(jù)集(server.db[i].dict)中任意選擇數(shù)據(jù)淘汰

no-enviction(驅(qū)逐):禁止驅(qū)逐數(shù)據(jù)

當(dāng)mem_used內(nèi)存已經(jīng)超過(guò)maxmemory的設(shè)定,對(duì)于所有的讀寫(xiě)請(qǐng)求,都會(huì)觸發(fā)redis.c/freeMemoryIfNeeded(void)函數(shù)以清理超出的內(nèi)存。注意這個(gè)清理過(guò)程是阻塞的,直到清理出足夠的內(nèi)存空間。所以如果在達(dá)到maxmemory并且調(diào)用方還在不斷寫(xiě)入的情況下,可能會(huì)反復(fù)觸發(fā)主動(dòng)清理策略,導(dǎo)致請(qǐng)求會(huì)有一定的延遲。

清理時(shí)會(huì)根據(jù)用戶配置的maxmemory-policy來(lái)做適當(dāng)?shù)那謇?一般是LRU或TTL),這里的LRU或TTL策略并不是針對(duì)redis的所有key,而是以配置文件中的maxmemory-samples個(gè)key作為樣本池進(jìn)行抽樣清理。

總結(jié)與備忘

如果Redis中每天過(guò)期大量Key(比如幾千萬(wàn)),那么必須得考慮過(guò)期Key的清理:

增加Redis主動(dòng)清理的頻率(通過(guò)調(diào)大hz參數(shù));

手動(dòng)清理過(guò)期Key,最簡(jiǎn)單的方法是進(jìn)行scan操作,scan操作會(huì)觸發(fā)***種被動(dòng)刪除,scan操作時(shí)候別忘了加count;

dbsize命令返回的Key數(shù)量,包含了過(guò)期Key;

randomkey命令返回的Key,不包含過(guò)期Key;

scan命令返回的Key,包含過(guò)期Key;

info命令返回的# Keyspace:

db6:keys=1034937352,expires=994731489,avg_ttl=507838502

keys對(duì)應(yīng)的Key數(shù)量等同于dbsize;

expires指的是設(shè)置了過(guò)期時(shí)間的Key數(shù)量;

avg_ttl指設(shè)置了過(guò)期時(shí)間的Key的平均過(guò)期時(shí)間(單位:毫秒);

到此,相信大家對(duì)“Redis的怎么清理沒(méi)用的數(shù)據(jù)”有了更深的了解,不妨來(lái)實(shí)際操作一番吧!這里是億速云網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI