Reids作為一個基於記憶體的資料庫,記憶體是否能夠高效合理的利用至關重要!從價格上來講,我們從某寶或某東上可以看到記憶體條的價格要比普通的機械硬碟貴上十幾倍,就算是是固態硬碟也要貴上不少,從效能上來說,記憶體佔用過高同樣會引起Reids響應變慢,從高可用上來說,記憶體過大可能會會引起部分資料丟失,故障恢復變慢.......
我們首先要知道Redis都消耗在哪,才能更好的管理優化記憶體的使用,已達到使用更少的記憶體儲存更多的資料、節省成本的目的,才能真正實現Redis的高效能、高可用。
1 Redis記憶體消耗
Redis記憶體消耗主要在於其主程式消耗和子程式消耗。而主程式消耗又主要包括自身記憶體、物件記憶體、緩衝區記憶體、記憶體碎片五個方面。
1.1 自身記憶體
自身記憶體是指Redis程式自身所佔用的記憶體,這部分記憶體通常很小,一個空的Redis程式所消耗的記憶體幾乎可以忽略不計。因此我們在分析記憶體消耗的時候一般不考慮其自身記憶體。
1.2 物件記憶體
物件記憶體是Redis記憶體中佔用最大的。我們知道Redis主要有五大物件,字串、列表、雜湊、集合、有序集合。其它如BigMaps、GEO等也都是基於這五大物件實現的。每種物件底層所使用的資料結構都是不同的,因此它們所佔用的記憶體空間大小也是不同的。在使用過程中我們要根據場景選擇合適的物件,以達到記憶體合理利用、避免溢位的目的。
關於Redis的五大物件和其底層所使用的幾種資料結構,可以檢視我的其他幾篇文章。傳送門
此外,Redis的每一種物件都是key-value的鍵值對形式。每個鍵值對的建立都包含兩個物件,key物件和value物件。因此物件記憶體的消耗可以理解為sizeof(key)+sizeof(value)。而key物件都是字串型別的,在使用過程中我們不應該忽略key物件所佔用的記憶體,應該避免使用過大的key。
1.3 緩衝區記憶體
Redis主要有三個緩衝區,客戶端緩衝區、AOF緩衝區、複製積壓緩衝區。
客戶端緩衝區是為了解決客戶端和服務端請求和處理速度不匹配問題的,它又分為輸入和輸出緩衝區。
輸入緩衝區會先把客戶端傳送過來的命令暫存起來,Redis 主執行緒再從輸入緩衝區中讀取命令,進行處理。當在處理完資料後,會把結果寫入到輸出緩衝區,再通過輸出緩衝區返回給客戶端。
AOF緩衝區我們前面的文章已經學習過,是在進行AOF持久化時所用到的緩衝區,AOF緩衝區消耗的記憶體取決於AOF重寫時間和寫入命令量, 這部分空間佔用通常很小關於AOF緩衝區的介紹我們可以複習一下
複製積壓緩衝區則是在叢集環境中為了保證主從節點資料同步的所設定的。
主節點在向從節點傳輸 RDB 檔案的同時,會繼續接收客戶端傳送的寫命令請求。這些寫命令就會先儲存在複製緩衝區中,等 RDB 檔案傳輸完成後,再傳送給從節點去執行。主節點上會為每個從節點都維護一個複製緩衝區,來保證主從節點間的資料同步。
1.4 記憶體碎片
記憶體碎片主要是由於作業系統的記憶體分配機制和Redis記憶體分配器的分配策略所決定的。
記憶體分配器為了更好地管理和重複利用記憶體, 分配記憶體策略一般採用固定範圍的記憶體塊進行分配。例如當儲存5KB物件時記憶體分配器可能會採用8KB的塊儲存, 而剩下的3KB空間變為了記憶體碎片不能再分配給其他物件儲存。
關於記憶體碎片的問題,後面會有單獨的一篇文章來詳細的進行解釋。
1.5 子程式記憶體消耗
除了上面所提到的4種記憶體消耗之外,還有一種也不能忽視,那就是子程式的記憶體消耗。
子程式記憶體消耗主要指執行AOF/RDB
重寫時Redis建立的子程式記憶體消耗。我們在學習Redis持久化的時候知道,在執行RDB快照和AOF重寫時主程式會fork出一個子程式,由子程式完成快照和重寫操作,雖然使用了寫時複製的技術,子程式可以不用完全複製父程式的所有實體記憶體,但是仍然需要複製其記憶體頁表,在此期間如果有寫入操作則需要複製出一份副本出來。因此子程式同樣會消耗一部分記憶體,其消耗的記憶體量取決於RDB和AOF期間的寫入命令量。在執行RDB和AOF重寫的時候為了防止記憶體溢位,會預留一部分記憶體。
2 記憶體消耗統計
關於分析Redis記憶體消耗的分析,我們可以使用info memory
命令來獲取記憶體相關的指標,讀懂每個指標有助於我們更加熟練的分析Redis的記憶體使用情況,如下一份全量的Redis最新版本(6.2.1)的info memory
命令的各項指標說明。
127.0.0.1:6379> info memory
used_memory:87795176 # Redis分配的記憶體總量(byte),包含redis程式內部的開銷和資料佔用的記憶體
used_memory_human:83.73M # Redis分配的記憶體總量(mb)
used_memory_rss:222318592 # 向作業系統申請的記憶體大小(byte)
used_memory_rss_human:212.02M # 向作業系統申請的記憶體大小(mb)
used_memory_peak:337032496 # redis的記憶體消耗峰值(byte)
used_memory_peak_human:321.42M # redis的記憶體消耗峰值(mb)
used_memory_peak_perc:26.05% # 使用記憶體與峰值記憶體的百分比(used_memory / used_memory_peak) *100%
used_memory_overhead:2010038 # Redis維護資料集的內部機制所需的記憶體開銷,包括所有客戶端輸出緩衝區、查詢緩衝區、AOF重寫緩衝區和主從複製的backlog
used_memory_startup:1960232 # Redis啟動完成使用的記憶體
used_memory_dataset:85785138 # 資料佔用的記憶體(used_memory - used_memory_overhead)
used_memory_dataset_perc:99.94% # 資料佔用的記憶體大小百分比,(used_memory_dataset / (used_memory - used_memory_startup))*100%
allocator_allocated:88139168 # 分配器分配的記憶體
allocator_active:89964544 # 分配器活躍的記憶體
allocator_resident:389095424 # 分配器常駐的記憶體
total_system_memory:67118374912 # 主機記憶體總量(byte)
total_system_memory_human:62.51G # 主機記憶體總量(mb)
used_memory_lua:37888 # Lua引擎儲存佔用的記憶體(byte)
used_memory_lua_human:37.00K # Lua引擎儲存佔用的記憶體(mb)
used_memory_scripts:0 # Lua指令碼所佔用的記憶體(byte)
used_memory_scripts_human:0B # Lua指令碼所佔用的記憶體(mb)
number_of_cached_scripts:0 # 快取的Lua指令碼數
maxmemory:0 # 配置中設定的最大可使用記憶體值(byte),預設0,不限制
maxmemory_human:0B # 配置中設定的最大可使用記憶體值(mb)
maxmemory_policy:noeviction # 當達到maxmemory時的淘汰策略
allocator_frag_ratio:1.02 # 分配器的碎片率
allocator_frag_bytes:1825376 # 分配器的碎片大小
allocator_rss_ratio:4.32 # 分配器常駐記憶體比例
allocator_rss_bytes:299130880 # 分配器的常駐記憶體大小
rss_overhead_ratio:0.57 # 常駐記憶體開銷比例
rss_overhead_bytes:-166776832 # 常駐記憶體開銷大小
mem_fragmentation_ratio:2.53 # 碎片率(used_memory_rss / used_memory),正常(1,1.6),大於比例說明記憶體碎片嚴重
mem_fragmentation_bytes:134564432 # 記憶體碎片大小
mem_not_counted_for_evict:0 # 被驅逐的記憶體
mem_replication_backlog:0 # redis複製積壓緩衝區記憶體
mem_clients_slaves:0 # Redis節點客戶端消耗記憶體
mem_clients_normal:49694 # Redis所有常規客戶端消耗記憶體
mem_aof_buffer:0 # AOF使用記憶體
mem_allocator:jemalloc-5.1.0 # 記憶體分配器
active_defrag_running:0 # 活動碎片整理是否處於活動狀態(0沒有,1正在執行)
lazyfree_pending_objects:0 # 0-不存在延遲釋放的掛起物件
lazyfreed_objects:0 # 已經延遲釋放的物件
3 總結
最後,我們用一張思維導圖來看一看Redis的記憶體都去哪兒了
系列文章:
-----END-----
關注下方公眾號,回覆“Redis”,可得Redis相關學習資料