通過
CONFIG SET maxmemory 100mb
或者在
redis.conf
配置檔案設定
maxmemory 100mb
Redis 記憶體占用限制。當達到記憶體最大值值,會觸發記憶體淘汰政策。
除此之外,當 key 達到過期時間,Redis 會有以下兩種删除過期資料的政策:
- 背景定時任務選取部分資料删除;
- 惰性删除。
假設 Redis 執行個體儲存了 5GB 的資料,現在删除了 2GB 資料,Redis 程序占用的記憶體一定會降低麼?(也叫做 RSS,程序消耗記憶體頁數)。
答案是:可能依然占用了大約 5GB 的記憶體,即使 Redis 的資料隻占用了 3GB 左右。
大家一定要設定
maxmemory
,否則 Redis 會繼續為新寫入的資料配置設定記憶體,無法配置設定就會導緻應用程式報錯,當然不會導緻當機。
釋放的記憶體去哪了
明明删除了資料,使用 top 指令檢視,為何還是占用了那麼多記憶體?
記憶體都去哪了?使用
info memory
指令擷取 Redis 記憶體相關名額,我列舉了幾個重要的資料:
127.0.0.1:6379> info memory
# Memory
used_memory:1132832 // Redis 存儲資料占用的記憶體量
used_memory_human:1.08M // 人類可讀形式傳回記憶體總量
used_memory_rss:2977792 // 作業系統角度,程序占用的實體總記憶體
used_memory_rss_human:2.84M // used_memory_rss 可讀性模式展示
used_memory_peak:1183808 // 記憶體使用的最大值,表示 used_memory 的峰值
used_memory_peak_human:1.13M // 以可讀的格式傳回 used_memory_peak的值
used_memory_lua:37888 // Lua 引擎所消耗的記憶體大小。
used_memory_lua_human:37.00K
maxmemory:2147483648 // 能使用的最大記憶體值,位元組為機關。
maxmemory_human:2.00G // 可讀形式
maxmemory_policy:noeviction // 記憶體淘汰政策
// used_memory_rss / used_memory 的比值,代表記憶體碎片率
mem_fragmentation_ratio:2.79
Redis 程序記憶體消耗主要由以下部分組成:
- Redis 自身啟動所占用的記憶體;
- 存儲對象資料記憶體;
- 緩沖區記憶體:主要由 client-output-buffer-limit 用戶端輸出緩沖區、複制積壓緩沖區、AOF 緩沖區。
- 記憶體碎片。
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLicmbw5COBVCN5UyNFVCMBVCR4USNFVCO5UCRBVSNFVSN4UiN4USNFVycpRWZy9CXzlGZlJ3Lc12bj5ycj5Wd5lGbh5iblhmeuVGaz1ibj1ycz9mLlRXeiV2Zh12Lc9CX6MHc0RHaiojIsJye.png)
Redis 自身空程序占用的記憶體很小可以忽略不計,對象記憶體是占比對打的一塊,裡面存儲着所有的資料。
緩沖區記憶體在大流量場景容易失控,造成 Redis 記憶體不穩定,需要重點關注。
記憶體碎片過大會導緻明明有空間可用,但是卻無法存儲資料。
碎片 = used_memory_rss 實際使用的實體記憶體(RSS 值)除以 used_memory 實際存儲資料記憶體。
什麼是記憶體碎片
記憶體碎片會造成明明有記憶體空間空閑,可是卻無法存儲資料。舉個例子,你跟漂亮小姐姐去電影院看電影,肯定想連在一塊坐。
假設現在有 8 個座位,已經賣出了 4 張票,還有 4 張可以買。可是好巧不巧,買票的人很奇葩,分别間隔一個座位買票。
即使還有 4 個座位空閑,可是你卻買不到兩個座位連在一塊的票,厚禮蟹!
記憶體碎片形成原因
記憶體碎片是什麼原因導緻呢?
主要有兩個原因:
- 記憶體配置設定器的配置設定政策。
- 鍵值對的大小不一樣和删改操作:Redis 頻繁做更新操作、大量過期資料删除,釋放的空間(不夠連續)無法得到複用,導緻碎片率上升。
接下來我分别探讨實際發生的原因……
記憶體配置設定器的配置設定政策
Redis 預設的記憶體配置設定器采用 jemalloc,可選的配置設定器還有:glibc、tcmalloc。
記憶體配置設定器并不能做到按需配置設定,而是采用固定範圍的記憶體塊進行配置設定。
例如 8 位元組、16 位元組…..,2 KB,4KB,當申請記憶體最近接某個固定值的時候,jemalloc 會給它配置設定最接近固定值大小的空間。
這樣就會出現記憶體碎片,比如程式隻需要 1.5 KB,記憶體配置設定器會配置設定 2KB 空間,那麼這 0.5KB 就是碎片。
這麼做的目的是減少記憶體配置設定次數,比如申請 22 位元組的空間儲存資料,jemalloc 就會配置設定 32 位元組,如果後邊還要寫入 10 位元組,就不需要再向作業系統申請空間了,可以使用之前申請的 32 位元組。
删除 key 的時候,Redis 并不會立馬把記憶體歸還給作業系統,出現這個情況是因為底層記憶體配置設定器管理導緻,比如大多數已經删除的 key 依然與其他有效的 key配置設定在同一個記憶體頁中。
另外,配置設定器為了複用空閑的記憶體塊,原有 5GB 的資料中删除了 2 GB 後,當再次添加資料到執行個體中,Redis 的 RSS 會保持穩定,不會增長太多。
因為記憶體配置設定器基本上複用了之前删除釋放出來的 2GB 記憶體。
鍵值對大小不一樣和删改操作
由于記憶體配置設定器是按照固定大小配置設定記憶體,是以通常配置設定的記憶體空間比實際資料占用的大小多一些,會造成碎片,降低記憶體的存儲效率。
另外,鍵值對的頻繁修改和删除,導緻記憶體空間的擴容和釋放,比如原本占用 32 位元組的字元串,現在修改為占用 20 位元組的字元串,那麼釋放出的 12 位元組就是空閑空間。
如果下一個資料存儲請求需要申請 13 位元組的字元串,那麼剛剛釋放的 12 位元組空間無法使用,導緻碎片。
碎片最大的問題:空間總量足夠大,但是這些記憶體不是連續的,可能大緻無法存儲資料。
記憶體碎片解決之道
那該如何解決呢?
首先要确定是否發生了記憶體碎片,重點關注前面
INFO memory
指令提示的
mem_fragmentation_ratio
名額,表示記憶體碎片率:
mem_fragmentation_ratio = used_memory_rss/ used_memory
如果 1 < 碎片率 < 1.5,可以認為是合理的,而大于 1.5 說明碎片已經超過 50%,我們需要采取一些手段解決碎片率過大的問題。
重新開機大法
最簡單粗暴的方式就是重新開機,如果沒有開啟持久化,資料會丢失。
開啟持久化的話,需要使用 RDB 或者 AOF 恢複資料,如果隻有一個執行個體,資料大的話會導緻恢複階段長時間無法提供服務,高可用大打折扣。
咋辦呢?碼哥靓仔
自動清理記憶體碎片
既然你都叫我靓仔了,就傾囊相助告訴你終極殺招:Redis 4.0 版本後,自身提供了一種記憶體碎片清理機制。
怎麼清理呢?
很簡單,還是上面的例子,想要買兩張連在一塊的電影票。與與别人溝通調換下位置,就實作了。
對于 Redis 來說,當一塊連續的記憶體空間被劃分為好幾塊不連續的空間的時候,作業系統先把資料以依次挪動拼接在一塊,并釋放原來資料占據的空間,形成一塊連續空閑記憶體空間。。
如下圖所示:
自動清理記憶體碎片的代價
自動清理雖好,可不要肆意妄為,作業系統把資料移動到新位置,再把原有空間釋放是需要消耗資源的。
Redis 操作資料的指令是單線程,是以在資料複制移動的時候,隻能等待清理碎片完成才能處理請求,造成性能損耗。
如何避免清理碎片對性能的影響又能實作自動清理呢?
好問題,通過以下兩個參數來控制記憶體碎片清理和結束時機,避免占用 CPU 過多,減少清理碎片對 Redis 處理請求的性能影響。
開啟自動記憶體碎片清理
CONFIG SET activedefrag yes
這隻是開啟自動清理,何時清理要同時滿足以下兩個條件才會觸發清理操作。
清理的條件
active-defrag-ignore-bytes 200mb
:記憶體碎片占用的記憶體達到 200MB,開始清理;
active-defrag-threshold-lower 20
:記憶體碎片的空間占慚怍系統配置設定給 Redis 空間的 20% ,開始清理。
避免對性能造成影響
清理時間有了,還需要控制清理對性能的影響。由一項兩個設定先配置設定清理碎片占用的 CPU 資源,保證既能正常清理碎片,又能避免對 Redis 處理請求的性能影響。
active-defrag-cycle-min 20
:自動清理過程中,占用 CPU 時間的比例不低于 20%,進而保證能正常展開清理任務。
active-defrag-cycle-max 50
:自動清理過程占用的 CPU 時間比例不能高于 75%,超過的話就立刻停止清理,避免對 Redis 的阻塞,造成高延遲。
總結
如果你發現明明 Redis 存儲資料的記憶體占用遠小于作業系統配置設定給 Redis 的記憶體,而又無法儲存資料,那可能出現大量記憶體碎片了。
通過
info memory
指令,看下記憶體碎片
mem_fragmentation_ratio
名額是否正常。
那麼我們就開啟自動清理并合理設定清理時機和 CPU 資源占用,該機制涉及到記憶體拷貝,會對 Redis 性能造成潛在風險。
如果遇到 Redis 性能變慢,排查下是否由于清理碎片導緻,如果是,那就調小
active-defrag-cycle-max
的值。