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

深入理解Redis 內(nèi)存管理

 更新時(shí)間:2025年02月06日 10:38:36   作者:濤粒子  
本文主要介紹了深入理解Redis 內(nèi)存管理,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧

Redis 給緩存數(shù)據(jù)設(shè)置過(guò)期時(shí)間有什么用?

一般情況下,我們?cè)O(shè)置保存的緩存數(shù)據(jù)的時(shí)候都會(huì)設(shè)置一個(gè)過(guò)期時(shí)間。為什么呢?

內(nèi)存是有限且珍貴的,如果不對(duì)緩存數(shù)據(jù)設(shè)置過(guò)期時(shí)間,那內(nèi)存占用就會(huì)一直增長(zhǎng),最終可能會(huì)導(dǎo)致 OOM 問(wèn)題。通過(guò)設(shè)置合理的過(guò)期時(shí)間,Redis 會(huì)自動(dòng)刪除暫時(shí)不需要的數(shù)據(jù),為新的緩存數(shù)據(jù)騰出空間。

Redis 自帶了給緩存數(shù)據(jù)設(shè)置過(guò)期時(shí)間的功能,比如:

127.0.0.1:6379> expire key 60 # 數(shù)據(jù)在 60s 后過(guò)期
(integer) 1
127.0.0.1:6379> setex key 60 value # 數(shù)據(jù)在 60s 后過(guò)期 (setex:[set] + [ex]pire)
OK
127.0.0.1:6379> ttl key # 查看數(shù)據(jù)還有多久過(guò)期
(integer) 56

注意 ??:Redis 中除了字符串類(lèi)型有自己獨(dú)有設(shè)置過(guò)期時(shí)間的命令 setex 外,其他方法都需要依靠 expire 命令來(lái)設(shè)置過(guò)期時(shí)間 。另外, persist 命令可以移除一個(gè)鍵的過(guò)期時(shí)間。

過(guò)期時(shí)間除了有助于緩解內(nèi)存的消耗,還有什么其他用么?

很多時(shí)候,我們的業(yè)務(wù)場(chǎng)景就是需要某個(gè)數(shù)據(jù)只在某一時(shí)間段內(nèi)存在,比如我們的短信驗(yàn)證碼可能只在 1 分鐘內(nèi)有效,用戶登錄的 Token 可能只在 1 天內(nèi)有效。

如果使用傳統(tǒng)的數(shù)據(jù)庫(kù)來(lái)處理的話,一般都是自己判斷過(guò)期,這樣更麻煩并且性能要差很多。

Redis 是如何判斷數(shù)據(jù)是否過(guò)期的呢?

Redis 通過(guò)一個(gè)叫做過(guò)期字典(可以看作是 hash 表)來(lái)保存數(shù)據(jù)過(guò)期的時(shí)間。過(guò)期字典的鍵指向 Redis 數(shù)據(jù)庫(kù)中的某個(gè) key(鍵),過(guò)期字典的值是一個(gè) long long 類(lèi)型的整數(shù),這個(gè)整數(shù)保存了 key 所指向的數(shù)據(jù)庫(kù)鍵的過(guò)期時(shí)間(毫秒精度的 UNIX 時(shí)間戳)。

過(guò)期字典是存儲(chǔ)在 redisDb 這個(gè)結(jié)構(gòu)里的:

typedef struct redisDb {
    ...

    dict *dict;     //數(shù)據(jù)庫(kù)鍵空間,保存著數(shù)據(jù)庫(kù)中所有鍵值對(duì)
    dict *expires   // 過(guò)期字典,保存著鍵的過(guò)期時(shí)間
    ...
} redisDb;

在查詢一個(gè) key 的時(shí)候,Redis 首先檢查該 key 是否存在于過(guò)期字典中(時(shí)間復(fù)雜度為 O(1)),如果不在就直接返回,在的話需要判斷一下這個(gè) key 是否過(guò)期,過(guò)期直接刪除 key 然后返回 null。

Redis 過(guò)期 key 刪除策略了解么?

如果假設(shè)你設(shè)置了一批 key 只能存活 1 分鐘,那么 1 分鐘后,Redis 是怎么對(duì)這批 key 進(jìn)行刪除的呢?

常用的過(guò)期數(shù)據(jù)的刪除策略就下面這幾種:

  • 惰性刪除:只會(huì)在取出/查詢 key 的時(shí)候才對(duì)數(shù)據(jù)進(jìn)行過(guò)期檢查。這種方式對(duì) CPU 最友好,但是可能會(huì)造成太多過(guò)期 key 沒(méi)有被刪除。
  • 定期刪除:周期性地隨機(jī)從設(shè)置了過(guò)期時(shí)間的 key 中抽查一批,然后逐個(gè)檢查這些 key 是否過(guò)期,過(guò)期就刪除 key。相比于惰性刪除,定期刪除對(duì)內(nèi)存更友好,對(duì) CPU 不太友好。
  • 延遲隊(duì)列:把設(shè)置過(guò)期時(shí)間的 key 放到一個(gè)延遲隊(duì)列里,到期之后就刪除 key。這種方式可以保證每個(gè)過(guò)期 key 都能被刪除,但維護(hù)延遲隊(duì)列太麻煩,隊(duì)列本身也要占用資源。
  • 定時(shí)刪除:每個(gè)設(shè)置了過(guò)期時(shí)間的 key 都會(huì)在設(shè)置的時(shí)間到達(dá)時(shí)立即被刪除。這種方法可以確保內(nèi)存中不會(huì)有過(guò)期的鍵,但是它對(duì) CPU 的壓力最大,因?yàn)樗枰獮槊總€(gè)鍵都設(shè)置一個(gè)定時(shí)器。

Redis 采用的那種刪除策略呢?

Redis 采用的是 定期刪除+惰性/懶漢式刪除 結(jié)合的策略,這也是大部分緩存框架的選擇。定期刪除對(duì)內(nèi)存更加友好,惰性刪除對(duì) CPU 更加友好。兩者各有千秋,結(jié)合起來(lái)使用既能兼顧 CPU 友好,又能兼顧內(nèi)存友好。

下面是我們?cè)敿?xì)介紹一下 Redis 中的定期刪除具體是如何做的。

Redis 的定期刪除過(guò)程是隨機(jī)的(

#define ACTIVE_EXPIRE_CYCLE_FAST_DURATION 1000 /* Microseconds. */
#define ACTIVE_EXPIRE_CYCLE_SLOW_TIME_PERC 25 /* Max % of CPU to use. */
#define ACTIVE_EXPIRE_CYCLE_ACCEPTABLE_STALE 10 /* % of stale keys after which
                                                   we do extra efforts. */

周期性地隨機(jī)從設(shè)置了過(guò)期時(shí)間的 key 中抽查一批),所以并不保證所有過(guò)期鍵都會(huì)被立即刪除。這也就解釋了為什么有的 key 過(guò)期了,并沒(méi)有被刪除。并且,Redis 底層會(huì)通過(guò)限制刪除操作執(zhí)行的時(shí)長(zhǎng)和頻率來(lái)減少刪除操作對(duì) CPU 時(shí)間的影響。

另外,定期刪除還會(huì)受到執(zhí)行時(shí)間和過(guò)期 key 的比例的影響:

  • 執(zhí)行時(shí)間已經(jīng)超過(guò)了閾值,那么就中斷這一次定期刪除循環(huán),以避免使用過(guò)多的 CPU 時(shí)間。
  • 如果這一批過(guò)期的 key 比例超過(guò)一個(gè)比例,就會(huì)重復(fù)執(zhí)行此刪除流程,以更積極地清理過(guò)期 key。相應(yīng)地,如果過(guò)期的 key 比例低于這個(gè)比例,就會(huì)中斷這一次定期刪除循環(huán),避免做過(guò)多的工作而獲得很少的內(nèi)存回收。

Redis 7.2 版本的執(zhí)行時(shí)間閾值是 25ms,過(guò)期 key 比例設(shè)定值是 10%

#define ACTIVE_EXPIRE_CYCLE_FAST_DURATION 1000 /* Microseconds. */
#define ACTIVE_EXPIRE_CYCLE_SLOW_TIME_PERC 25 /* Max % of CPU to use. */
#define ACTIVE_EXPIRE_CYCLE_ACCEPTABLE_STALE 10 /* % of stale keys after which
                                                   we do extra efforts. */

每次隨機(jī)抽查數(shù)量是多少?

expire.c中定義了每次隨機(jī)抽查的數(shù)量,Redis 7.2 版本為 20 ,也就是說(shuō)每次會(huì)隨機(jī)選擇 20 個(gè)設(shè)置了過(guò)期時(shí)間的 key 判斷是否過(guò)期。

#define ACTIVE_EXPIRE_CYCLE_KEYS_PER_LOOP 20 /* Keys for each DB loop. */

如何控制定期刪除的執(zhí)行頻率?

在 Redis 中,定期刪除的頻率是由 hz 參數(shù)控制的。hz 默認(rèn)為 10,代表每秒執(zhí)行 10 次,也就是每秒鐘進(jìn)行 10 次嘗試來(lái)查找并刪除過(guò)期的 key。

hz 的取值范圍為 1~500。增大 hz 參數(shù)的值會(huì)提升定期刪除的頻率。如果你想要更頻繁地執(zhí)行定期刪除任務(wù),可以適當(dāng)增加 hz 的值,但這會(huì)加 CPU 的使用率。根據(jù) Redis 官方建議,hz 的值不建議超過(guò) 100,對(duì)于大部分用戶使用默認(rèn)的 10 就足夠了。

下面是 hz 參數(shù)的官方注釋,我翻譯了其中的重要信息(Redis 7.2 版本)。

類(lèi)似的參數(shù)還有一個(gè) dynamic-hz,這個(gè)參數(shù)開(kāi)啟之后 Redis 就會(huì)在 hz 的基礎(chǔ)上動(dòng)態(tài)計(jì)算一個(gè)值。Redis 提供并默認(rèn)啟用了使用自適應(yīng) hz 值的能力,

這兩個(gè)參數(shù)都在 Redis 配置文件 redis.conf中:

# 默認(rèn)為 10
hz 10
# 默認(rèn)開(kāi)啟
dynamic-hz yes

多提一嘴,除了定期刪除過(guò)期 key 這個(gè)定期任務(wù)之外,還有一些其他定期任務(wù)例如關(guān)閉超時(shí)的客戶端連接、更新統(tǒng)計(jì)信息,這些定期任務(wù)的執(zhí)行頻率也是通過(guò) hz 參數(shù)決定。

為什么定期刪除不是把所有過(guò)期 key 都刪除呢?

這樣會(huì)對(duì)性能造成太大的影響。如果我們 key 數(shù)量非常龐大的話,挨個(gè)遍歷檢查是非常耗時(shí)的,會(huì)嚴(yán)重影響性能。Redis 設(shè)計(jì)這種策略的目的是為了平衡內(nèi)存和性能。

為什么 key 過(guò)期之后不立馬把它刪掉呢?這樣不是會(huì)浪費(fèi)很多內(nèi)存空間嗎?

因?yàn)椴惶棉k到,或者說(shuō)這種刪除方式的成本太高了。假如我們使用延遲隊(duì)列作為刪除策略,這樣存在下面這些問(wèn)題:

  • 隊(duì)列本身的開(kāi)銷(xiāo)可能很大:key 多的情況下,一個(gè)延遲隊(duì)列可能無(wú)法容納。
  • 維護(hù)延遲隊(duì)列太麻煩:修改 key 的過(guò)期時(shí)間就需要調(diào)整期在延遲隊(duì)列中的位置,并且,還需要引入并發(fā)控制。

大量 key 集中過(guò)期怎么辦?

當(dāng) Redis 中存在大量 key 在同一時(shí)間點(diǎn)集中過(guò)期時(shí),可能會(huì)導(dǎo)致以下問(wèn)題:

  • 請(qǐng)求延遲增加: Redis 在處理過(guò)期 key 時(shí)需要消耗 CPU 資源,如果過(guò)期 key 數(shù)量龐大,會(huì)導(dǎo)致 Redis 實(shí)例的 CPU 占用率升高,進(jìn)而影響其他請(qǐng)求的處理速度,造成延遲增加。
  • 內(nèi)存占用過(guò)高: 過(guò)期的 key 雖然已經(jīng)失效,但在 Redis 真正刪除它們之前,仍然會(huì)占用內(nèi)存空間。如果過(guò)期 key 沒(méi)有及時(shí)清理,可能會(huì)導(dǎo)致內(nèi)存占用過(guò)高,甚至引發(fā)內(nèi)存溢出。

為了避免這些問(wèn)題,可以采取以下方案:

  • 盡量避免 key 集中過(guò)期: 在設(shè)置鍵的過(guò)期時(shí)間時(shí)盡量隨機(jī)一點(diǎn)。
  • 開(kāi)啟 lazy free 機(jī)制: 修改 redis.conf 配置文件,將 lazyfree-lazy-expire 參數(shù)設(shè)置為 yes,即可開(kāi)啟 lazy free 機(jī)制。開(kāi)啟 lazy free 機(jī)制后,Redis 會(huì)在后臺(tái)異步刪除過(guò)期的 key,不會(huì)阻塞主線程的運(yùn)行,從而降低對(duì) Redis 性能的影響。

Redis 內(nèi)存淘汰策略了解么?

相關(guān)問(wèn)題:MySQL 里有 2000w 數(shù)據(jù),Redis 中只存 20w 的數(shù)據(jù),如何保證 Redis 中的數(shù)據(jù)都是熱點(diǎn)數(shù)據(jù)?

Redis 的內(nèi)存淘汰策略只有在運(yùn)行內(nèi)存達(dá)到了配置的最大內(nèi)存閾值時(shí)才會(huì)觸發(fā),這個(gè)閾值是通過(guò)redis.confmaxmemory參數(shù)來(lái)定義的。64 位操作系統(tǒng)下,maxmemory 默認(rèn)為 0 ,表示不限制內(nèi)存大小。32 位操作系統(tǒng)下,默認(rèn)的最大內(nèi)存值是 3GB。

你可以使用命令 config get maxmemory 來(lái)查看 maxmemory的值。

config get maxmemory
maxmemory
0

Redis 提供了 6 種內(nèi)存淘汰策略:

  • volatile-lru(least recently used):從已設(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(least recently used):從數(shù)據(jù)集(server.db[i].dict)中移除最近最少使用的數(shù)據(jù)淘汰。
  • allkeys-random:從數(shù)據(jù)集(server.db[i].dict)中任意選擇數(shù)據(jù)淘汰。
  • no-eviction(默認(rèn)內(nèi)存淘汰策略):禁止驅(qū)逐數(shù)據(jù),當(dāng)內(nèi)存不足以容納新寫(xiě)入數(shù)據(jù)時(shí),新寫(xiě)入操作會(huì)報(bào)錯(cuò)。

4.0 版本后增加以下兩種:

  • volatile-lfu(least frequently used):從已設(shè)置過(guò)期時(shí)間的數(shù)據(jù)集(server.db[i].expires)中挑選最不經(jīng)常使用的數(shù)據(jù)淘汰。
  • allkeys-lfu(least frequently used):從數(shù)據(jù)集(server.db[i].dict)中移除最不經(jīng)常使用的數(shù)據(jù)淘汰。

allkeys-xxx 表示從所有的鍵值中淘汰數(shù)據(jù),而 volatile-xxx 表示從設(shè)置了過(guò)期時(shí)間的鍵值中淘汰數(shù)據(jù)。

config.c中定義了內(nèi)存淘汰策略的枚舉數(shù)組:

configEnum maxmemory_policy_enum[] = {
    {"volatile-lru", MAXMEMORY_VOLATILE_LRU},
    {"volatile-lfu", MAXMEMORY_VOLATILE_LFU},
    {"volatile-random",MAXMEMORY_VOLATILE_RANDOM},
    {"volatile-ttl",MAXMEMORY_VOLATILE_TTL},
    {"allkeys-lru",MAXMEMORY_ALLKEYS_LRU},
    {"allkeys-lfu",MAXMEMORY_ALLKEYS_LFU},
    {"allkeys-random",MAXMEMORY_ALLKEYS_RANDOM},
    {"noeviction",MAXMEMORY_NO_EVICTION},
    {NULL, 0}
};

你可以使用 config get maxmemory-policy 命令來(lái)查看當(dāng)前 Redis 的內(nèi)存淘汰策略。

> config get maxmemory-policy
maxmemory-policy
noeviction

可以通過(guò)config set maxmemory-policy 內(nèi)存淘汰策略 命令修改內(nèi)存淘汰策略,立即生效,但這種方式重啟 Redis 之后就失效了。修改 redis.conf 中的 maxmemory-policy 參數(shù)不會(huì)因?yàn)橹貑⒍В贿^(guò),需要重啟之后修改才能生效。

maxmemory-policy noeviction

到此這篇關(guān)于深入理解Redis 內(nèi)存管理的文章就介紹到這了,更多相關(guān)Redis 內(nèi)存管理內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家! 

相關(guān)文章

  • Redis實(shí)現(xiàn)全局唯一id的使用示例

    Redis實(shí)現(xiàn)全局唯一id的使用示例

    全局ID生成器,是一種在分布式系統(tǒng)下用來(lái)生成全局唯一ID的工具,本文主要介紹了Redis實(shí)現(xiàn)全局唯一id的使用示例,具有一定的參考價(jià)值,感興趣的可以了解一下
    2023-09-09
  • Redis簡(jiǎn)介

    Redis簡(jiǎn)介

    Redis是一個(gè)開(kāi)源,高級(jí)的鍵值存儲(chǔ)和一個(gè)適用的解決方案,用于構(gòu)建高性能,可擴(kuò)展的Web應(yīng)用程序。關(guān)于redis的相關(guān)知識(shí)大家可以通過(guò)本教程學(xué)習(xí)
    2017-05-05
  • Redis Cluster集群動(dòng)態(tài)擴(kuò)容的實(shí)現(xiàn)

    Redis Cluster集群動(dòng)態(tài)擴(kuò)容的實(shí)現(xiàn)

    本文主要介紹了Redis Cluster集群動(dòng)態(tài)擴(kuò)容的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-07-07
  • Redis 對(duì)比 Memcached 并在 CentOS 下進(jìn)行安裝配置詳解

    Redis 對(duì)比 Memcached 并在 CentOS 下進(jìn)行安裝配置詳解

    Redis 是一個(gè)開(kāi)源、支持網(wǎng)絡(luò)、基于內(nèi)存、鍵值對(duì)的 Key-Value 數(shù)據(jù)庫(kù),本篇文章主要介紹了Redis 對(duì)比 Memcached 并在 CentOS 下進(jìn)行安裝配置詳解,有興趣的可以了解一下。
    2016-11-11
  • Redis持久化深入詳解

    Redis持久化深入詳解

    這篇文章主要介紹了Redis持久化深入詳解,講解的還是比較詳細(xì)的,有感興趣的同學(xué)可以學(xué)習(xí)下
    2021-03-03
  • Redis中過(guò)期鍵刪除的三種方法

    Redis中過(guò)期鍵刪除的三種方法

    Redis中可以設(shè)置鍵的過(guò)期時(shí)間,并且通過(guò)取出過(guò)期字典(expires dict)中鍵的過(guò)期時(shí)間和當(dāng)前時(shí)間比較來(lái)判斷是否過(guò)期,那么一個(gè)過(guò)期的鍵是怎么被刪除的呢?本文給大家總結(jié)了三種方法,選了其中兩種給大家詳細(xì)的介紹一下,需要的朋友可以參考下
    2024-05-05
  • Redis:Redisson分布式鎖的使用方式(推薦使用)

    Redis:Redisson分布式鎖的使用方式(推薦使用)

    這篇文章主要介紹了Redis:Redisson分布式鎖的使用方式(推薦使用),具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-04-04
  • Redis Cluster 字段模糊匹配及刪除

    Redis Cluster 字段模糊匹配及刪除

    在數(shù)據(jù)庫(kù)內(nèi)我們可以通過(guò)like關(guān)鍵字、%、*或者REGEX關(guān)鍵字進(jìn)行模糊匹配。而在Redis內(nèi)我們?nèi)绾芜M(jìn)行模糊匹配呢?本文就來(lái)介紹一下
    2021-05-05
  • Redis集群(cluster模式)搭建過(guò)程

    Redis集群(cluster模式)搭建過(guò)程

    文章介紹了Redis集群的概念、使用原因和搭建方法,Redis集群通過(guò)分區(qū)實(shí)現(xiàn)數(shù)據(jù)水平擴(kuò)容,提供了一定的可用性,文章詳細(xì)闡述了集群的連接方式,解釋了如何分配節(jié)點(diǎn),并提供了詳細(xì)的集群搭建步驟,包括創(chuàng)建節(jié)點(diǎn)、清空數(shù)據(jù)、修改配置、啟動(dòng)節(jié)點(diǎn)、配置集群等
    2024-10-10
  • Redis實(shí)現(xiàn)每日簽到功能(大數(shù)據(jù)量)

    Redis實(shí)現(xiàn)每日簽到功能(大數(shù)據(jù)量)

    在面對(duì)百萬(wàn)級(jí)用戶簽到情況下,傳統(tǒng)數(shù)據(jù)庫(kù)存儲(chǔ)和判斷會(huì)遇到瓶頸,使用Redis的二進(jìn)制數(shù)據(jù)類(lèi)型可實(shí)現(xiàn)高效的簽到功能,示例代碼展示了如何調(diào)用這些功能,包括當(dāng)天簽到、補(bǔ)簽以及查詢簽到記錄,PHP結(jié)合Redis二進(jìn)制數(shù)據(jù)類(lèi)型可有效處理大數(shù)據(jù)量下的簽到問(wèn)題
    2024-10-10

最新評(píng)論