久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

為什么Redis的數(shù)據(jù)被刪除,內(nèi)存占用還這么大,?

 LGPL 2022-12-03 發(fā)布于北京

?
操作系統(tǒng)分配給 Redis 的內(nèi)存有 6GB,,通過指標 used_memory_human 發(fā)現(xiàn)存儲數(shù)據(jù)只使用了 4GB,為何會這樣,?為何無法保存數(shù)據(jù),?

通過 CONFIG SET maxmemory 100mb或者在 redis.conf 配置文件設(shè)置 maxmemory 100mb Redis 內(nèi)存占用限制。當達到內(nèi)存最大值,,會觸發(fā)內(nèi)存淘汰策略刪除數(shù)據(jù),。

除此之外,當 key 達到過期時間,,Redis 會有以下兩種刪除過期數(shù)據(jù)的策略:

  • 后臺定時任務(wù)選取部分數(shù)據(jù)刪除,;
  • 惰性刪除。

?
假設(shè) Redis 實例保存了 5GB 的數(shù)據(jù),,現(xiàn)在刪除了 2GB 數(shù)據(jù),,Redis 進程占用的內(nèi)存一定會降低么?(也叫做 RSS,,進程消耗內(nèi)存頁數(shù)),。

答案是:可能依然占用了大約 5GB 的內(nèi)存,即使 Redis 的數(shù)據(jù)只占用了 3GB 左右,。

大家一定要設(shè)置maxmemory,,否則 Redis 會繼續(xù)為新寫入的數(shù)據(jù)分配內(nèi)存,無法分配就會導(dǎo)致應(yīng)用程序報錯,當然不會導(dǎo)致宕機,。

釋放的內(nèi)存去哪了

?
明明刪除了數(shù)據(jù),,使用 top 命令查看,為何還是占用了那么多內(nèi)存,?

內(nèi)存都去哪了,?使用 info memory 命令獲取 Redis 內(nèi)存相關(guān)指標,我列舉了幾個重要的數(shù)據(jù):

127.0.0.1:6379> info memory
# Memory
used_memory:1132832  // Redis 存儲數(shù)據(jù)占用的內(nèi)存量
used_memory_human:1.08M  // 人類可讀形式返回內(nèi)存總量
used_memory_rss:2977792  // 操作系統(tǒng)角度,,進程占用的物理總內(nèi)存
used_memory_rss_human:2.84M // used_memory_rss 可讀性模式展示
used_memory_peak:1183808 // 內(nèi)存使用的最大值,,表示 used_memory 的峰值

used_memory_peak_human:1.13M  // 以可讀的格式返回 used_memory_peak的值
used_memory_lua:37888   // Lua 引擎所消耗的內(nèi)存大小。
used_memory_lua_human:37.00K
maxmemory:2147483648    // 能使用的最大內(nèi)存值,,字節(jié)為單位,。
maxmemory_human:2.00G  // 可讀形式
maxmemory_policy:noeviction // 內(nèi)存淘汰策略

// used_memory_rss / used_memory 的比值,代表內(nèi)存碎片率
mem_fragmentation_ratio:2.79

Redis 進程內(nèi)存消耗主要由以下部分組成:

  • Redis 自身啟動所占用的內(nèi)存,;
  • 存儲對象數(shù)據(jù)內(nèi)存,;
  • 緩沖區(qū)內(nèi)存:主要由 client-output-buffer-limit 客戶端輸出緩沖區(qū)、復(fù)制積壓緩沖區(qū),、AOF 緩沖區(qū),。
  • 內(nèi)存碎片。

Redis 自身空進程占用的內(nèi)存很小可以忽略不計,,對象內(nèi)存是占比最大的一塊,,里面存儲著所有的數(shù)據(jù)。

緩沖區(qū)內(nèi)存在大流量場景容易失控,,造成 Redis 內(nèi)存不穩(wěn)定,,需要重點關(guān)注。

內(nèi)存碎片過大會導(dǎo)致明明有空間可用,,但是卻無法存儲數(shù)據(jù),。

碎片 = used_memory_rss 實際使用的物理內(nèi)存(RSS 值)除以 used_memory 實際存儲數(shù)據(jù)內(nèi)存。

什么是內(nèi)存碎片

內(nèi)存碎片會造成明明有內(nèi)存空間空閑,,可是卻無法存儲數(shù)據(jù),。舉個例子,,你跟漂亮小姐姐去電影院看電影,,肯定想連在一塊。

假設(shè)現(xiàn)在有 8 個座位,,已經(jīng)賣出了 4 張票,,還有 4 張可以買??墒呛们刹磺?,買票的人很奇葩,分別間隔一個座位買票。

即使還有 4 個座位空閑,,可是你卻買不到兩個座位連在一塊的票,,厚禮蟹!

內(nèi)存碎片形成原因

?

內(nèi)存碎片是什么原因?qū)е履兀?/p>

主要有兩個原因:

  • 內(nèi)存分配器的分配策略,。
  • 鍵值對的大小不一樣和刪改操作:Redis 頻繁做更新操作,、大量過期數(shù)據(jù)刪除,釋放的空間(不夠連續(xù))無法得到復(fù)用,,導(dǎo)致碎片率上升,。

接下來我分別探討實際發(fā)生的原因……

內(nèi)存分配器的分配策略

Redis 默認的內(nèi)存分配器采用 jemalloc,可選的分配器還有:glibc,、tcmalloc,。

內(nèi)存分配器并不能做到按需分配,而是采用固定范圍的內(nèi)存塊進行分配,。

例如 8 字節(jié),、16 字節(jié)…..,2 KB,,4KB,,當申請內(nèi)存最近接某個固定值的時候,jemalloc 會給它分配最接近固定值大小的空間,。

這樣就會出現(xiàn)內(nèi)存碎片,,比如程序只需要 1.5 KB,內(nèi)存分配器會分配 2KB 空間,,那么這 0.5KB 就是碎片,。

這么做的目的是減少內(nèi)存分配次數(shù),比如申請 22 字節(jié)的空間保存數(shù)據(jù),,jemalloc 就會分配 32 字節(jié),,如果后邊還要寫入 10 字節(jié),就不需要再向操作系統(tǒng)申請空間了,,可以使用之前申請的 32 字節(jié),。

刪除 key 的時候,Redis 并不會立馬把內(nèi)存歸還給操作系統(tǒng),,出現(xiàn)這個情況是因為底層內(nèi)存分配器管理導(dǎo)致,,比如大多數(shù)已經(jīng)刪除的 key 依然與其他有效的 key 分配在同一個內(nèi)存頁中。

另外,,分配器為了復(fù)用空閑的內(nèi)存塊,,原有 5GB 的數(shù)據(jù)中刪除了 2 GB 后,當再次添加數(shù)據(jù)到實例中,,Redis 的 RSS 會保持穩(wěn)定,,不會增長太多。

因為內(nèi)存分配器基本上復(fù)用了之前刪除釋放出來的 2GB 內(nèi)存。

鍵值對大小不一樣和刪改操作

由于內(nèi)存分配器是按照固定大小分配內(nèi)存,,所以通常分配的內(nèi)存空間比實際數(shù)據(jù)占用的大小多一些,,會造成碎片,降低內(nèi)存的存儲效率,。

另外,,鍵值對的頻繁修改和刪除,導(dǎo)致內(nèi)存空間的擴容和釋放,,比如原本占用 32 字節(jié)的字符串,,現(xiàn)在修改為占用 20 字節(jié)的字符串,那么釋放出的 12 字節(jié)就是空閑空間,。

如果下一個數(shù)據(jù)存儲請求需要申請 13 字節(jié)的字符串,,那么剛剛釋放的 12 字節(jié)空間無法使用,導(dǎo)致碎片,。

碎片最大的問題:空間總量足夠大,,但是這些內(nèi)存不是連續(xù)的,可能大致無法存儲數(shù)據(jù),。

內(nèi)存碎片解決之道

?
那該如何解決呢,?

首先要確定是否發(fā)生了內(nèi)存碎片,重點關(guān)注前面 INFO memory 命令提示的 mem_fragmentation_ratio 指標,,表示內(nèi)存碎片率:

mem_fragmentation_ratio = used_memory_rss/ used_memory

如果 1 < 碎片率 < 1.5,,可以認為是合理的,而大于 1.5 說明碎片已經(jīng)超過 50%,,我們需要采取一些手段解決碎片率過大的問題,。

重啟大法

最簡單粗暴的方式就是重啟,如果沒有開啟持久化,,數(shù)據(jù)會丟失,。

開啟持久化的話,需要使用 RDB 或者 AOF 恢復(fù)數(shù)據(jù),,如果只有一個實例,,數(shù)據(jù)大的話會導(dǎo)致恢復(fù)階段長時間無法提供服務(wù),高可用大打折扣,。

自動清理內(nèi)存碎片

既然你都叫我靚仔了,,就傾囊相助告訴你終極殺招:Redis 4.0 版本后,自身提供了一種內(nèi)存碎片清理機制,。

?
怎么清理呢,?

很簡單,,還是上面的例子,,想要買兩張連在一塊的電影票。與與別人溝通調(diào)換下位置,就實現(xiàn)了,。

對于 Redis 來說,,當一塊連續(xù)的內(nèi)存空間被劃分為好幾塊不連續(xù)的空間的時候,操作系統(tǒng)先把數(shù)據(jù)以依次挪動拼接在一塊,,并釋放原來數(shù)據(jù)占據(jù)的空間,,形成一塊連續(xù)空閑內(nèi)存空間。,。

如下圖所示:

自動清理內(nèi)存碎片的代價

自動清理雖好,,可不要肆意妄為,操作系統(tǒng)把數(shù)據(jù)移動到新位置,,再把原有空間釋放是需要消耗資源的,。

Redis 操作數(shù)據(jù)的指令是單線程,所以在數(shù)據(jù)復(fù)制移動的時候,,只能等待清理碎片完成才能處理請求,,造成性能損耗。

?
如何避免清理碎片對性能的影響又能實現(xiàn)自動清理呢,?

好問題,,通過以下兩個參數(shù)來控制內(nèi)存碎片清理和結(jié)束時機,避免占用 CPU 過多,,減少清理碎片對 Redis 處理請求的性能影響,。

開啟自動內(nèi)存碎片清理

CONFIG SET activedefrag yes

這只是開啟自動清理,何時清理要同時滿足以下兩個條件才會觸發(fā)清理操作,。

清理的條件

active-defrag-ignore-bytes 200mb:內(nèi)存碎片占用的內(nèi)存達到 200MB,,開始清理;

active-defrag-threshold-lower 20:內(nèi)存碎片的空間占比超過系統(tǒng)分配給 Redis 空間的 20% ,,開始清理,。

避免對性能造成影響

清理時間有了,還需要控制清理對性能的影響,。由一項兩個設(shè)置先分配清理碎片占用的 CPU 資源,,保證既能正常清理碎片,又能避免對 Redis 處理請求的性能影響,。

active-defrag-cycle-min 20:自動清理過程中,,占用 CPU 時間的比例不低于 20%,從而保證能正常展開清理任務(wù),。

active-defrag-cycle-max 50:自動清理過程占用的 CPU 時間比例不能高于 50%,,超過的話就立刻停止清理,避免對 Redis 的阻塞,,造成高延遲,。

總結(jié)

如果你發(fā)現(xiàn)明明 Redis 存儲數(shù)據(jù)的內(nèi)存占用遠小于操作系統(tǒng)分配給 Redis 的內(nèi)存,,而又無法保存數(shù)據(jù),那可能出現(xiàn)大量內(nèi)存碎片了,。

通過 info memory 命令,,看下內(nèi)存碎片mem_fragmentation_ratio 指標是否正常。

那么我們就開啟自動清理并合理設(shè)置清理時機和 CPU 資源占用,,該機制涉及到內(nèi)存拷貝,,會對 Redis 性能造成潛在風(fēng)險。

如果遇到 Redis 性能變慢,,排查下是否由于清理碎片導(dǎo)致,,如果是,那就調(diào)小 active-defrag-cycle-max 的值,。

    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多