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

Redis內(nèi)存碎片原理深入分析

 更新時(shí)間:2023年02月01日 11:36:49   作者:JAVA旭陽(yáng)  
這篇文章主要為大家介紹了Redis內(nèi)存碎片原理深入分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

前言

我們先來(lái)看一個(gè)問(wèn)題, 假設(shè)Redis實(shí)例保存了5GB的數(shù)據(jù),現(xiàn)在刪除了2GB的數(shù)據(jù),那么Redis進(jìn)程占用的內(nèi)存會(huì)不會(huì)減少呢?

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

如果maxmemory不設(shè)置該參數(shù),Redis不會(huì)觸發(fā)內(nèi)存淘汰策略刪除數(shù)據(jù)。

Redis會(huì)繼續(xù)為新寫(xiě)入的數(shù)據(jù)分配內(nèi)存。分配失敗會(huì)導(dǎo)致應(yīng)用程序報(bào)錯(cuò),當(dāng)然不會(huì)導(dǎo)致宕機(jī)。

注:設(shè)置maxmemory參數(shù),執(zhí)行命令CONFIG SET maxmemory 100mb,或在redis.conf 配置文件中設(shè)置maxmemory 100mb。

使用top命令查看數(shù)據(jù)是否已經(jīng)刪除,為什么它仍然占用這么多內(nèi)存?

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

當(dāng)我們使用top命令查看系統(tǒng)使用情況時(shí),會(huì)發(fā)現(xiàn)內(nèi)存依然很高,Redis并沒(méi)有真正釋放內(nèi)存。那么內(nèi)存都去哪兒了?這時(shí)候我們就需要使用info memory命令獲取Redis內(nèi)存相關(guān)的指標(biāo)。

127.0.0.1:6379> info memory
# Memory
used_memory:1132832           // Redis Amount of memory used to store data
used_memory_human:1.08M       // Returns the total amount of memory in human readable form
used_memory_rss:2977792       // From the perspective of the operating system, the total physical memory occupied by the process
used_memory_rss_human:2.84M   // used_memory_rss Readability mode display
used_memory_peak:1183808      // The maximum value of memory used, representing the peak value of used_memory
used_memory_peak_human:1.13M  // Returns the value of used_memory_peak in a human readable format
used_memory_lua:37888         // Lua The amount of memory consumed by the engine。
used_memory_lua_human:37.00K
maxmemory:2147483648          // The maximum memory value that can be used, in bytes.
maxmemory_human:2.00G         // readable form
maxmemory_policy:noeviction   // Memory Retirement Policy
mem_fragmentation_ratio:2.79  // The ratio of used_memory_rss & used_memory represents the memory fragmentation rate

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

  • 內(nèi)存被Redis自己?jiǎn)?dòng)占用
  • 存儲(chǔ)對(duì)象數(shù)據(jù)內(nèi)存
  • 緩沖區(qū)內(nèi)存:主要由client-output-buffer-limit客戶(hù)端輸出緩沖區(qū)、copy backlog緩沖區(qū)、AOF緩沖區(qū)組成
  • 內(nèi)存碎片

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

需要注意, 如果緩沖區(qū)有大流量的場(chǎng)景很容易失控,導(dǎo)致Redis內(nèi)存不穩(wěn)定。

內(nèi)存碎片過(guò)多導(dǎo)致有可用空間不足,無(wú)法存儲(chǔ)數(shù)據(jù)。內(nèi)存碎片Fragmentation = used_memory_rss 實(shí)際使用的物理內(nèi)存(RSS 值)除以 used_memory 實(shí)際存儲(chǔ)的數(shù)據(jù)內(nèi)存。

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

內(nèi)存碎片會(huì)導(dǎo)致內(nèi)存空間空閑,但無(wú)法存儲(chǔ)數(shù)據(jù)。比如你和女朋友去電影院看電影,你們肯定是要在一起的。

假設(shè)現(xiàn)在有 8 個(gè)座位,已售出 4 張票,還有 4 張可供購(gòu)買(mǎi)。不過(guò)巧合的是,買(mǎi)票的人很奇怪,都是隔一個(gè)座位買(mǎi)票。即使還有4個(gè)座位,也不能買(mǎi)順序連接兩個(gè)座位的票。

什么導(dǎo)致內(nèi)存碎片?

主要有兩個(gè)原因:

  • 內(nèi)存分配器的分配策略
  • 鍵值對(duì)的大小不同,刪除操作

下面我們就實(shí)際發(fā)生的原因進(jìn)行探討。

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

Redis 默認(rèn)的內(nèi)存分配器使用jemalloc,可選的分配器有:glibctcmalloc。

內(nèi)存分配器不能按需分配,而是使用固定范圍的內(nèi)存塊進(jìn)行分配。

比如8字節(jié)、16字節(jié)……、2KB、4KB,當(dāng)申請(qǐng)內(nèi)存最接近固定值時(shí),jemalloc會(huì)分配最接近固定值的空間。這樣就會(huì)出現(xiàn)內(nèi)存碎片。

比如程序只需要1.5KB,而內(nèi)存分配器會(huì)分配2KB的空間,那么這0.5KB就是碎片。這樣做的目的是減少內(nèi)存分配的次數(shù)。比如你申請(qǐng)22個(gè)字節(jié)的空間來(lái)存放數(shù)據(jù),jemalloc就會(huì)分配32個(gè)字節(jié)。如果后面需要寫(xiě)入10個(gè)字節(jié),則不需要向操作系統(tǒng)申請(qǐng)空間。您可以使用之前請(qǐng)求的 32 個(gè)字節(jié)。

當(dāng)一個(gè)鍵被刪除時(shí),Redis 不會(huì)立即將內(nèi)存歸還給操作系統(tǒng)。發(fā)生這種情況是因?yàn)榈讓觾?nèi)存分配器的管理。例如,大多數(shù)已刪除的鍵仍與其他有效鍵分配在同一內(nèi)存頁(yè)中。

此外,為了重用空閑內(nèi)存塊,分配器刪除了原始 5 GB 數(shù)據(jù)中的 2 GB。再次向?qū)嵗砑訑?shù)據(jù)時(shí),Redis的RSS會(huì)保持穩(wěn)定,不會(huì)增加太多。因?yàn)閮?nèi)存分配器基本上重新使用了之前刪除釋放的2GB內(nèi)存。

2.鍵值對(duì)大小不同,刪除操作

由于內(nèi)存分配器是按照固定的大小分配內(nèi)存,因此分配的內(nèi)存空間通常會(huì)大于實(shí)際數(shù)據(jù)占用的大小,這會(huì)造成碎片,降低內(nèi)存的存儲(chǔ)效率。

另外,鍵值對(duì)的頻繁修改和刪除導(dǎo)致內(nèi)存空間的擴(kuò)大和釋放。例如,如果原來(lái)占用32個(gè)字節(jié)的字符串現(xiàn)在修改為占用20個(gè)字節(jié)的字符串,那么釋放的12個(gè)字節(jié)就是空閑空間。

如果下一次數(shù)據(jù)存儲(chǔ)請(qǐng)求需要申請(qǐng)一個(gè)13字節(jié)的字符串,剛剛釋放的12字節(jié)空間就不能使用,造成碎片。

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

mem_fragmentation_ratio = used_memory_rss/ used_memory

如何解決?

首先要判斷是否發(fā)生了內(nèi)存碎片,重點(diǎn)看info memory命令執(zhí)行后的mem_fragmentation_ratio指標(biāo),表示內(nèi)存碎片率。

如果1 < mem_fragmentation_ratio < 1.5,可以認(rèn)為是合理的,如果大于1.5,說(shuō)明碎片已經(jīng)超過(guò)了50%,我們需要采取一些措施來(lái)解決碎片過(guò)多的問(wèn)題。

1. 重啟

最簡(jiǎn)單的方法是重新啟動(dòng)。如果未啟用持久性,數(shù)據(jù)將丟失。

如果開(kāi)啟持久化,需要使用RDB或者AOF來(lái)恢復(fù)數(shù)據(jù)。如果只有一個(gè)實(shí)例,數(shù)據(jù)量大會(huì)導(dǎo)致恢復(fù)階段長(zhǎng)時(shí)間無(wú)法提供服務(wù),高可用性會(huì)大大降低。

2.自動(dòng)清理內(nèi)存碎片

Redis在4.0版本之后,提供了內(nèi)存碎片清理機(jī)制。

對(duì)于Redis來(lái)說(shuō),當(dāng)連續(xù)的內(nèi)存空間被分割成若干個(gè)不連續(xù)的空間時(shí),操作系統(tǒng)首先將數(shù)據(jù)移動(dòng)拼接在一起,釋放掉原來(lái)數(shù)據(jù)占用的空間,形成一個(gè)連續(xù)的空閑內(nèi)存空間。

圖片由作者提供

自動(dòng)清理雖然好,但也不要亂來(lái)。操作系統(tǒng)需要消耗資源將數(shù)據(jù)移動(dòng)到新的位置,然后釋放原來(lái)的空間。

Redis 操作數(shù)據(jù)的指令是單線(xiàn)程的,所以在數(shù)據(jù)復(fù)制和移動(dòng)時(shí),只有清理碎片后才能處理請(qǐng)求,會(huì)造成性能損失。

那么問(wèn)題來(lái)了,如何減少對(duì)性能的影響來(lái)實(shí)現(xiàn)自動(dòng)清理碎片?

問(wèn)得好,用下面兩個(gè)參數(shù)來(lái)控制內(nèi)存碎片清理和結(jié)束的時(shí)機(jī),避免占用過(guò)多CPU,減少清理碎片對(duì)Redis處理請(qǐng)求的性能影響。

啟用自動(dòng)內(nèi)存碎片整理:

CONFIG SET activedefrag yes

這只是為了啟用自動(dòng)清潔。當(dāng)清理需要同時(shí)滿(mǎn)足以下兩個(gè)條件時(shí),就會(huì)出發(fā)清理操作。

  • 清理?xiàng)l件

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

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

  • 避免性能影響

清理時(shí)間是有的,需要控制清理對(duì)性能的影響。一二設(shè)置先分配清理碎片占用的CPU資源,保證碎片可以正常清理,避免對(duì)Redis處理請(qǐng)求造成性能影響。

active-defrag-cycle-min 20:自動(dòng)碎片整理過(guò)程中占用CPU時(shí)間比例不低于20%,以保證清理任務(wù)正常進(jìn)行。

active-defrag-cycle-max 50:自動(dòng)清理進(jìn)程占用CPU時(shí)間比例不能高于50%。如果超過(guò),會(huì)立即停止清理,避免阻塞 Redis 造成高延遲。

總結(jié)

如果發(fā)現(xiàn)Redis存儲(chǔ)數(shù)據(jù)占用的內(nèi)存比操作系統(tǒng)分配給Redis的內(nèi)存小很多,但是數(shù)據(jù)無(wú)法保存,那么可能是內(nèi)存碎片很多。使用info memory命令查看內(nèi)存碎片mem_fragmentation_ratio指標(biāo)是否正常。

然后我們啟用自動(dòng)清理并合理設(shè)置清理時(shí)間和CPU資源占用。該機(jī)制涉及內(nèi)存復(fù)制,這對(duì) Redis 性能構(gòu)成潛在風(fēng)險(xiǎn)。如果Redis性能變慢,檢查是否是清理碎片導(dǎo)致的。如果是這樣,減小配置active-defrag-cycle-max的值。

以上就是Redis內(nèi)存碎片原理深入分析的詳細(xì)內(nèi)容,更多關(guān)于Redis內(nèi)存碎片的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • redis lua腳本實(shí)戰(zhàn)秒殺和減庫(kù)存的實(shí)現(xiàn)

    redis lua腳本實(shí)戰(zhàn)秒殺和減庫(kù)存的實(shí)現(xiàn)

    本文主要是學(xué)習(xí)一下redis lua腳本的編寫(xiě),以及在redisson這個(gè)redis客戶(hù)端中是怎樣使用的,實(shí)戰(zhàn)一下秒殺場(chǎng)景redis減庫(kù)存lua腳本的編寫(xiě),并偽真實(shí)環(huán)境壓測(cè)查看效果。感興趣的可以了解一下
    2021-11-11
  • redis中bind配置的詳細(xì)步驟

    redis中bind配置的詳細(xì)步驟

    本文主要介紹了redis中bind配置的詳細(xì)步驟,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2023-07-07
  • Redis常用數(shù)據(jù)類(lèi)型命令實(shí)例匯總

    Redis常用數(shù)據(jù)類(lèi)型命令實(shí)例匯總

    這篇文章主要介紹了Redis常用數(shù)據(jù)類(lèi)型命令實(shí)例匯總,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-10-10
  • Redis發(fā)布訂閱和實(shí)現(xiàn).NET客戶(hù)端詳解

    Redis發(fā)布訂閱和實(shí)現(xiàn).NET客戶(hù)端詳解

    發(fā)布訂閱在應(yīng)用級(jí)其作用是為了減少依賴(lài)關(guān)系,通常也叫觀察者模式。主要是把耦合點(diǎn)單獨(dú)抽離出來(lái)作為第三方,隔離易變化的發(fā)送方和接收方。下面這篇文章主要給大家介紹了關(guān)于Redis發(fā)布訂閱和實(shí)現(xiàn).NET客戶(hù)端的相關(guān)資料,需要的朋友可以參考下
    2017-03-03
  • Redis實(shí)現(xiàn)UV統(tǒng)計(jì)的示例代碼

    Redis實(shí)現(xiàn)UV統(tǒng)計(jì)的示例代碼

    本文主要介紹了Redis實(shí)現(xiàn)UV統(tǒng)計(jì)的示例代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2023-01-01
  • 通過(guò)kubesphere部署redis的方法

    通過(guò)kubesphere部署redis的方法

    這篇文章主要介紹了通過(guò)kubesphere部署redis的方法,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-11-11
  • 使用redis獲取自增序列號(hào)實(shí)現(xiàn)方式

    使用redis獲取自增序列號(hào)實(shí)現(xiàn)方式

    這篇文章主要介紹了使用redis獲取自增序列號(hào)實(shí)現(xiàn)方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-12-12
  • Redis生成全局唯一ID的實(shí)現(xiàn)方法

    Redis生成全局唯一ID的實(shí)現(xiàn)方法

    全局唯一ID生成器是一種在分布式系統(tǒng)下用來(lái)生成全局唯一ID的工具,本文主要介紹了Redis生成全局唯一ID的實(shí)現(xiàn)方法,具有一定的參考價(jià)值,感興趣的可以了解一下
    2022-06-06
  • Redis02 使用Redis數(shù)據(jù)庫(kù)(String類(lèi)型)全面解析

    Redis02 使用Redis數(shù)據(jù)庫(kù)(String類(lèi)型)全面解析

    這篇文章主要介紹了Redis02 使用Redis數(shù)據(jù)庫(kù)(String類(lèi)型)全面解析的相關(guān)資料,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下
    2016-07-07
  • 淺談RedisTemplate和StringRedisTemplate的區(qū)別

    淺談RedisTemplate和StringRedisTemplate的區(qū)別

    本文主要介紹了RedisTemplate和StringRedisTemplate的區(qū)別及個(gè)人見(jiàn)解,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-06-06

最新評(píng)論