快速診斷Linux服務(wù)器故障的三大法寶
原創(chuàng)【51CTO精選譯文】作為系統(tǒng)管理員的你,是否以為一切盡在你的掌握和控制之中呢?但現(xiàn)實(shí)往往事與愿違,你認(rèn)為那些正在運(yùn)行和收集數(shù)據(jù)的進(jìn)程卻已經(jīng)有兩個(gè)小時(shí)沒有向你匯報(bào)任何消息了,也許是你的監(jiān)控客戶端失去了響應(yīng),也許是服務(wù)器端出了問題,總之你不能第一時(shí)間知道問題出在哪里,而最要命的是這種情況每隔幾天就會(huì)重復(fù)一次,心態(tài)再好的人遇到這種情況也會(huì)火冒三丈。那么如何找出運(yùn)行中的進(jìn)程究竟發(fā)生了什么呢?其實(shí)不用高深知識,也不用高級的監(jiān)控套件,用系統(tǒng)自帶的一些工具就夠了,下面一起來看看如何利用Linux系統(tǒng)自帶的一些工具診斷服務(wù)器故障吧。
Top和其它系統(tǒng)工具
要想知道進(jìn)程在運(yùn)行期間發(fā)生了什么,我們最好先獲得該進(jìn)程的ID,如果你知道被“卡住”或資源消耗不斷上升進(jìn)程的名稱,那反查該進(jìn)程的ID就好辦了,使用ps aux | grep processname命令即可,不知道進(jìn)程名稱也沒關(guān)系,我們還可以使用top來查看高CPU利用率或高內(nèi)存占有率的進(jìn)程。
Tasks: 114 total, 1 running, 113 sleeping, 0 stopped, 0 zombie Cpu(s): 1.2%us, 0.6%sy, 0.6%ni, 96.0%id, 1.6%wa, 0.0%hi, 0.0%si, 0.0%st Mem: 4053756k total, 1059196k used, 2994560k free, 305236k buffers Swap: 2249060k total, 0k used, 2249060k free, 465112k cached PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 3055 akkana 20 0 160m 39m 18m S 39 1.0 0:02.83 plugin-containe 2223 akkana 20 0 330m 107m 26m S 16 2.7 0:51.33 firefox-bin 65 root 20 0 0 0 0 S 2 0.0 0:00.34 kondemand/0 1586 root 20 0 71712 22m 8244 S 2 0.6 0:24.87 Xorg 1 root 20 0 2748 1612 1216 S 0 0.0 0:00.37 init 2 root 20 0 0 0 0 S 0 0.0 0:00.00 kthreadd 3 root RT 0 0 0 0 S 0 0.0 0:00.00 migration/0 ...and so on
默認(rèn)情況下,top命令的結(jié)果按“吃”CPU多少進(jìn)行倒序排列,在上面的例子中,F(xiàn)irefox卡住了,它正在運(yùn)行Flash,瀏覽器和它的輔助程序一起占用了45%的CPU時(shí)鐘周期,這還不算什么,如果你看到一個(gè)CPU利用率達(dá)到99%的進(jìn)程,那它一定有問題。
當(dāng)你發(fā)現(xiàn)有問題的進(jìn)程后,該如何了解它正在做什么呢?這個(gè)時(shí)候就要請出strace了。
strace
strace是一個(gè)很有用的程序,它可以顯示正在發(fā)生的系統(tǒng)調(diào)用,系統(tǒng)調(diào)用包括文件操作,如讀、寫和打開,超時(shí)設(shè)定和發(fā)送信號,網(wǎng)絡(luò)操作以及其它各種獲得或設(shè)置系統(tǒng)信息的操作,你可以閱讀man 2 intro查看概述,或man 2 syscalls查看所有可用系統(tǒng)調(diào)用的詳細(xì)列表。
這一切聽起來有點(diǎn)神秘,但有時(shí)看strace輸出可以準(zhǔn)確地知道一個(gè)程序?yàn)槭裁闯龉收狭?,也許是等待網(wǎng)絡(luò),也許是重復(fù)打開一個(gè)根本就不存在的文件等等。
你可以在strace下運(yùn)行一個(gè)程序,如strace firefox,但更多時(shí)候,你想連接到一個(gè)正在運(yùn)行的進(jìn)程,當(dāng)然沒問題,首先使用ps或top得到進(jìn)程ID,然后使用“strace –p 進(jìn)程id”即可。
假設(shè)我有一個(gè)程序看起來已經(jīng)掛了,top命令顯示它沒有使用任何CPU,但它確實(shí)已經(jīng)卡住,至少有半個(gè)小時(shí)沒有做任何事情了,我們使用strace –p來跟蹤一下。
$ strace -p 3672 Process 3672 attached - interrupt to quit recv(3,
strace就停在這里,光標(biāo)在中間那行閃動(dòng),這是怎么回事呢?
其實(shí)它在等待recv系統(tǒng)調(diào)用,按照Ctrl-C退出strace,然后使用apropos。
$ apropos recv recv (2) - receive a message from a socket recvfrom (2) - receive a message from a socket recvmsg (2) - receive a message from a socket
從上面的結(jié)果可以看出,進(jìn)程是在等待讀取網(wǎng)絡(luò)套接字中的內(nèi)容,顯然我們對進(jìn)程掛起有了進(jìn)一步了解。
如何模擬故障?
你在建立一個(gè)診斷工具庫時(shí),有時(shí)你可能希望有一個(gè)簡單辦法來體驗(yàn)它們,這時(shí)我們要模仿進(jìn)程掛起故障,如果你有一個(gè)Web服務(wù)器就好辦了,編寫一個(gè)腳本,內(nèi)容如下:
#! /usr/bin/env python import time print """Content-Type: text/html Hello, world. Now we'll hang for a bit ... """ for i in range(50) : # Don't run forever and clog up the server time.sleep(300) # sleep for 5 minutes print "<p>\nAnother line"
你可以使用wget,curl或自己編寫一個(gè)Python腳本測試它。
#!/usr/bin/env python import urllib2 response = urllib2.urlopen("http://example.com/testcgi/index.cgi")
當(dāng)然,如果你想要某個(gè)程序占用所有可用的CPU資源,只需要在腳本中添加下面的代碼:
while /bin/true; do echo x done
用其它語言也可以,只要達(dá)到這種目的即可。
如果用top和strace的幫助仍然不大,下面還有個(gè)最終法寶——#p#
使用gdb獲得堆棧跟蹤信息
好吧,我承認(rèn)即使知道了進(jìn)程ID和strace輸出結(jié)果,但幫助仍然不大,不用急,我還使出絕招呢,絕招就是使用gdb獲得堆棧跟蹤信息,堆棧跟蹤不僅會(huì)告訴你程序當(dāng)前正在做什么,有底層的信息(如等待網(wǎng)絡(luò)套接字),也有較高級別的信息(如正在執(zhí)行什么類型的網(wǎng)絡(luò)操作)。
和strace的使用方法一樣,gdb也使用-p加進(jìn)程id的命令格式,啟動(dòng)后你會(huì)獲得一個(gè)gdb提示符,輸入where就可以獲得一個(gè)堆棧跟蹤。下面是Firefox在運(yùn)行一些有問題的JavaScript代碼時(shí)的堆棧跟蹤信息。
#0 0x01ad9794 in gfxPangoFontGroup::GetFontAt (this=0xa74e8160, i=0) at gfxPangoFonts.cpp:1936 #1 0x01ad1c11 in GetFontOrGroup (this=0xa51466b4, aKey=0xbfab1e2c) at gfxTextRunWordCache.cpp:899 #2 TextRunWordCache::CacheHashEntry::KeyEquals (this=0xa51466b4, aKey=0xbfab1e2c) at gfxTextRunWordCache.cpp:910 #3 0x01a5cb74 in SearchTable (table=0xb45ce2d0, key=, keyHash=, op=PL_DHASH_ADD) at pldhash.c:472 #4 0x01a5cc50 in PL_DHashTableOperate (table=0xb45ce2d0, key=0xbfab1e2c, op=) at pldhash.c:661 #5 0x01ad2421 in nsTHashtable::PutEntry ( this=0xb45ce2c0, aTextRun=0xa7ee0ae0, aFirstFont=0xad613d30, aStart=8, aEnd=10, aHash=821, aDeferredWords=0x0) at ../../../dist/include/nsTHashtable.h:188 #6 TextRunWordCache::LookupWord (this=0xb45ce2c0, aTextRun=0xa7ee0ae0, aFirstFont=0xad613d30, aStart=8, aEnd=10, aHash=821, aDeferredWords=0x0) at gfxTextRunWordCache.cpp:358 ... etc.
即使你不熟悉Firefox源代碼也能從上面的堆棧跟蹤結(jié)果看出,它正在處理一些和字體有關(guān)的事情。
如果程序正在循環(huán),那么它可能一直在做相同的事情,當(dāng)你運(yùn)行g(shù)db –p時(shí),它會(huì)暫時(shí)停止程序以便你進(jìn)行檢查,在提示符后按下c就可以讓它繼續(xù)運(yùn)行,按下Ctrl-C會(huì)再次停止,再輸入一次where就會(huì)獲得第二個(gè)堆棧輸出。
(gdb) where #0 0xb686db07 in ?? () from /usr/lib/firefox-3.6.12/libmozjs.so #1 0xb684bec9 in ?? () from /usr/lib/firefox-3.6.12/libmozjs.so #2 0xb685cf66 in js_Invoke () from /usr/lib/firefox-3.6.12/libmozjs.so #3 0xb6b6231b in ?? () from /usr/lib/firefox-3.6.12/libxul.so
這一次結(jié)果不一樣了,它只暗示Firefox正在處理JavaScript(JS)和XUL相關(guān)的事情,反復(fù)停止又啟動(dòng)程序,你就會(huì)發(fā)現(xiàn)它在處理什么事情上花費(fèi)的時(shí)間最多,這些有用的信息可以一并附在你要提交的BUG中,或在搜索引擎中使用其中一些作為關(guān)鍵字進(jìn)行搜索,看看是否有現(xiàn)成的解決方案。
堆棧跟蹤應(yīng)用到等待資源而掛起的程序上也很好使,下面是我前面使用的Python程序的跟蹤結(jié)果。
(gdb) where #0 0x006a2422 in __kernel_vsyscall () #1 0x0095d241 in recv () at ../sysdeps/unix/sysv/linux/i386/socket.S:61 #2 0x081301ba in ?? () #3 0x081303b4 in ?? () #4 0x080e0a21 in PyEval_EvalFrameEx () #5 0x080e2807 in PyEval_EvalCodeEx () #6 0x080e0c8b in PyEval_EvalFrameEx () ... etc.
Gdb顯示了strace做的一些事情:recv,接下來的內(nèi)容只告訴你你正在運(yùn)行Python,但沒有告訴你身在Python腳本何處,想知道怎么發(fā)掘更多的信息嗎?請繼續(xù)關(guān)注下一期文章吧,我將介紹調(diào)式Python程序的一些技術(shù),以及在出問題的機(jī)器上沒有安裝gdb等花俏的開發(fā)工具時(shí)該怎么做。
【51CTO.com譯稿,轉(zhuǎn)載請注明原文作譯者和出處。】
原文:http://www.linuxplanet.com/linuxplanet/tutorials/7232/1/
【編輯推薦】