Redis內存——內存消耗(內存都去哪了?)
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相關學習資料