Redis記憶體碎片深入分析
導讀 | 如果發現Redis儲存資料佔用的記憶體比作業系統分配給Redis的記憶體小很多,但是資料無法儲存,那麼可能是記憶體碎片很多。使用info memory 檢視記憶體碎片mem_fragmentation_ratio指標是否正常。 |
我們先來看一個問題, 假設Redis例項儲存了5GB的資料,現在刪除了2GB的資料,那麼Redis程式佔用的記憶體會不會減少呢?
答案是:它可能仍然佔用大約5GB記憶體,即使Redis資料只佔用大約3GB。
如果maxmemory不設定該引數,Redis不會觸發記憶體淘汰策略刪除資料。
Redis會繼續為新寫入的資料分配記憶體。分配失敗會導致應用程式報錯,當然不會導致當機。
注:設定maxmemory引數,執行 CONFIG SET maxmemory 100mb,或在redis.conf 配置檔案中設定maxmemory 100mb。
使用top命令檢視資料是否已經刪除,為什麼它仍然佔用這麼多記憶體?
當我們使用top命令檢視系統使用情況時,會發現記憶體依然很高,Redis並沒有真正釋放記憶體。那麼記憶體都去哪兒了?這時候我們就需要使用info memory命令獲取Redis記憶體相關的指標。
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程式記憶體消耗主要由以下幾部分組成:
- 記憶體被Redis自己啟動佔用
- 儲存物件資料記憶體
- 緩衝區記憶體:主要由client-output-buffer-limit客戶端輸出緩衝區、copy backlog緩衝區、AOF緩衝區組成
- 記憶體碎片
- 記憶體分配器的分配策略
- 鍵值對的大小不同,刪除操作
Redis自身的空程式佔用的記憶體很小,可以忽略不計,而物件記憶體是最大的,裡面存放了所有的資料。
需要注意, 如果緩衝區有大流量的場景很容易失控,導致Redis記憶體不穩定。
記憶體碎片過多導致有可用空間不足,無法儲存資料。記憶體碎片Fragmentation = used_memory_rss 實際使用的實體記憶體(RSS 值)除以 used_memory 實際儲存的資料記憶體。
記憶體碎片會導致記憶體空間空閒,但無法儲存資料。比如你和女朋友去電影院看電影,你們肯定是要在一起的。
假設現在有 8 個座位,已售出 4 張票,還有 4 張可供購買。不過巧合的是,買票的人很奇怪,都是隔一個座位買票。即使還有4個座位,也不能買順序連線兩個座位的票。
主要有兩個原因:
下面我們就實際發生的原因進行探討。
Redis 預設的記憶體分配器使用jemalloc,可選的分配器有:glibc,tcmalloc。
記憶體分配器不能按需分配,而是使用固定範圍的記憶體塊進行分配。
比如8位元組、16位元組……、2KB、4KB,當申請記憶體最接近固定值時,jemalloc會分配最接近固定值的空間。這樣就會出現記憶體碎片。
比如程式只需要1.5KB,而記憶體分配器會分配2KB的空間,那麼這0.5KB就是碎片。這樣做的目的是減少記憶體分配的次數。比如你申請22個位元組的空間來存放資料,jemalloc就會分配32個位元組。如果後面需要寫入10個位元組,則不需要向作業系統申請空間。您可以使用之前請求的 32 個位元組。
當一個鍵被刪除時,Redis 不會立即將記憶體歸還給作業系統。發生這種情況是因為底層記憶體分配器的管理。例如,大多數已刪除的鍵仍與其他有效鍵分配在同一記憶體頁中。
此外,為了重用空閒記憶體塊,分配器刪除了原始 5 GB 資料中的 2 GB。再次向例項新增資料時,Redis的RSS會保持穩定,不會增加太多。因為記憶體分配器基本上重新使用了之前刪除釋放的2GB記憶體。
由於記憶體分配器是按照固定的大小分配記憶體,因此分配的記憶體空間通常會大於實際資料佔用的大小,這會造成碎片,降低記憶體的儲存效率。
另外,鍵值對的頻繁修改和刪除導致記憶體空間的擴大和釋放。例如,如果原來佔用32個位元組的字串現在修改為佔用20個位元組的字串,那麼釋放的12個位元組就是空閒空間。
如果下一次資料儲存請求需要申請一個13位元組的字串,剛剛釋放的12位元組空間就不能使用,造成碎片。
分片最大的問題:空間總量足夠大,但是這些記憶體並不連續,可能存不下資料。
mem_fragmentation_ratio = used_memory_rss/ used_memory
首先要判斷是否發生了記憶體碎片,重點看info memory命令執行後的mem_fragmentation_ratio指標,表示記憶體碎片率。
如果1 < mem_fragmentation_ratio < 1.5,可以認為是合理的,如果大於1.5,說明碎片已經超過了50%,我們需要採取一些措施來解決碎片過多的問題。 [erji]1. 重啟[/erji] 最簡單的方法是重新啟動。如果未啟用永續性,資料將丟失。 如果開啟持久化,需要使用RDB或者AOF來恢復資料。如果只有一個例項,資料量大會導致恢復階段長時間無法提供服務,高可用性會大大降低。 [erji]2.自動清理記憶體碎片[/erji] 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時間比例不能高於50%。如果超過,會立即停止清理,避免阻塞 Redis 造成高延遲。
如果發現Redis儲存資料佔用的記憶體比作業系統分配給Redis的記憶體小很多,但是資料無法儲存,那麼可能是記憶體碎片很多。使用info memory命令檢視記憶體碎片mem_fragmentation_ratio指標是否正常。
然後我們啟用自動清理併合理設定清理時間和CPU資源佔用。該機制涉及記憶體複製,這對 Redis 效能構成潛在風險。如果Redis效能變慢,檢查是否是清理碎片導致的。如果是這樣,減小配置active-defrag-cycle-max的值。
原文來自:
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69955379/viewspace-2943146/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- Redis效能篇(四)Redis記憶體碎片Redis記憶體
- Redis4.0如何自動清理記憶體碎片Redis記憶體
- 記憶體碎片與緩解記憶體
- Redis記憶體——記憶體消耗(記憶體都去哪了?)Redis記憶體
- 【Redis記憶體策略】Redis記憶體
- Linux堆記憶體管理深入分析Linux記憶體
- linux kernel記憶體碎片防治技術Linux記憶體
- 解決golang 的記憶體碎片問題Golang記憶體
- 一種避免 iOS 記憶體碎片的方法iOS記憶體
- redis的記憶體滿了之後,redis如何回收記憶體嗎Redis記憶體
- 關於redis記憶體分析,記憶體優化Redis記憶體優化
- Linux堆記憶體管理深入分析(下半部)Linux記憶體
- Redis 記憶體壓縮原理Redis記憶體
- Redis的記憶體淘汰策略Redis記憶體
- 精講Redis記憶體模型Redis記憶體模型
- 深入學習 Redis(1):Redis 記憶體模型Redis記憶體模型
- [20170126]hugepage與記憶體碎片.txt記憶體
- TimesTen記憶體碎片(高水位)回收步驟詳解記憶體
- docker部署redis快取記憶體DockerRedis快取記憶體
- Redis持久化——記憶體快照(RDB)Redis持久化記憶體
- Redis-記憶體優化(一)Redis記憶體優化
- 【Redis】 redis解析rdb檔案,記憶體排序等Redis記憶體排序
- Redis In Action 筆記(七)降低記憶體使用Redis筆記記憶體
- Redis 記憶體優化神技,小記憶體儲存大資料Redis記憶體優化大資料
- 全記憶體的redis用習慣了?那能突破記憶體限制類redis產品ssdb呢?記憶體Redis
- Redis 記憶體淘汰機制詳解Redis記憶體
- Redis記憶體淘汰策略配置翻譯Redis記憶體
- Redis記憶體回收:LRU演算法Redis記憶體演算法
- Redis的記憶體回收機制和記憶體過期淘汰策略詳解Redis記憶體
- Redis 記憶體突增時,如何定量分析其記憶體使用情況Redis記憶體
- Redis的記憶體和實現機制Redis記憶體
- Redis 過期時間與記憶體管理Redis記憶體
- Redis 雜湊結構記憶體模型剖析Redis記憶體模型
- Redis 報”OutOfDirectMemoryError“(堆外記憶體溢位)RedisError記憶體溢位
- Redis 記憶體使用優化與儲存Redis記憶體優化
- 線上redis服務記憶體異常分析。Redis記憶體
- [Redis]過期刪除和記憶體淘汰Redis記憶體
- Redis 實戰 —— 12. 降低記憶體佔用Redis記憶體