美團在Redis上踩過的一些坑-3.redis內存占用飆升(轉載)
阿新 • • 發佈:2017-09-09
car shu idl 運維人員 監控 images 我想 依然 服務器
一、現象: redis-cluster某個分片內存飆升,明顯比其他分片高很多,而且持續增長。並且主從的內存使用量並不一致。 二、分析可能原因: 1. redis-cluster的bug (這個應該不存在) 2. 客戶端的hash(key)有問題,造成分配不均。(redis使用的是crc16, 不會出現這麽不均的情況) 3. 存在個別大的key-value: 例如一個包含了幾百萬數據set數據結構(這個有可能) 4. 主從復制出現了問題。 5. 其他原因 三、調查原因: 1. 經查詢,上述1-4都不存在 2. 觀察info信息,有一點引起了懷疑: client_longes_output_list有些異常。
3. 於是理解想到服務端和客戶端交互時,分別為每個客戶端設置了輸入緩沖區和輸出緩沖區,這部分如果很大的話也會占用Redis服務器的內存。
從上面的client_longest_output_list看,應該是輸出緩沖區占用內存較大,也就是有大量的數據從Redis服務器向某些客戶端輸出。
於是使用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內存。
四、緊急處理和解決方法
進行主從切換(主從內存使用量不一致),也就是redis-cluster的fail-over操作,繼續觀察新的Master是否有異常,通過觀察未出現異常。
查找到真正的原因後,也就是monitor,關閉掉monitor命令的進程後,內存很快就降下來了。
五、 預防辦法:
1. 為什麽會有monitor這個命令發生,我想原因有兩個:
(1). 工程師想看看究竟有哪些命令在執行,就用了monitor
(2). 工程師對於redis學習的目的,因為進行了redis的托管,工程師只要會用redis就可以了,但是作為技術人員都有學習的好奇心和欲望。
2. 預防方法:
(1) 對工程師培訓,講一講redis使用過程中的坑和禁忌
(2) 對redis雲進行介紹,甚至可以讓有興趣的同學參與進來
(3) 針對client做限制,但是官方也不建議這麽做,官方的默認配置中對於輸出緩沖區沒有限制。
Java代碼
一、現象: redis-cluster某個分片內存飆升,明顯比其他分片高很多,而且持續增長。並且主從的內存使用量並不一致。 二、分析可能原因: 1. redis-cluster的bug (這個應該不存在) 2. 客戶端的hash(key)有問題,造成分配不均。(redis使用的是crc16, 不會出現這麽不均的情況) 3. 存在個別大的key-value: 例如一個包含了幾百萬數據set數據結構(這個有可能) 4. 主從復制出現了問題。 5. 其他原因 三、調查原因: 1. 經查詢,上述1-4都不存在 2. 觀察info信息,有一點引起了懷疑: client_longes_output_list有些異常。
- client-output-buffer-limit normal 0 0 0
- rename-command FLUSHALL "隨機數"
- rename-command FLUSHDB "隨機數"
- rename-command KEYS "隨機數"
- 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
- redis-cli -h 127.0.0.1 -p 6379 monitor
- redis-benchmark -h 127.0.0.1 -p 6379 -c 500 -n 200000
- 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
- =========================2015-11-06_10:07:16===============================
- #Client-Monitor
- id=7 addr=127.0.0.1:56358 fd=6 name= age=91 idle=0 flags=O db=0 sub=0 psub=0 multi=-1 qbuf=0 qbuf-free=0 obl=0 oll=4869 omem=133081288 events=rw cmd=monitor
- # Clients
- connected_clients:502
- client_longest_output_list:4869
- client_biggest_input_buf:0
- blocked_clients:0
- # Memory
- used_memory:174411224
- used_memory_human:166.33M
- used_memory_rss:161513472
- used_memory_peak:176974792
- used_memory_peak_human:168.78M
- used_memory_lua:36864
- mem_fragmentation_ratio:0.93
- mem_allocator:jemalloc-3.6.0
美團在Redis上踩過的一些坑-3.redis內存占用飆升(轉載)