快速診斷Linux服務器故障的三大法寶
原創【51CTO精選譯文】作為系統管理員的你,是否以為一切盡在你的掌握和控制之中呢?但現實往往事與愿違,你認為那些正在運行和收集數據的進程卻已經有兩個小時沒有向你匯報任何消息了,也許是你的監控客戶端失去了響應,也許是服務器端出了問題,總之你不能第一時間知道問題出在哪里,而最要命的是這種情況每隔幾天就會重復一次,心態再好的人遇到這種情況也會火冒三丈。那么如何找出運行中的進程究竟發生了什么呢?其實不用高深知識,也不用高級的監控套件,用系統自帶的一些工具就夠了,下面一起來看看如何利用Linux系統自帶的一些工具診斷服務器故障吧。
Top和其它系統工具
要想知道進程在運行期間發生了什么,我們最好先獲得該進程的ID,如果你知道被“卡住”或資源消耗不斷上升進程的名稱,那反查該進程的ID就好辦了,使用ps aux | grep processname命令即可,不知道進程名稱也沒關系,我們還可以使用top來查看高CPU利用率或高內存占有率的進程。
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
默認情況下,top命令的結果按“吃”CPU多少進行倒序排列,在上面的例子中,Firefox卡住了,它正在運行Flash,瀏覽器和它的輔助程序一起占用了45%的CPU時鐘周期,這還不算什么,如果你看到一個CPU利用率達到99%的進程,那它一定有問題。
當你發現有問題的進程后,該如何了解它正在做什么呢?這個時候就要請出strace了。
strace
strace是一個很有用的程序,它可以顯示正在發生的系統調用,系統調用包括文件操作,如讀、寫和打開,超時設定和發送信號,網絡操作以及其它各種獲得或設置系統信息的操作,你可以閱讀man 2 intro查看概述,或man 2 syscalls查看所有可用系統調用的詳細列表。
這一切聽起來有點神秘,但有時看strace輸出可以準確地知道一個程序為什么出故障了,也許是等待網絡,也許是重復打開一個根本就不存在的文件等等。
你可以在strace下運行一個程序,如strace firefox,但更多時候,你想連接到一個正在運行的進程,當然沒問題,首先使用ps或top得到進程ID,然后使用“strace –p 進程id”即可。
假設我有一個程序看起來已經掛了,top命令顯示它沒有使用任何CPU,但它確實已經卡住,至少有半個小時沒有做任何事情了,我們使用strace –p來跟蹤一下。
$ strace -p 3672 Process 3672 attached - interrupt to quit recv(3,
strace就停在這里,光標在中間那行閃動,這是怎么回事呢?
其實它在等待recv系統調用,按照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
從上面的結果可以看出,進程是在等待讀取網絡套接字中的內容,顯然我們對進程掛起有了進一步了解。
如何模擬故障?
你在建立一個診斷工具庫時,有時你可能希望有一個簡單辦法來體驗它們,這時我們要模仿進程掛起故障,如果你有一個Web服務器就好辦了,編寫一個腳本,內容如下:
#! /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或自己編寫一個Python腳本測試它。
#!/usr/bin/env python import urllib2 response = urllib2.urlopen("http://example.com/testcgi/index.cgi")
當然,如果你想要某個程序占用所有可用的CPU資源,只需要在腳本中添加下面的代碼:
while /bin/true; do echo x done
用其它語言也可以,只要達到這種目的即可。
如果用top和strace的幫助仍然不大,下面還有個最終法寶——#p#
使用gdb獲得堆棧跟蹤信息
好吧,我承認即使知道了進程ID和strace輸出結果,但幫助仍然不大,不用急,我還使出絕招呢,絕招就是使用gdb獲得堆棧跟蹤信息,堆棧跟蹤不僅會告訴你程序當前正在做什么,有底層的信息(如等待網絡套接字),也有較高級別的信息(如正在執行什么類型的網絡操作)。
和strace的使用方法一樣,gdb也使用-p加進程id的命令格式,啟動后你會獲得一個gdb提示符,輸入where就可以獲得一個堆棧跟蹤。下面是Firefox在運行一些有問題的JavaScript代碼時的堆棧跟蹤信息。
#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源代碼也能從上面的堆棧跟蹤結果看出,它正在處理一些和字體有關的事情。
如果程序正在循環,那么它可能一直在做相同的事情,當你運行gdb –p時,它會暫時停止程序以便你進行檢查,在提示符后按下c就可以讓它繼續運行,按下Ctrl-C會再次停止,再輸入一次where就會獲得第二個堆棧輸出。
(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
這一次結果不一樣了,它只暗示Firefox正在處理JavaScript(JS)和XUL相關的事情,反復停止又啟動程序,你就會發現它在處理什么事情上花費的時間最多,這些有用的信息可以一并附在你要提交的BUG中,或在搜索引擎中使用其中一些作為關鍵字進行搜索,看看是否有現成的解決方案。
堆棧跟蹤應用到等待資源而掛起的程序上也很好使,下面是我前面使用的Python程序的跟蹤結果。
(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,接下來的內容只告訴你你正在運行Python,但沒有告訴你身在Python腳本何處,想知道怎么發掘更多的信息嗎?請繼續關注下一期文章吧,我將介紹調式Python程序的一些技術,以及在出問題的機器上沒有安裝gdb等花俏的開發工具時該怎么做。
【51CTO.com譯稿,轉載請注明原文作譯者和出處?!?/p>
原文:http://www.linuxplanet.com/linuxplanet/tutorials/7232/1/
【編輯推薦】