佳木斯湛栽影视文化发展公司

主頁 > 知識庫 > redis內(nèi)存空間效率問題的深入探究

redis內(nèi)存空間效率問題的深入探究

熱門標(biāo)簽:Linux服務(wù)器 AI電銷 百度競價排名 呼叫中心市場需求 鐵路電話系統(tǒng) 網(wǎng)站排名優(yōu)化 地方門戶網(wǎng)站 服務(wù)外包

前言

在使用redis時,我們會遇到一個問題,數(shù)據(jù)刪除后,數(shù)據(jù)量已經(jīng)不大了,但是使用top命令查看,還會發(fā)現(xiàn)redis占用了很對內(nèi)存。實(shí)際上,因?yàn)閿?shù)據(jù)刪除后,redis釋放內(nèi)存由內(nèi)存分配器管理,不會立刻返回給操作系統(tǒng)。所以,操作系統(tǒng)仍然記錄著給redis分配了大量的內(nèi)存

這往往會伴隨一個潛在的風(fēng)險點(diǎn):Redis 釋放的內(nèi)存空間可能并不是連續(xù)的,那么,這些不連續(xù)的內(nèi)存空間很有可能處于一種閑置的狀態(tài)。這就會導(dǎo)致一個問題:雖然有空閑空間,Redis 卻無法用來保存數(shù)據(jù),不僅會減少 Redis 能夠?qū)嶋H保存的數(shù)據(jù)量,還會降低 Redis 運(yùn)行機(jī)器的成本回報率。

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

通常情況下,內(nèi)存空間利用率低,往往是因?yàn)椴僮飨到y(tǒng)發(fā)生了比較嚴(yán)重的內(nèi)存碎片,那么什么是內(nèi)存碎片呢?可以將內(nèi)存看成是高鐵上的作為,連續(xù)的空間相當(dāng)于連座,內(nèi)存碎片可以看成一個個零散的作為,如果你是3個人出行,火車上沒有三個座位連著的,那么你就沒法買到合適的作為,可能需要換一輛車

內(nèi)存類似,如果需要申請一個N字節(jié)的連續(xù)空間,但是沒有這么大的連續(xù)空間,那么,這些剩余空間就是內(nèi)存碎片,redis內(nèi)存碎片是什么原因?qū)е碌哪?,了解了原因才有可能比較好的解決

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

一般來說內(nèi)存碎片形成的原因有兩個,內(nèi)因是操作系統(tǒng)的內(nèi)存分配機(jī)制,外因是redis的負(fù)載特征

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

內(nèi)存分配器的分配策略就決定了操作系統(tǒng)無法做到“按需分配”。這是因?yàn)?,?nèi)存分配器一般是按固定大小來分配內(nèi)存,而不是完全按照應(yīng)用程序申請的內(nèi)存空間大小給程序分配。

Redis 可以使用 libc、jemalloc、tcmalloc 多種內(nèi)存分配器來分配內(nèi)存,默認(rèn)使用 jemalloc。接下來,我就以 jemalloc 為例,來具體解釋一下。其他分配器也存在類似的問題。

jemalloc 的分配策略之一,是按照一系列固定的大小劃分內(nèi)存空間,例如 8 字節(jié)、16 字節(jié)、32 字節(jié)、48 字節(jié),…, 2KB、4KB、8KB 等。當(dāng)程序申請的內(nèi)存最接近某個固定值時,jemalloc 會給它分配相應(yīng)大小的空間。

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

redis通常作為公共緩存和鍵值數(shù)據(jù)庫對外提供服務(wù),所以對于不同大小的數(shù)據(jù),redis申請內(nèi)存空間大小不一,這是一個外因。

因?yàn)閮?nèi)存分配是按照固定大小分配,所以內(nèi)存空間一般都會比申請的空間大一些,所以本身就會有一些內(nèi)存碎片,降低內(nèi)存空間存儲效率。

第二個外因是,這些數(shù)據(jù)會被刪除和修改,會導(dǎo)致空間空間擴(kuò)充和釋放,具體來說,一方面,如果修改后的鍵值對變大或變小了,就需要占用額外的空間或者釋放不用的空間。另一方面,刪除的鍵值對就不再需要內(nèi)存空間了,此時,就會把空間釋放出來,形成空閑空間

一開始,應(yīng)用 A、B、C、D 分別保存了 3、1、2、4 字節(jié)的數(shù)據(jù),并占據(jù)了相應(yīng)的內(nèi)存空間。然后,應(yīng)用 D 刪除了 1 個字節(jié),這個 1 字節(jié)的內(nèi)存空間就空出來了。緊接著,應(yīng)用 A 修改了數(shù)據(jù),從 3 字節(jié)變成了 4 字節(jié)。為了保持 A 數(shù)據(jù)的空間連續(xù)性,操作系統(tǒng)就需要把 B 的數(shù)據(jù)拷貝到別的空間,比如拷貝到 D 剛剛釋放的空間中。此時,應(yīng)用 C 和 D 也分別刪除了 2 字節(jié)和 1 字節(jié)的數(shù)據(jù),整個內(nèi)存空間上就分別出現(xiàn)了 2 字節(jié)和 1 字節(jié)的空閑碎片。如果應(yīng)用 E 想要一個 3 字節(jié)的連續(xù)空間,顯然是不能得到滿足的。因?yàn)椋m然空間總量夠,但卻是碎片空間,并不是連續(xù)的。

好了,到這里,我們就知道了造成內(nèi)存碎片的內(nèi)外因素,其中,內(nèi)存分配器策略是內(nèi)因,而 Redis 的負(fù)載屬于外因,包括了大小不一的鍵值對和鍵值對修改刪除帶來的內(nèi)存空間變化。

如何判斷是否有內(nèi)存碎片

Redis 是內(nèi)存數(shù)據(jù)庫,內(nèi)存利用率的高低直接關(guān)系到 Redis 運(yùn)行效率的高低。為了讓用戶能監(jiān)控到實(shí)時的內(nèi)存使用情況,Redis 自身提供了 INFO 命令,可以用來查詢內(nèi)存使用的詳細(xì)信息,命令如下:

INFO memory
# Memory
used_memory:1073741736
used_memory_human:1024.00M
used_memory_rss:1997159792
used_memory_rss_human:1.86G
…
mem_fragmentation_ratio:1.86O memory

INFO memory
# Memory
used_memory:1073741736
used_memory_human:1024.00M
used_memory_rss:1997159792
used_memory_rss_human:1.86G
…
mem_fragmentation_ratio:1.86

這里有一個 mem_fragmentation_ratio 的指標(biāo),它表示的就是 Redis 當(dāng)前的內(nèi)存碎片率。那么,這個碎片率是怎么計算的呢?其實(shí),就是上面的命令中的兩個指標(biāo) used_memory_rss 和 used_memory 相除的結(jié)果。

mem_fragmentation_ratio = used_memory_rss/ used_memory

used_memory_rss 是操作系統(tǒng)實(shí)際分配給 Redis 的物理內(nèi)存空間,里面就包含了碎片;而 used_memory 是 Redis 為了保存數(shù)據(jù)實(shí)際申請使用的空間。

我簡單舉個例子。例如,Redis 申請使用了 100 字節(jié)(used_memory),操作系統(tǒng)實(shí)際分配了 128 字節(jié)(used_memory_rss),此時,mem_fragmentation_ratio 就是 1.28。

那么,知道了這個指標(biāo),我們該如何使用呢?在這兒,我提供一些經(jīng)驗(yàn)閾值:

  • mem_fragmentation_ratio大于1小于1.5。這種情況是合理的。這是因?yàn)?,剛才我介紹的那些因素是難以避免的。畢竟,內(nèi)因的內(nèi)存分配器是一定要使用的,分配策略都是通用的,不會輕易修改;而外因由 Redis 負(fù)載決定,也無法限制。所以,存在內(nèi)存碎片也是正常的。
  • mem_fragmentation_ratio大于1.5。 這表明內(nèi)存碎片率已經(jīng)超過了 50%。一般情況下,這個時候,我們就需要采取一些措施來降低內(nèi)存碎片率了。

如何清理內(nèi)存碎片

當(dāng) Redis 發(fā)生內(nèi)存碎片后,一個“簡單粗暴”的方法就是重啟redis實(shí)例,當(dāng)然這并不是一個優(yōu)雅的方法,重啟會帶來一些問題

  • 如果數(shù)據(jù)沒有持久化,那么數(shù)據(jù)會丟失
  • 如果數(shù)據(jù)持久化了,我們需要通過AOF或RDB進(jìn)行恢復(fù),恢復(fù)時長取決于AOF或RDB的大小,如果只有一個實(shí)例,在恢復(fù)階段無法提供服務(wù)。

幸運(yùn)的是,從 4.0-RC3 版本以后,Redis 自身提供了一種內(nèi)存碎片自動清理的方法,我們先來看這個方法的基本機(jī)制。還是通過一張圖來看下

在進(jìn)行碎片清理前,這段 10 字節(jié)的空間中分別有 1 個 2 字節(jié)和 1 個 1 字節(jié)的空閑空間,只是這兩個空間并不連續(xù)。操作系統(tǒng)在清理碎片時,會先把應(yīng)用 D 的數(shù)據(jù)拷貝到 2 字節(jié)的空閑空間中,并釋放 D 原先所占的空間。然后,再把 B 的數(shù)據(jù)拷貝到 D 原來的空間中。這樣一來,這段 10 字節(jié)空間的最后三個字節(jié)就是一塊連續(xù)空間了。到這里,碎片清理結(jié)束。

需要注意:碎片清理事由代價的,操作系統(tǒng)需要把多份數(shù)據(jù)拷貝到新位置,把原有空間釋放出來,這會帶來時間開銷。因?yàn)?Redis 是單線程,在數(shù)據(jù)拷貝時,Redis 只能等著,這就導(dǎo)致 Redis 無法及時處理請求,性能就會降低。而且,有的時候,數(shù)據(jù)拷貝還需要注意順序,就像剛剛說的清理內(nèi)存碎片的例子,操作系統(tǒng)需要先拷貝 D,并釋放 D 的空間后,才能拷貝 B。這種對順序性的要求,會進(jìn)一步增加 Redis 的等待時間,導(dǎo)致性能降低。

那么,有什么辦法可以盡量緩解這個問題嗎?這就要提到,Redis 專門為自動內(nèi)存碎片清理功機(jī)制設(shè)置的參數(shù)了。我們可以通過設(shè)置參數(shù),來控制碎片清理的開始和結(jié)束時機(jī),以及占用的 CPU 比例,從而減少碎片清理對 Redis 本身請求處理的性能影響。

首先,Redis 需要啟用自動內(nèi)存碎片清理,可以把 activedefrag 配置項(xiàng)設(shè)置為 yes,命令如下:

config set activedefrag yes

這個命令只是啟用了自動清理功能,但是,具體什么時候清理,會受到下面這兩個參數(shù)的控制。這兩個參數(shù)分別設(shè)置了觸發(fā)內(nèi)存清理的一個條件,如果同時滿足這兩個條件,就開始清理。在清理的過程中,只要有一個條件不滿足了,就停止自動清理。

  • active-defrag-ignore-bytes 100mb:表示內(nèi)存碎片數(shù)量達(dá)到100MB時,開始清理
  • active-defrag-threshold-lower 10:表示內(nèi)存碎片空間占操作系統(tǒng)給redis分配空間的10%時開始清理

為了盡可能減少碎片清理對 Redis 正常請求處理的影響,自動內(nèi)存碎片清理功能在執(zhí)行時,還會監(jiān)控清理操作占用的 CPU 時間,而且還設(shè)置了兩個參數(shù),分別用于控制清理操作占用的 CPU 時間比例的上、下限,既保證清理工作能正常進(jìn)行,又避免了降低 Redis 性能。這兩個參數(shù)具體如下:

  • active-defrag-cycle-min 25:表示自動清理過程cpu時間筆記不低于25%,保證清理能正常開展
  • active-defrag-cycle-max 75:表示自動清理過程所用 CPU 時間的比例不高于 75%,一旦超過,就停止清理,從而避免在清理時,大量的內(nèi)存拷貝阻塞 Redis,導(dǎo)致響應(yīng)延遲升高。

自動內(nèi)存碎片清理機(jī)制在控制碎片清理啟停的時機(jī)上,既考慮了碎片的空間占比、對 Redis 內(nèi)存使用效率的影響,還考慮了清理機(jī)制本身的 CPU 時間占比、對 Redis 性能的影響。而且,清理機(jī)制還提供了 4 個參數(shù),讓我們可以根據(jù)實(shí)際應(yīng)用中的數(shù)據(jù)量需求和性能要求靈活使用,建議你在實(shí)踐中好好地把這個機(jī)制用起來。

總結(jié)

到此這篇關(guān)于redis內(nèi)存空間效率問題的文章就介紹到這了,更多相關(guān)redis內(nèi)存空間效率內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

您可能感興趣的文章:
  • redis 限制內(nèi)存使用大小的實(shí)現(xiàn)
  • redis 使用lettuce 啟動內(nèi)存泄漏錯誤的解決方案
  • 淺談內(nèi)存耗盡后Redis會發(fā)生什么
  • 一次關(guān)于Redis內(nèi)存詭異增長的排查過程實(shí)戰(zhàn)記錄
  • 淺談redis內(nèi)存數(shù)據(jù)的持久化方式
  • 內(nèi)存型數(shù)據(jù)庫Redis持久化小結(jié)
  • 降低PHP Redis內(nèi)存占用
  • Redis教程(十四):內(nèi)存優(yōu)化介紹
  • 詳解Redis瘦身指南

標(biāo)簽:湘潭 湖南 衡水 銅川 仙桃 崇左 蘭州 黃山

巨人網(wǎng)絡(luò)通訊聲明:本文標(biāo)題《redis內(nèi)存空間效率問題的深入探究》,本文關(guān)鍵詞  ;如發(fā)現(xiàn)本文內(nèi)容存在版權(quán)問題,煩請?zhí)峁┫嚓P(guān)信息告之我們,我們將及時溝通與處理。本站內(nèi)容系統(tǒng)采集于網(wǎng)絡(luò),涉及言論、版權(quán)與本站無關(guān)。
  • 相關(guān)文章
  • 收縮
    • 微信客服
    • 微信二維碼
    • 電話咨詢

    • 400-1100-266
    西乌| 芜湖县| 双峰县| 中卫市| 盐津县| 临高县| 淳安县| 英吉沙县| 秦安县| 南川市| 肇源县| 彰化市| 东阿县| 岳阳县| 宣武区| 芦溪县| 兴安县| 麟游县| 洛南县| 新晃| 汽车| 铁岭市| 武平县| 武陟县| 峡江县| 清徐县| 鸡西市| 博客| 凤庆县| 湖北省| 长岛县| 永昌县| 诏安县| 中宁县| 公安县| 敦煌市| 万载县| 正宁县| 吉木萨尔县| 章丘市| 偃师市|