下面讓我們一起進入現(xiàn)場,來逐步發(fā)現(xiàn)其中的原因。
首先,還是運行gdb 命令,gdb wbxgs core.5797,來看看現(xiàn)場。
[root@hfgs126 bin]# gdb wbxgs_crash core.5797
GNU gdb Red Hat Linux (6.3.0.0-1.132.EL4rh)
……
#0 0x00000038e8d70540 in strlen () from /lib64/tls/libc.so.6
(gdb) bt
#0 0x00000038e8d70540 in strlen () from /lib64/tls/libc.so.6
#1 0x000000000057cfc0 in T120_Trace::Text_Formator::advance (this=0x7e800a70, lpsz=0x1 <Address 0x1 out of bounds>)
at ./t120trace.cpp:1464
#2 0x000000000057ceb1 in T120_Trace::Text_Formator::operator<< (this=0x7e800a70, lpsz=0x1 <Address 0x1 out of bounds>)
at ./t120trace.cpp:1411
#3 0x0000000000407927 in ~func_tracer (this=0x7e804bd0) at ../h/t120trace.h:381
#4 0x00000000004432fd in CGSSocketServer::readHeader (this=0x8e4130, socketfd=1088,
buf=0x7e806cc0 "GET /detectService?cmd=selfcheck HTTP/1.1/r/nConnection: Close/r/nHost: 10.224.122.94/r/n/r/n", bufsize=1024)
at mgr/gssocketserver.cpp:337
#5 0x0000000000443981 in CGSSocketServer::handle (this=0x8e4130, socketfd=1088, strRet=@0x7e807190) at mgr/gssocketserver.cpp:424
#6 0x0000000000442f5e in CGSSocketServer::readThread (pArg=0x9ae9c0) at mgr/gssocketserver.cpp:304
#7 0x00000038e980610a in start_thread () from /lib64/tls/libpthread.so.0
#8 0x00000038e8dc68b3 in clone () from /lib64/tls/libc.so.6
#9 0x0000000000000000 in ?? ()
通過這個調(diào)用棧,可以看出,程序crash在打log的時候。雖然遇到過類似的crash,但是,當時的原因是有死循環(huán),通過review code,沒有發(fā)現(xiàn)死循環(huán)。但是當前的調(diào)用棧對于分析Crash的原因是一點用也沒有,如果分析具體的原因呢?會不會是其他得線程出現(xiàn)錯誤導(dǎo)致程序Crash在這個線程呢?為了找到深一層的原因,嘗試著通過GDB的一些關(guān)于線程的命令,來看看其他的線程是否有問題。于是,使用info threads,查看了一下當時線程的情況。
(gdb) info threads
21 process 5797 0x00000038e8d7186d in memset () from /lib64/tls/libc.so.6
20 process 5839 0x00000038e8dc6c8c in epoll_wait () from /lib64/tls/libc.so.6
19 process 5842 0x00000038e8d8f7d5 in __nanosleep_nocancel () from /lib64/tls/libc.so.6
18 process 5845 0x00000038e8d8f7d5 in __nanosleep_nocancel () from /lib64/tls/libc.so.6
17 process 5846 0x00000038e980a66f in sem_wait () from /lib64/tls/libpthread.so.0
16 process 5847 0x00000038e980a66f in sem_wait () from /lib64/tls/libpthread.so.0
15 process 5848 0x00000038e980a66f in sem_wait () from /lib64/tls/libpthread.so.0
14 process 5849 0x00000038e980a66f in sem_wait () from /lib64/tls/libpthread.so.0
13 process 5850 0x00000038e980a66f in sem_wait () from /lib64/tls/libpthread.so.0
12 process 5852 0x00000038e8dbf946 in __select_nocancel () from /lib64/tls/libc.so.6
11 process 5854 0x00000038e980a66f in sem_wait () from /lib64/tls/libpthread.so.0
10 process 5856 0x00000038e980a66f in sem_wait () from /lib64/tls/libpthread.so.0
9 process 5857 0x00000038e980a66f in sem_wait () from /lib64/tls/libpthread.so.0
8 process 5858 0x00000038e980a66f in sem_wait () from /lib64/tls/libpthread.so.0
7 process 5859 0x00000038e8d8f7d5 in __nanosleep_nocancel () from /lib64/tls/libc.so.6
6 process 5861 0x00000038e980a66f in sem_wait () from /lib64/tls/libpthread.so.0
5 process 5862 0x00000038e980a66f in sem_wait () from /lib64/tls/libpthread.so.0
4 process 5863 0x00000038e8d8f7d5 in __nanosleep_nocancel () from /lib64/tls/libc.so.6
3 process 5864 0x00000038e8d8f7d5 in __nanosleep_nocancel () from /lib64/tls/libc.so.6
2 process 5883 0x00000038e8d8f7d5 in __nanosleep_nocancel () from /lib64/tls/libc.so.6
* 1 process 5853 0x00000038e8d70540 in strlen () from /lib64/tls/libc.so.6
對于線程如果停止在sleep或者wait的情況,都是正常的,但是我們看到thread 21有些異常,程序停止在memset,不管是否有問題,都需要看看這樣的線程具體有沒有出錯。
于是通過命令thread 21,進入到thread 21的調(diào)用棧。
(gdb) thread 21
[Switching to thread 21 (process 5797)]#0 0x00000038e8d7186d in memset () from /lib64/tls/libc.so.6
(gdb) bt
#0 0x00000038e8d7186d in memset () from /lib64/tls/libc.so.6
#1 0x000000000049da0d in CGSPduFactory::streamStringFrom (is=@0x7fff9b436360, strFrom=@0x2aaaec979760) at common/pdu/gspdu.cpp:422
#2 0x00000000004d1f25 in CGSOthShardUserRspPdu::streamFrom (this=0x2aaaec951650, is=@0x7fff9b436360) at common/pdu/pdugs.cpp:2707
#3 0x000000000049cb2d in CGSPduFactory::derivePdu (is=@0x7fff9b436360, ulPDULen=30506) at common/pdu/gspdu.cpp:79
#4 0x000000000049c78e in CGSPduFactory::streamPduFrom (pDataPacket=0x2aaaeca31d70) at common/pdu/gspdu.cpp:35
#5 0x0000000000449681 in CGSWDMSManager::on_wdms_message_indication (this=0x8e3680, msg=0x2aaae9894360)
at mgr/gswdmsmanager.cpp:344
……
#18 0x0000000000407733 in main (argc=1, argv=0x7fff9b44ac98) at gsmain.cpp:118
(gdb) f 3
#3 0x000000000049cb2d in CGSPduFactory::derivePdu (is=@0x7fff9b436360, ulPDULen=30506) at common/pdu/gspdu.cpp:79
79 common/pdu/gspdu.cpp: No such file or directory.
in common/pdu/gspdu.cpp
使用命令 i locals,打印所有的變量的值。
(gdb) i locals
pPdu = (CBasePdu *) 0x2aaaec951650
pPduHeader = (CPduHeader *) 0x2aaaea1c4190
ulPduType = 50
到現(xiàn)在還沒有看出有什么明顯的異常,然后再把PDU的頭打印出來如下:
(gdb) p *pPduHeader
$1 = {m_ulHeadLen = 61, m_ulVersion = 2080000, m_ulPduType = 50, m_ulSrcSvrType = WEBEX_CONNECT_GS, m_strSrcSvrAddr = {
static npos = 18446744073709551615,
_M_dataplus = {<std::allocator<char>> = {<__gnu_cxx::new_allocator<char>> = {<No data fields>}, <No data fields>},
_M_p = 0x2aaaeca52a68 "10.224.95.109:9900"}}, m_strSubject = {static npos = 18446744073709551615,
_M_dataplus = {<std::allocator<char>> = {<__gnu_cxx::new_allocator<char>> = {<No data fields>}, <No data fields>},
_M_p = 0x2aaaec929b28 "qawin.qazone.GS"}}, m_ulSequence = 0}
從藍色的字的部分可以看出,這個PDU是從10.224.95.109這臺server上發(fā)過來的。
當時QA測試的環(huán)境,都是10.224.122開頭的IP的server,怎么會有這個IP的PDU,于是,詢問QA,發(fā)現(xiàn)10.224.95.109這個server是其他DataCenter的Server,而且還是老的版本,由于當前測試環(huán)境的版本刪除了兩個PDU,同時又增加了四個PDU,導(dǎo)致了老的PDU發(fā)來的時候,新的版本的把它當作新的PUD解析,從而導(dǎo)致不能正確解析,最終導(dǎo)致了解析出來的長度不對??梢酝ㄟ^f 1命令進入第一級調(diào)用棧查看所有的局部變量。
(gdb) f 1
#1 0x000000000049da0d in CGSPduFactory::streamStringFrom (is=@0x7fff9b436360, strFrom=@0x2aaaec979760) at common/pdu/gspdu.cpp:422
422 in common/pdu/gspdu.cpp
(gdb) i locals
strTmp = 0x2aaaf1c00010 ""
iRet = 0
ulLen = 1179995975
可以看出解析出來的長度是一個很大的值1179995975,而線程21正式停止在分配內(nèi)存之后,使用memset時,停止在那里。從Log中也可以看到,thread 21也一致阻塞在這里,而且沒有再繼續(xù)運行。
由于當時有兩臺server crash,通過查看另外一臺server的core file,發(fā)現(xiàn)另外一臺server也是和本臺server一樣的調(diào)用棧。在QA更新了10.224.95.109的版本后,crash沒有再出現(xiàn)。
通過這個實例,可以看出,當server出現(xiàn)crash的時候,雖然當前的調(diào)用棧可能沒有什么價值,但是,通過分析所有線程的調(diào)用棧,還是可能分析出蛛絲馬跡的,從而對于解決Crash的問題帶來幫助。
通過這個問題可以得到一個教訓(xùn),在修改Server之間的接口時,一定要考慮到和老版本的兼容問題,即使這個PDU可能永遠也不會使用,仍然需要保留,因為Production上,是先上GSB,然后再上Primary,肯定會存在兩個版本同時運行的情況。如果出現(xiàn)刪除或者改變PDU順序的情況,可能會導(dǎo)致整個系統(tǒng)不能工作。
希望本文章,對解決Crash問題和避免類似的Crash問題有一定的借鑒作用。
聯(lián)系客服