Redis3.X內存佔用飆升排查

 1、現象:

redis-cluster某個分片內存飆升,明顯比其餘分片高不少,並且持續增加。而且主從的內存使用量並不一致。mysql

2、分析可能緣由:

一、redis-cluster的bug (這個應該不存在)redis

二、客戶端的hash(key)有問題,形成分配不均。(redis使用的是crc16, 不會出現這麼不均的狀況)sql

三、存在個別大的key-value: 例如一個包含了幾百萬數據set數據結構(這個有可能)服務器

四、主從複製出現了問題。數據結構

五、其餘緣由運維

3、調查緣由:

一、經查詢,上述1-4都不存在學習

二、觀察info信息,有一點引發了懷疑: client_longes_output_list有些異常。lua

三、因而理解想到服務端和客戶端交互時,分別爲每一個客戶端設置了輸入緩衝區和輸出緩衝區,這部分若是很大的話也會佔用Redis服務器的內存。spa

從上面的client_longest_output_list看,應該是輸出緩衝區佔用內存較大,也就是有大量的數據從Redis服務器向某些客戶端輸出。3d

因而使用client list命令(相似於mysql processlist) redis-cli -h host -p port client list | grep -v "omem=0",來查詢輸出緩衝區不爲0的客戶端鏈接,因而查詢到禍首monitor,因而豁然開朗.

monitor的模型是這樣的,它會將全部在Redis服務器執行的命令進行輸出,一般來說Redis服務器的QPS是很高的,也就是若是執行了monitor命令,Redis服務器在Monitor這個客戶端的輸出緩衝區又會有大量「存貨」,也就佔用了大量Redis內存。

4、緊急處理和解決方法

進行主從切換(主從內存使用量不一致),也就是redis-cluster的fail-over操做,繼續觀察新的Master是否有異常,經過觀察未出現異常。

查找到真正的緣由後,也就是monitor,關閉掉monitor命令的進程後,內存很快就降下來了。

5、 預防辦法:

5.1  爲何會有monitor這個命令發生,我想緣由有兩個:

一、工程師想看看究竟有哪些命令在執行,就用了monitor

二、工程師對於redis學習的目的,由於進行了redis的託管,工程師只要會用redis就能夠了,可是做爲技術人員都有學習的好奇心和慾望。

5.2  預防方法:

一、對工程師培訓,講一講redis使用過程當中的坑和禁忌

二、對redis雲進行介紹,甚至可讓有興趣的同窗參與進來

三、針對client作限制,可是官方也不建議這麼作,官方的默認配置中對於輸出緩衝區沒有限制。

client-output-buffer-limit normal 0 0 0

四、密碼:redis的密碼功能較弱,同時多了一次IO

五、修改客戶端源代碼,禁止掉一些危險的命令(shutdown, flushall, monitor, keys *),固然仍是能夠經過redis-cli來完成

六、添加command-rename配置,將一些危險的命令(flushall, monitor, keys * , flushdb)作rename,若是有須要的話,找到redis的運維人員處理

rename-command FLUSHALL "隨機數"  
rename-command FLUSHDB "隨機數"  
rename-command KEYS "隨機數"

6、模擬實驗:

6.1  開啓一個空的Redis(最簡,直接redis-server)

初始化狀態以下:

# Memory  
used_memory:815072  
used_memory_human:795.97K  
used_memory_rss:7946240  
used_memory_peak:815912  
used_memory_peak_human:796.79K  
used_memory_lua:36864  
mem_fragmentation_ratio:9.75  
mem_allocator:jemalloc-3.6.0  

# Clients  
connected_clients:1  
client_longest_output_list:0  
client_biggest_input_buf:0  
blocked_clients:0

6.2  開啓一個monitor:

redis-cli -h 127.0.0.1 -p 6379 monitor

6.3  使用redis-benchmark:

redis-benchmark -h 127.0.0.1 -p 6379 -c 500 -n 200000

6.4  觀察

1)info memory:內存一直增長,直到benchmark結束,monitor輸出完畢,可是used_memory_peak_human(歷史峯值)依然很高--觀察附件中日誌

2)info clients: client_longest_output_list: 一直在增長,直到benchmark結束,monitor輸出完畢,才變爲0--觀察附件中日誌

3)redis-cli -h host -p port client list | grep "monitor" omem一直很高,直到benchmark結束,monitor輸出完畢,才變爲0--觀察附件中日誌

監控腳本:

while [ 1 == 1 ]  
do  
now=$(date "+%Y-%m-%d_%H:%M:%S")  
echo "=========================${now}==============================="  
echo " #Client-Monitor"  
redis-cli -h 127.0.0.1 -p 6379 client list | grep monitor  
redis-cli -h 127.0.0.1 -p 6379 info clients  
redis-cli -h 127.0.0.1 -p 6379 info memory  
#休息100毫秒  
usleep 100000  
done
相關文章
相關標籤/搜索