Redis崩潰調試
背景
Redis的代碼質量一直被業內人士稱讚,在極高的業務壓力下也能有很好的穩定性。但是極端情況下,Redis也是有可能會Crash的。有時候因為種種原因,係統配置問題,磁盤空間寫滿了,進程權限不夠等等,我們可能不會運氣那麼好,有一個core
文件可以拿去調試。這個時候,Redis提供了幾種異常崩潰情況下的Crash Report
,很多時候我們基於Crash Report,再加上一定的分析就可以直接定位問題了。
Crash Report
在異常崩潰時,Redis會通過設置的signal handler
來生成Crash Report,目前Redis為生成Crash Report捕獲的異常信號主要有以下幾種:
- SIGSEGV
- SIGFPE
- SIGILL
- SIGBUS
這4種信號應該能包含大部分程序異常崩潰情況了,最常見的就是SIGSEGV段錯誤了,除0異常SIGFPE有時候也會遇到。
當Redis收到上麵4種信號之一時,會在設置的sigsegvHandler()
函數中生成Crash Report,如下,
=== REDIS BUG REPORT START: Cut & paste starting from here ===
[19179] 12 Apr 18:47:42.599 # Redis 2.8.19 crashed by signal: 11
[19179] 12 Apr 18:47:42.599 # Failed assertion: <no assertion failed> (<no file>:0)
[19179] 12 Apr 18:47:42.599 # --- STACK TRACE
/home/dejun.xdj/kvs-kernel/src/libredis-server.so(logStackTrace+0x4a)[0x7f5be2d6895a]
/home/dejun.xdj/kvs-kernel/src/libredis-server.so(debugCommand+0x1b0)[0x7f5be2d69ad0]
/lib64/libpthread.so.0(+0xf500)[0x7f5be3c1a500]
/home/dejun.xdj/kvs-kernel/src/libredis-server.so(debugCommand+0x1b0)[0x7f5be2d69ad0]
/home/dejun.xdj/kvs-kernel/src/libredis-server.so(call+0x8a)[0x7f5be2d2f12a]
/home/dejun.xdj/kvs-kernel/src/libredis-server.so(processCommand+0x5dd)[0x7f5be2d3017d]
/home/dejun.xdj/kvs-kernel/src/libredis-server.so(processInputBuffer+0x4d)[0x7f5be2d3b86d]
/home/dejun.xdj/kvs-kernel/src/libredis-server.so(readQueryFromClient+0xf0)[0x7f5be2d3cb70]
/home/dejun.xdj/kvs-kernel/src/libredis-server.so(aeProcessEvents+0x13d)[0x7f5be2d2804d]
/home/dejun.xdj/kvs-kernel/src/libredis-server.so(aeMain+0x2b)[0x7f5be2d2833b]
/home/dejun.xdj/kvs-kernel/src/libredis-server.so(runRedis+0x4f)[0x7f5be2d31eaf]
/home/dejun.xdj/kvs-kernel/src/redis-server /home/dejun.xdj/local/redis/conf/redis_7071.conf *:1071(main+0x180)[0x405db0]
/lib64/libc.so.6(__libc_start_main+0xfd)[0x3d4ac1ecdd]
/home/dejun.xdj/kvs-kernel/src/redis-server /home/dejun.xdj/local/redis/conf/redis_7071.conf *:1071[0x4055e9]
[19179] 12 Apr 18:47:42.599 # --- INFO OUTPUT
...
...
[19179] 12 Apr 18:47:42.599 # --- CLIENT LIST OUTPUT
[19179] 12 Apr 18:47:42.599 # id=2 addr=127.0.0.1:30494 fd=5 name= age=0 idle=0 flags=N db=0 sub=0 psub=0 multi=-1 qbuf=0 qbuf-free=32768 obl=0 oll=0 omem=0 events=r cmd=debug read=0 write=0 type=admin next_opid=-1
[19179] 12 Apr 18:47:42.599 # --- CURRENT CLIENT INFO
[19179] 12 Apr 18:47:42.599 # client: id=2 addr=127.0.0.1:30494 fd=5 name= age=0 idle=0 flags=N db=0 sub=0 psub=0 multi=-1 qbuf=0 qbuf-free=32768 obl=0 oll=0 omem=0 events=r cmd=debug read=0 write=0 type=admin next_opid=-1
[19179] 12 Apr 18:47:42.600 # argv[0]: 'debug'
[19179] 12 Apr 18:47:42.600 # argv[1]: 'segfault'
[19179] 12 Apr 18:47:42.600 # --- REGISTERS
...
...
=== REDIS BUG REPORT END. Make sure to include from START to END. ===
Please report the crash by opening an issue on github:
https://github.com/antirez/redis/issues
Suspect RAM error? Use redis-server --test-memory to verify it.
Crash Report主要包括4部分,
- STACK TRACE,崩潰時的調用棧信息
- INFO OUTPUT,崩潰時的Redis info命令輸出
- CLIENT OUTPUT,包括崩潰時的CURRENT CLIENT,這個可以看到崩潰時客戶端執行的命令
- REGISTERS,寄存器信息
其中對於調試最有幫助的就是STACK TRACE
信息了,我們直接以上麵的Crash Report來說明一下如何調試。
調試
Redis提供了debug segfault
命令用於調試,我們直接給Redis發送這個命令,就可以在日誌中生成類似於上麵的崩潰報告(請不要在生產環境使用這個命令!!!)。
實際調試之前先說明一下,如果編譯時沒有加上-g
選項,可執行文件中沒有調試符號信息,是無法進行後麵的調試的,考慮到性能的影響很小,Redis默認編譯是帶有-g選項的。
上麵的STACK TRACE信息直接告訴我們了,出core的點在libredis-server.so
中,簡單分析可以知道是在執行debugCommand
時出現段錯誤,函數後麵的+
號帶的地址是函數內的代碼偏移,我們隻要知道函數的起始地址就可以獲取出core的函數內代碼地址了,進而可以通過addr2line
獲取地址對應的具體的源文件名和行號。
通過nm工具獲取函數起始地址,
$nm -l /home/dejun.xdj/kvs-kernel/src/libredis-server.so | grep debugCommand
000000000006d920 T debugCommand /home/dejun.xdj/kvs-kernel/src/debug.c:255
000000000007f3f0 T pfdebugCommand /home/dejun.xdj/kvs-kernel/src/hyperloglog.c:1455
我們可以看到debugCommand的起始地址是0x6d920
(十六進製),加上偏移0x1b0
,可以知道出core的具體地址是0x6dad0
,那麼我們就可以很方便的獲取到具體的行號了,
$addr2line -e /home/dejun.xdj/kvs-kernel/src/libredis-server.so 0x6dad0
/home/dejun.xdj/kvs-kernel/src/debug.c:304
參考源文件我們可以發現debug.c的304行存在非法地址訪問,
*((char*)-1) = 'x';
總結
以上隻是為了說明調試流程,舉的一個簡單例子,有時候定位了出core的點,可能還需要更為細致的分析,結合info輸出和client輸出。在沒有core文件的場景下,Crash Report確實能夠提供很大的幫助,上麵的流程,有興趣的同學可以直接做成一個腳本,直接分析日誌,自動化的獲取出core點的信息。
參考:https://antirez.com/news/43
誠聘英才:阿裏雲-技術專家-KVstore
最後更新:2017-04-13 16:00:23