標籤:http os io 使用 ar strong 檔案 資料 2014
紅帽Linux故障定位技術詳解與執行個體(1)2011-09-28 14:26 圈兒 BEAREYES.COM 我要評論(0) 字型大小:T | T
線上故障定位就是在故障發生時, 故障所處的作業系統環境仍然可以訪問,故障處理人員可通過console, ssh等方式登入到作業系統上,在shell上執行各種操作命令或測試程式的方式對故障環境進行觀察,分析,測試,以定位出故障發生的原因。
AD:2014WOT全球軟體技術峰會北京站 課程視頻發布
紅帽Linux故障定位技術詳解與執行個體是本文要介紹的內容,主要是來瞭解並學習紅帽linux中故障定位技術的學習,故障定位技術分為線上故障定位和離線故障定位,一起來看詳解。
1、故障定位(Debugging)情境分類
為便於描述問題,將Linux上各種軟體故障定位的情形分成兩類
(1)線上故障故障定位
線上故障定位(online-debugging)就是在故障發生時, 故障所處的作業系統環境仍然可以訪問,故障處理人員可通過console, ssh等方式登入到作業系統上,在shell上執行各種操作命令或測試程式的方式對故障環境進行觀察,分析,測試,以定位出故障發生的原因
(2)離線故障定位
離線故障定位(offline-debugging)就是在故障發生時,故障所處的作業系統環境已經無法正常訪問,但故障發生時系統的全部或部分狀態已經被系統本身所固有或事先設定的方式收集起來,故障處理人員可通過對收集到的故障定位狀態資訊進行分析,定位出故障發生的原因
2、應用進程故障情形及處理
應用進程的故障一般不會影響作業系統運行環境的正常使用(如果應用代碼的bug導致了核心的crash或hang,則屬於核心存在漏洞),所以可採用線上故障定位的方法,靈活的進行分析. 應用代碼故障的情形有如下幾種:
(1)進程異常終止
很多使用者認為進程異常終止情況無從分析,但實際上進程異常終止情況都是有跡可尋的. 所有的進程異常終止行為,都是通過核心發訊號給特定進程或進程組實現的. 可分成幾個類型進行描述:
- SIGKILL. SIGKILL最特殊,因為該訊號不可被捕獲,同時SIGKILL不會導致被終止的進程產生core檔案, 但如果真正的是由核心中發出的SIGKILL,則核心一定會在dmesg中記錄下資訊. 另外在核心中使用SIGKILL的地方屈指可數,如oom_kill_process()中, 所以通過dmesg記錄並且分析核心中使用SIGKILL的代碼,並不難分析原因
- SIGQUIT, SIGILL, SIGABRT, SIGBUS, SIGFPE, SIGSEGV. 這幾個訊號在保留情況下會終止進程並會產生core檔案, 使用者根據core中的stack trace資訊,能直接定位出導致終止訊號的代碼位置. 另外, SIGQUIT,SIGABRT一般是由使用者代碼自己使用的,好的代碼一般會記錄日誌. SIGILL, SIGBUS, SIGFPE, SIGSEGV, 都是由核心中產生的,搜尋核心源碼,不難列出核心中使用這幾個訊號的地方, 如SIGILL 是非法指令,可能是浮點運算產生的代碼被corrupted或文本地區的實體記憶體corruption; SIGBUS多由MCE故障定位導致; SIGSEGV多由應用代碼的指標變數被corrupted導致. 對於應用的heap或stack的記憶體被corrupted, 可用valgrind工具對應用進行profile, 通常能直接發現導致corruption的代碼
- SIGINT, SIGPIPE, SIGALRM, SIGTERM. 這幾個訊號在保留情況下終止進程但不會產生core檔案. 對這幾個訊號,建議使用者一定要定義一個handler,以記錄產生問題的上下文. 比較容易忽略的是SIGPIPE, 很多使用者程式在使用select()或poll()時只監聽read/write描述符,不監聽exception描述符,在對方TCP已經關閉的情況下,仍然向socket中寫入,導致SIGPIPE.
- 對於惡意的代嗎產生的進程終止行為,如合作的一些進程中,A向B發SIGKILL, 而沒做日誌記錄,或者B直接判斷某條件而調用exit(), 也沒有做日誌記錄.在應用代碼量很大的情況下,通過分析代碼故障定位這種情形也許很難. SystemTap提供瞭解決這個問題的一個比較好的方法,就是寫使用者層的probes, 追蹤進程對signal(), exit() 等系統調用的使用
(2)進程阻塞,應用無法正常推進
這種情況,對於單個被阻塞的進程而言,屬於正常狀態, 但對於包含多個進程的應用整體而言,屬於異常. 應用無法推進,說明其中某一個進程推進的因素出現了問題,導致其他依賴於它的進程也要等待. 分析這種情形需要分析清楚進程或事件之間的依賴關係,及資料的處理流. 首先要用gdb -p 的back trace功能查出各進程阻塞的執行路徑, 以確定每個進程所處在的狀態機器的位置.
通常而言,如果只考慮各個進程的狀態,則進程之間可能形成了一種互相依賴的環形關係,如(P1發請求=>P2處理=>P2發反應=>P1再請求=>P2處理=>P2再發反應), 但應用對workload, 一般是按一個個的transaction 或 session的方式進行處理的,每個transaction都有起點和終點, 我們需要用strace, tcpdump 等工具以及應用的執行日誌進行觀察,分析出當前正被處理的transaction所被阻滯的位置,從而找出全部狀態機器被阻塞的原因. 導致這種狀態機器停止運轉的原因有多個:如和應用通訊的遠端出現了問題,後端資料庫/目錄等出現了問題,應用的某個進程或線程處於非正常的blocking位置或直接終止,不再正常工作.
(3)使用者進程形成死結
使用者進程形成死結,如果沒有記憶體上的故障定位,則完全是應用自身的邏輯問題. 死結的進程或線程之間由於鎖的互相佔有形成了環路。 這種情況發生時,用gdb -p 的back trace的功能能直接確定死結的進程全部阻塞在futex()等和鎖相關的系統調用上, 這些調用futex()的路徑可能是mutex, semaphore, conditional variable 等鎖函數. 通過分析call trace 的代碼,能直接確定各進程在執行到該位置時,可能已經持有的全部鎖, 根據這個修改程式的代碼,消除死結環路,就可解決問題.
注意,記憶體故障也可導致假的死結的,如實體記憶體故障可直接導致鎖變數的值為-1, 所以使用該鎖的進程都會阻塞. 如果是代碼的bug導致的記憶體corruption,可用valgrind工具檢查程式來發現. 但如果是實體記憶體的故障定位導致的corruption, 則需要硬體的支援,對於高端的PC, 如MCE功能的機器,當實體記憶體故障定位時能直接產生異常或報告, 但對於低端PC伺服器,除了運行memtest工具進行檢測外,沒有其他方法
(4)進程長期處於 ‘D‘ (UnInterruptible)狀態沒法退出
這種多是由核心中的故障引起的. 核心在很多執行路徑中會將進程至於‘D‘的狀態,以確保關鍵的執行路徑不被外部的訊號中斷, 導致不必要的核心中資料結構狀態的不一致性. 但一般而言,進程處於 ‘D‘ 狀態的時間不會太久, 因為狀態結束的條件(如timer觸發,
IO操作完成等)很快會將進程喚醒. 當進程長期處於 ‘D‘,關鍵是要找出其阻塞的代碼位置, 用 sysrq 的t鍵功能可直接列印出系統中全部睡眠進程的核心執行堆棧,如 echo ‘t‘ > /proc/sysrq-trigger, 其中包括出現 ‘D‘狀態的進程的核心態堆棧. 找出代碼位置後,一般可直接分析出 ‘D‘ 狀態不能退出的原因, 如IO read操作因硬體或nfs故障而不能完成.
有可能導致 ‘D‘ 狀態的原因比較複雜,如‘D’的退出依賴於某變數的值,而該變數的值因某種原因被永久corrupted掉了.
紅帽Linux故障定位技術詳解與執行個體(1)