天天看點

Redis3.X記憶體占用飙升排查 一、現象:二、分析可能原因:三、調查原因:四、緊急處理和解決方法五、 預防辦法:六、模拟實驗:

 一、現象:

redis-cluster某個分片記憶體飙升,明顯比其他分片高很多,而且持續增長。并且主從的記憶體使用量并不一緻。

Redis3.X記憶體占用飙升排查 一、現象:二、分析可能原因:三、調查原因:四、緊急處理和解決方法五、 預防辦法:六、模拟實驗:

二、分析可能原因:

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

2、用戶端的hash(key)有問題,造成配置設定不均。(redis使用的是crc16, 不會出現這麼不均的情況)

3、存在個别大的key-value: 例如一個包含了幾百萬資料set資料結構(這個有可能)

4、主從複制出現了問題。

5、其他原因

三、調查原因:

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

2、觀察info資訊,有一點引起了懷疑: client_longes_output_list有些異常。

Redis3.X記憶體占用飙升排查 一、現象:二、分析可能原因:三、調查原因:四、緊急處理和解決方法五、 預防辦法:六、模拟實驗:

3、于是了解想到服務端和用戶端互動時,分别為每個用戶端設定了輸入緩沖區和輸出緩沖區,這部分如果很大的話也會占用Redis伺服器的記憶體。

Redis3.X記憶體占用飙升排查 一、現象:二、分析可能原因:三、調查原因:四、緊急處理和解決方法五、 預防辦法:六、模拟實驗:

從上面的client_longest_output_list看,應該是輸出緩沖區占用記憶體較大,也就是有大量的資料從Redis伺服器向某些用戶端輸出。

于是使用client list指令(類似于mysql processlist) redis-cli -h host -p port client list | grep -v "omem=0",來查詢輸出緩沖區不為0的用戶端連接配接,于是查詢到禍首monitor,于是豁然開朗.

Redis3.X記憶體占用飙升排查 一、現象:二、分析可能原因:三、調查原因:四、緊急處理和解決方法五、 預防辦法:六、模拟實驗:

monitor的模型是這樣的,它會将所有在Redis伺服器執行的指令進行輸出,通常來講Redis伺服器的QPS是很高的,也就是如果執行了monitor指令,Redis伺服器在Monitor這個用戶端的輸出緩沖區又會有大量“存貨”,也就占用了大量Redis記憶體。

Redis3.X記憶體占用飙升排查 一、現象:二、分析可能原因:三、調查原因:四、緊急處理和解決方法五、 預防辦法:六、模拟實驗:

四、緊急處理和解決方法

進行主從切換(主從記憶體使用量不一緻),也就是redis-cluster的fail-over操作,繼續觀察新的Master是否有異常,通過觀察未出現異常。

查找到真正的原因後,也就是monitor,關閉掉monitor指令的程序後,記憶體很快就降下來了。

五、 預防辦法:

5.1  為什麼會有monitor這個指令發生,我想原因有兩個:

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

2、工程師對于redis學習的目的,因為進行了redis的托管,工程師隻要會用redis就可以了,但是作為技術人員都有學習的好奇心和欲望。

5.2  預防方法:

1、對工程師教育訓練,講一講redis使用過程中的坑和禁忌

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

3、針對client做限制,但是官方也不建議這麼做,官方的預設配置中對于輸出緩沖區沒有限制。

client-output-buffer-limit normal 0 0 0 
           

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

5、修改用戶端源代碼,禁止掉一些危險的指令(shutdown, flushall, monitor, keys *),當然還是可以通過redis-cli來完成

6、添加command-rename配置,将一些危險的指令(flushall, monitor, keys * , flushdb)做rename,如果有需要的話,找到redis的運維人員處理

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

六、模拟實驗:

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  
           

繼續閱讀