redis調優 -- 內存碎片


最近查看了一下redis運行狀況,發現公司測試服務器的redis內存不太夠用,但是實際占用內存的數據量其實不大,以前也沒有這種情況,之前在cache層新增了一個防刷積分任務的邏輯才會這樣,搜索一下原因,發現原來是產生了大量的內存碎片。

首先,查看redis的內存狀態,要用info memory指令


 
2018-06-01_110028.png

ps:(這個是我flushdb后的結果,反面教材來的。。。)
圖中幾個參數的意義:

1、used_memory:

已經使用了的內存大小,包括redis進程內部開銷和你的cache的數據所占用的內存,單位byte。

2、used_memory_human:

用戶數據所占用的內存,就是你緩存的數據的大小。

3、used_memory_rss:(rss for Resident Set Size)

表示redis物理內存的大小,即向OS申請了多少內存使用與used_memory的區別在后面解釋。

4、used_memory_peak:

redis內存使用的峰值。

5、used_memory_peak_human:

用戶cache數據的峰值大小。

6、used_memory_lua:

執行lua腳本所占用的內存。

7、mem_fragmentation_ratio:

 

 

內存碎片率,計算公式:
 
190138549569988.png

ratio指數>1表明有內存碎片,越大表明越多,<1表明正在使用虛擬內存,虛擬內存其實就是硬盤,性能比內存低得多,這是應該增強機器的內存以提高性能。一般來說,mem_fragmentation_ratio的數值在1 ~ 1.5之間是比較健康的。

8、mem_allocator:

在編譯時指定的Redis使用的內存分配器,可以是libc、jemalloc、tcmalloc,默認是jemalloc。jemalloc在64位系統中,將內存空間划分為小、大、巨大三個范圍;每個范圍內又划分了許多小的內存塊單位;存儲數據的時候,會選擇大小最合適的內存塊進行存儲。
jemalloc划分的內存單元如下圖所示:


 
1174710-20180327001126509-2023165562.png

(圖侵刪)

----------------------------------------------------- 分割線 ------------------------------------------------

產生原因

可以這樣認為,redis產生內存碎片有兩個原因,
A:redis自身的內存分配器。
B:修改cache的值,且修改后的value與原來value的大小差異較大。

進程需要用內存的話,會先通過OS向device申請,然后才能夠使用。一般進程在不需要使用的時候,會釋放掉這部分內存並返回給device。但是redis作者可能為了更高的性能,所以在redis中實現了自己的內存分配器來管理內存,不會馬上返還內存,不用每次都向OS申請了,從而實現高性能。

但是,在內存分配器的那張圖片我們知道,redis的每個k-v對初始化的內存大小是最適合的,當這個value改變的並且原來內存大小不適用的時候,就需要重新分配內存了。(但是value存比原來小不知道會不會產生碎片)。重新分配之后,就會有一部分內存redis無法正常回收,一直占用着。

----------------------------------------------------- 分割線 ------------------------------------------------

知道了原因就可以解決問題了,網上找到了兩個解決方案:
1、重啟redis服務,簡單粗暴。
2、redis4.0以上可以使用新增指令來手動回收內存碎片,配置監控使用性能更佳

最近看到redis4支持內存碎片清理了, 之前一直期待有這么一個功能, 因為之前遇到內存碎片的解決辦法就是重啟, 現在終於有了優雅的解決方案.\^o^/, 這個功能其實oranagra 在2017年1月1日已經提交pr了, 相關地址: https://github.com/antirez/redis/pull/3720

版本說明:

  •  Redis 4.0-RC3 以上版本才支持的
  • 需要使用jemalloc作為內存分配器(默認的)

功能介紹:

  • 支持在運行期進行自動內存碎片清理 (config set activedefrag yes)
  • 支持通過命令 memory purge 進行清理(與自動清理區域不同)

功能驗證流程:

(1) 首先需要拉取4.0-RC3之后的版本代碼, 編譯

(2) 啟動時限定內存大小為1g並啟動lru, 命令如下:

./src/redis-server --maxmemory 1gb --maxmemory-policy allkeys-lru --activedefrag no --port 6383

(3) 構造大量數據並導致lru, 這樣可以觸發內存碎片, 命令如下:

redis-cli -p 6383 debug populate 7000000 asdf 150

(4) 查看當前的內存使用情況, 會發現有200多萬的數據被清理掉了

$ redis-cli -p 6383 info keyspace
# Keyspace db0:keys=4649543,expires=0,avg_ttl=0

(5) 查看當前的內存碎片率, 這時碎片率(mem_fragmentation_ratio)很高 : 1.54, 意味着54%的內存浪費

$ redis-cli -p 6383 info memory
# Memory used_memory:1073741736 used_memory_human:1024.00M used_memory_rss:1650737152 used_memory_rss_human:1.54G used_memory_peak:1608721680 used_memory_peak_human:1.50G used_memory_peak_perc:66.75% used_memory_overhead:253906398 used_memory_startup:766152 used_memory_dataset:819835338 used_memory_dataset_perc:76.41% total_system_memory:67535904768 total_system_memory_human:62.90G used_memory_lua:37888 used_memory_lua_human:37.00K maxmemory:1073741824 maxmemory_human:1.00G maxmemory_policy:allkeys-lru mem_fragmentation_ratio:1.54 mem_allocator:jemalloc-4.0.3 active_defrag_running:0 lazyfree_pending_objects:0

(6) 看看內存分配的詳細情況, 這個地方看不懂可以看看: 科普文, 關鍵的是util指標, 指的是內存利用率, 最大的bins內存util是0.661, 說明內存利用率不高

$ echo "`redis-cli -p 6383 memory malloc-stats`" ___ Begin jemalloc statistics ___ Version: 4.0.3-0-ge9192eacf8935e29fc62fddc2701f7942b1cc02c Assertions disabled Run-time option settings: opt.abort: false opt.lg_chunk: 21 opt.dss: "secondary" opt.narenas: 48 opt.lg_dirty_mult: 3 (arenas.lg_dirty_mult: 3) opt.stats_print: false opt.junk: "false" opt.quarantine: 0 opt.redzone: false opt.zero: false opt.tcache: true opt.lg_tcache_max: 15 CPUs: 12 Arenas: 48 Pointer size: 8 Quantum size: 8 Page size: 4096 Min active:dirty page ratio per arena: 8:1 Maximum thread-cached size class: 32768 Chunk size: 2097152 (2^21) Allocated: 1074509704, active: 1609732096, metadata: 41779072, resident: 1651118080, mapped: 1652555776 Current active ceiling: 1610612736 arenas[0]: assigned threads: 1 dss allocation precedence: secondary min active:dirty page ratio: 8:1 dirty pages: 393001:24 active:dirty, 0 sweeps, 0 madvises, 0 purged allocated nmalloc ndalloc nrequests small: 1006565256 28412640 9802493 35714594 large: 835584 20 11 20 huge: 67108864 1 0 1 total: 1074509704 28412661 9802504 35714615 active: 1609732096 mapped: 1650458624 metadata: mapped: 40202240, allocated: 491904 bins: size ind allocated nmalloc ndalloc nrequests curregs curruns regs pgs util nfills nflushes newruns reruns 8 0 1992 319 70 357 249 1 512 1 0.486 7 8 1 0 16 1 148618896 14110300 4821619 14310175 9288681 55119 256 1 0.658 141103 48825 55119 5 24 2 112104360 7200400 2529385 7300348 4671015 14064 512 3 0.648 72004 25881 14064 1 32 3 288 112 103 7003270 9 1 128 1 0.070 3 7 1 0 40 4 360 109 100 171 9 1 512 5 0.017 3 7 1 0 48 5 1248 112 86 63 26 1 256 3 0.101 2 5 1 0 56 6 896 106 90 16 16 1 512 7 0.031 2 6 1 0 64 7 128 64 62 5 2 1 64 1 0.031 1 3 1 0 80 8 880 106 95 7 11 1 256 5 0.042 2 4 1 0 96 9 9120 212 117 97 95 1 128 3 0.742 4 6 2 1 112 10 336 109 106 2 3 1 256 7 0.011 3 6 3 0 128 11 640 40 35 4 5 1 32 1 0.156 3 4 2 0 160 12 740617440 7000148 2371289 7000001 4628859 54688 128 5 0.661 70271 24334 54689 4 192 13 768 68 64 1 4 1 64 3 0.062 2 4 2 0 224 14 4683616 100000 79091 99946 20909 781 128 7 0.209 1000 1641 782 0 256 15 0 16 16 4 0 0 16 1 1 1 3 1 0 320 16 5120 64 48 16 16 1 64 5 0.250 1 3 1 0 384 17 768 33 31 2 2 1 32 3 0.062 1 3 1 0 448 18 28672 64 0 0 64 1 64 7 1 1 0 1 0 512 19 1024 10 8 4 2 1 8 1 0.250 1 2 2 0 640 20 0 32 32 1 0 0 32 5 1 1 3 1 0 --- 896 22 48384 85 31 50 54 2 32 7 0.843 2 3 2 0 1024 23 3072 10 7 3 3 1 4 1 0.750 1 2 3 0 1280 24 20480 16 0 0 16 1 16 5 1 1 0 1 0 1536 25 15360 10 0 0 10 2 8 3 0.625 1 0 2 0 1792 26 28672 16 0 0 16 1 16 7 1 1 0 1 0 2048 27 4096 10 8 2 2 1 2 1 1 1 2 5 0 --- 3584 30 35840 10 0 0 10 2 8 7 0.625 1 0 2 0 --- 5120 32 250880 49 0 49 49 13 4 5 0.942 0 0 13 0 --- 8192 35 81920 10 0 0 10 10 1 2 1 1 0 10 0 --- large: size ind allocated nmalloc ndalloc nrequests curruns 16384 39 16384 2 1 2 1 20480 40 40960 2 0 2 2 --- 32768 43 32768 1 0 1 1 40960 44 40960 10 9 10 1 --- 81920 48 81920 1 0 1 1 --- 131072 51 131072 1 0 1 1 163840 52 163840 1 0 1 1 --- 327680 56 327680 1 0 1 1 --- 1048576 63 0 1 1 1 0 --- huge: size ind allocated nmalloc ndalloc nrequests curhchunks --- 67108864 87 67108864 1 0 1 1 --- --- End jemalloc statistics ---

(7) 開啟自動內存碎片整理

$ redis-cli -p 6383 config set activedefrag yes OK

(8) 等會兒再看看, 發現內存碎片降低了

$ redis-cli -p 6383 info memory
# Memory used_memory:1073740712 used_memory_human:1024.00M used_memory_rss:1253371904 used_memory_rss_human:1.17G used_memory_peak:1608721680 used_memory_peak_human:1.50G used_memory_peak_perc:66.74% used_memory_overhead:253906398 used_memory_startup:766152 used_memory_dataset:819834314 used_memory_dataset_perc:76.41% total_system_memory:67535904768 total_system_memory_human:62.90G used_memory_lua:37888 used_memory_lua_human:37.00K maxmemory:1073741824 maxmemory_human:1.00G maxmemory_policy:allkeys-lru mem_fragmentation_ratio:1.17 mem_allocator:jemalloc-4.0.3 active_defrag_running:0 lazyfree_pending_objects:0

(9) 可以再看看內存利用率, 可以看到已經上升到0.82

$ echo "`redis-cli -p 6383 memory malloc-stats`" ___ Begin jemalloc statistics ___ Version: 4.0.3-0-ge9192eacf8935e29fc62fddc2701f7942b1cc02c Assertions disabled Run-time option settings: opt.abort: false opt.lg_chunk: 21 opt.dss: "secondary" opt.narenas: 48 opt.lg_dirty_mult: 3 (arenas.lg_dirty_mult: 3) opt.stats_print: false opt.junk: "false" opt.quarantine: 0 opt.redzone: false opt.zero: false opt.tcache: true opt.lg_tcache_max: 15 CPUs: 12 Arenas: 48 Pointer size: 8 Quantum size: 8 Page size: 4096 Min active:dirty page ratio per arena: 8:1 Maximum thread-cached size class: 32768 Chunk size: 2097152 (2^21) Allocated: 1074509800, active: 1307602944, metadata: 41779072, resident: 1512247296, mapped: 1652555776 Current active ceiling: 1308622848 arenas[0]: assigned threads: 1 dss allocation precedence: secondary min active:dirty page ratio: 8:1 dirty pages: 319239:39882 active:dirty, 4878 sweeps, 6343 madvises, 33915 purged allocated nmalloc ndalloc nrequests small: 1006565352 35456589 16846439 45126633 large: 835584 24 15 24 huge: 67108864 1 0 1 total: 1074509800 35456614 16846454 45126658 active: 1307602944 mapped: 1650458624 metadata: mapped: 40202240, allocated: 491904 bins: size ind allocated nmalloc ndalloc nrequests curregs curruns regs pgs util nfills nflushes newruns reruns 8 0 1992 319 70 357 249 1 512 1 0.486 7 8 1 0 16 1 148618896 17658482 8369801 17858357 9288681 44332 256 1 0.818 141103 48825 55119 26364 24 2 112104360 8897298 4226283 8997246 4671015 11525 512 3 0.791 72004 25881 14064 6205 32 3 384 115 103 9371363 12 1 128 1 0.093 4 7 1 0 40 4 360 109 100 171 9 1 512 5 0.017 3 7 1 0 48 5 1248 112 86 63 26 1 256 3 0.101 2 5 1 0 56 6 896 106 90 16 16 1 512 7 0.031 2 6 1 0 64 7 128 64 62 5 2 1 64 1 0.031 1 3 1 0 80 8 880 106 95 7 11 1 256 5 0.042 2 4 1 0 96 9 9120 212 117 97 95 1 128 3 0.742 4 6 2 1 112 10 336 109 106 2 3 1 256 7 0.011 3 6 3 0 128 11 640 40 35 4 5 1 32 1 0.156 3 4 2 0 160 12 740617440 8788058 4159199 8787911 4628859 44056 128 5 0.820 70271 24334 54689 26488 192 13 768 68 64 1 4 1 64 3 0.062 2 4 2 0 224 14 4683616 110956 90047 110902 20909 467 128 7 0.349 1000 1641 782 105 256 15 0 16 16 4 0 0 16 1 1 1 3 1 0 320 16 5120 64 48 16 16 1 64 5 0.250 1 3 1 0 384 17 768 33 31 2 2 1 32 3 0.062 1 3 1 0 448 18 28672 64 0 0 64 1 64 7 1 1 0 1 0 512 19 1024 10 8 4 2 1 8 1 0.250 1 2 2 0 640 20 0 32 32 1 0 0 32 5 1 1 3 1 0 --- 896 22 48384 85 31 50 54 2 32 7 0.843 2 3 2 0 1024 23 3072 10 7 3 3 1 4 1 0.750 1 2 3 0 1280 24 20480 16 0 0 16 1 16 5 1 1 0 1 0 1536 25 15360 10 0 0 10 2 8 3 0.625 1 0 2 0 1792 26 28672 16 0 0 16 1 16 7 1 1 0 1 0 2048 27 4096 10 8 2 2 1 2 1 1 1 2 5 0 --- 3584 30 35840 10 0 0 10 2 8 7 0.625 1 0 2 0 --- 5120 32 250880 49 0 49 49 13 4 5 0.942 0 0 13 0 --- 8192 35 81920 10 0 0 10 10 1 2 1 1 0 10 0 --- large: size ind allocated nmalloc ndalloc nrequests curruns 16384 39 16384 2 1 2 1 20480 40 40960 2 0 2 2 --- 32768 43 32768 1 0 1 1 40960 44 40960 14 13 14 1 --- 81920 48 81920 1 0 1 1 --- 131072 51 131072 1 0 1 1 163840 52 163840 1 0 1 1 --- 327680 56 327680 1 0 1 1 --- 1048576 63 0 1 1 1 0 --- huge: size ind allocated nmalloc ndalloc nrequests curhchunks --- 67108864 87 67108864 1 0 1 1 --- --- End jemalloc statistics ---

(10) 別急, 還有一個大招: 手動清理

$ redis-cli -p 6383 memory purge

(11) 再次查看內存使用情況: 發現碎片率降到1.04, 內存利用率到0.998, 內存碎片基本上消滅了^_^

$ redis-cli -p 6383 info memory
# Memory used_memory:1073740904 used_memory_human:1024.00M used_memory_rss:1118720000 used_memory_rss_human:1.04G used_memory_peak:1608721680 used_memory_peak_human:1.50G used_memory_peak_perc:66.74% used_memory_overhead:253906398 used_memory_startup:766152 used_memory_dataset:819834506 used_memory_dataset_perc:76.41% total_system_memory:67535904768 total_system_memory_human:62.90G used_memory_lua:37888 used_memory_lua_human:37.00K maxmemory:1073741824 maxmemory_human:1.00G maxmemory_policy:allkeys-lru mem_fragmentation_ratio:1.04 mem_allocator:jemalloc-4.0.3 active_defrag_running:0 lazyfree_pending_objects:0 $ 

配置說明:

# Enabled active defragmentation # 碎片整理總開關 # activedefrag yes  # Minimum amount of fragmentation waste to start active defrag # 內存碎片達到多少的時候開啟整理 active-defrag-ignore-bytes 100mb  # Minimum percentage of fragmentation to start active defrag # 碎片率達到百分之多少開啟整理 active-defrag-threshold-lower 10  # Maximum percentage of fragmentation at which we use maximum effort # 碎片率小余多少百分比開啟整理 active-defrag-threshold-upper 100  # Minimal effort for defrag in CPU percentage active-defrag-cycle-min 25  # Maximal effort for defrag in CPU percentage active-defrag-cycle-max 75

總結: 

從測試的結果看, 效果還是非常不錯的, 另外在配置中我們可以看到如下一段聲明:

說明現在這個功能還是實驗性質的, 對應的命令在官方文檔中都沒有看到. 但是它也說經過了壓力測試, 而且現在也一年多了, 經受了一些考驗, 可以嘗試小流量上線觀察

TODO redis 內存碎片整理實現


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM