Redis進程異常退出排查

Redis進程異常退出排查

一、排查思路

1. 是否因爲系統內存不足被oom killer殺掉;

如果是oom killer殺掉的話,一般會在/var/log/*留下日誌,dmesg也應該能查到,可以使用命令搜索:

dmesg | egrep -i 'killed process'
grep oom /var/log/*
grep total_vm /var/log/*

如果確實是由於內存不足被oom killer殺掉,可以考慮:

  • 加大系統內存;
  • 修改redis.conf配置,設置合理的maxmemory,保證機器有20%~30%的閒置內存,並使用適當的回收策略;
maxmemory 512mb
maxmemory-policy volatile-lru
  • 降低redis進程的oom adj分數;

“OOM killer會在可用內存不足時選擇性的殺掉用戶進程,它的運行規則是怎樣的,會選擇哪些用戶進程“下手”呢?OOM killer進程會爲每個用戶進程設置一個權值,這個權值越高,被“下手”的概率就越高,反之概率越低。每個進程的權值存放在/proc/{progress_id}/oom_score中,這個值是受/proc/{progress_id}/oom_adj的控制,oom_adj在不同的Linux版本的最小值不同,可以參考Linux源碼中oom.h(從-15到-17)。當oom_adj設置爲最小值時,該進程將不會被OOM killer殺掉。”

設置方法如下:

echo -17 > /proc/${process_id}/oom_adj
  • 優化redis的內存使用與設置;
    詳情參考文末的相關文章鏈接

2. 是否被人爲kill掉

  • 如果是人爲kill進程,可以搜索last和history的記錄,查看是什麼登陸用戶在什麼時間殺掉的;
  • 如果系統有安裝audit,也可以使用ausearch搜索命令記錄:
ausearch -sc kill

3. 是否因爲redis-cli發送了shutdown命令導致

如果是cli發送的shutdown命令導致redis退出,redis本身的log會有如下記錄:

3803:S 11 Oct 18:12:51.251 # User requested shutdown...
3803:S 11 Oct 18:12:51.251 * Removing the pid file.
3803:S 11 Oct 18:12:51.252 # Redis is now ready to exit, bye bye...

如果還沒打開redis log,需要在redis.conf中指定路徑然後重啓:

dir "/opt/redis-4.0.9/redis-cluster/7000"

4. 是否redis本身的bug導致崩潰

  • 設置系統ulimit,在進程崩潰時候生成core dump:
ulimit -c unlimited

修改/etc/sysctl.conf文件,加入如下配置指定core dump文件生成的名稱和路徑:

kernel.core_uses_pid = 1
kernel.core_pattern = /var/core/core_%e_%p

注意不同linux發行版可能設置的方式略有不同。

  • 使用strace命令跟蹤進程行爲:
screen -S redis_trace_7000
strace -T -tt -e trace=all -p `ps -ef|grep redis|grep 7000|grep -v -i screen|grep -v grep|awk '{split($0,a);print a[2]}'`

然後ctrl-a d退出screen

  • 使用gdb attach到redis進程

同樣建議使用獨立的screen執行gdb,另外,gdb需要使用ptrace,如果發現ptrace: Operation not permitted的報錯,需要關閉其他已經使用ptrace命令的進程,例如strace命令。

gdb /usr/local/bin/redis-server 58414
(gdb) continue

使用redis-cli連上server,發送debug segfault指令可以使redis server崩潰,這時候可以:
使用bt查看棧信息

(gdb) bt
#0  debugCommand (c=0x7ffc32005000) at debug.c:220
#1  0x000000010d246d63 in call (c=0x7ffc32005000) at redis.c:1163
#2  0x000000010d247290 in processCommand (c=0x7ffc32005000) at redis.c:1305
#3  0x000000010d251660 in processInputBuffer (c=0x7ffc32005000) at networking.c:959
#4  0x000000010d251872 in readQueryFromClient (el=0x0, fd=5, privdata=0x7fff76f1c0b0, mask=220924512) at networking.c:1021
#5  0x000000010d243523 in aeProcessEvents (eventLoop=0x7fff6ce408d0, flags=220829559) at ae.c:352
#6  0x000000010d24373b in aeMain (eventLoop=0x10d429ef0) at ae.c:397
......

使用info registers查看寄存器信息

(gdb) info registers
rax            0x0  0
rbx            0x7ffc32005000   140721147367424
rcx            0x10d2b0a60  4515891808
rdx            0x7fff76f1c0b0   140735188943024
rsi            0x10d299777  4515796855
rdi            0x0  0
rbp            0x7fff6ce40730   0x7fff6ce40730
rsp            0x7fff6ce40650   0x7fff6ce40650
r8             0x4f26b3f7   1327936503
r9             0x7fff6ce40718   140735020271384
r10            0x81 129
......

最後,使用gcore產生core dump文件

(gdb) gcore
Saved corefile core.58414

二、內存使用優化

  1. 縮減鍵值對象
    在條件允許的情況下建議字符串長度控制在39字節以內,減少創建redisObject內存分配次數;
    縮減鍵(key)和值(value)的長度;
    key長度:如在設計鍵時,在完整描述業務情況下,鍵值越短越好。
    value長度:值對象縮減比較複雜,常見需求是把業務對象序列化成二進制數組放入Redis。首先應該在業務上精簡業務對象,去掉不必要的屬性避免存儲無效數據。其次在序列化工具選擇上,應該選擇更高效的序列化工具來降低字節數組大小。在內存緊張的情況下,可以使用通用壓縮算法壓縮json,xml後再存入Redis,從而降低內存佔用,例如使用GZIP壓縮後的json可降低約60%的空間。
  2. 共享對象池
    使用共享對象池。整數對象池在Redis中通過變量REDIS_SHARED_INTEGERS定義,不能通過配置修改。可以通過object refcount 命令查看對象引用數驗證是否啓用整數對象池技術。使用共享對象池後,相同的數據內存使用降低30%以上。可見當數據大量使用[0-9999]的整數時,共享對象池可以節約大量內存。注意,當設置maxmemory並啓用LRU相關淘汰策略如:volatile-lru,allkeys-lru時,Redis禁止使用共享對象池。
  3. 字符串優化
    儘量減少字符串頻繁修改操作如append,setrange, 改爲直接使用set修改字符串,降低預分配帶來的內存浪費和內存碎片化。
  4. 編碼優化
    針對性能要求較高的場景使用ziplist,建議長度不要超過1000,每個元素大小控制在512字節以內。
    當集合只包含整數且長度不超過set-max-intset-entries配置時使用intset編碼。
    對於大量小對象的存儲場景,非常適合使用ziplist編碼的hash類型控制鍵的規模來降低內存。

三、參考資料

設置Redis最大佔用內存
Redis的內存優化
Redis debugging guide
Playing with ptrace, Part I
神器strace, ltrace
How to disable Redis RDB?
Redis研究(十九)—命令屬性
Virtual memory settings in Linux - The Problem with Overcommit
What is the logic behind killing processes during an Out of Memory situation?
How to reproduce a condition which invokes the OOM-Killer ?

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章