利用strace/pstack除錯Nginx

發表於2013-06-02

Linux下有兩個命令strace 和ltrace 可以檢視一個應用程式在執行過程中所發起的系統呼叫,這對作為標準應用程式的Nginx自然同樣可用。由於這兩個命令大同小異,所以下面就僅以strace為例做簡單介紹,大致瞭解一些它能幫助我們獲取哪些有用的除錯資訊。關於strace/ltrace以及後面介紹的pstack更多的用法請參考對應的Man手冊。

從strace的Man手冊可以看到幾個有用的選項。

-p pid:通過程式號來指定被跟蹤的程式。

-o filename:將跟蹤資訊輸出到指定檔案。

-f:跟蹤其通過frok呼叫產生的子程式。

-t:輸出每一個系統呼叫的發起時間。

-T:輸出每一個系統呼叫消耗的時間。

首先利用ps命令檢視到系統當前存在的Nginx程式,然後用strace命令的-p選項跟蹤Nginx工作程式,如圖2-2所示。

 

為了簡化操作,我這裡只設定了一個工作程式,該工作程式會停頓在epoll_wait系統呼叫上,這是合理的,因為在沒有客戶端請求時,Nginx就阻塞於此(除非是在爭用accept_mutex鎖),在另一終端執行wget命令向Nginx發出http請求後,再來看strace的輸出,如圖2-3所示。

 [root@localhost ~]# wget 127.0.0.1 

 

通過strace的輸出可以看到Nginx工作程式在處理一次客戶端請求過程中發起的所有系統呼叫。我這裡測試請求的html非常簡單,沒有附帶css、js、jpg等檔案,所以看到的輸出也比較簡單。strace輸出的每一行記錄一次系統呼叫,等號左邊是系統呼叫名以及呼叫引數,等號右邊是該系統呼叫的返回值。逐一註釋如下所述。

1. epoll_wait返回值為1,表示有1個描述符存在可讀/寫事件,這裡當然是可讀事件。

2. accept4接受該請求,返回的數字3表示socket的檔案描述符。

3. epoll_ctl把accept4建立的socket套接字(注意引數3)加入到事件監聽機制裡。

4. recv從發生可讀事件的socket檔案描述符內讀取資料,讀取的資料存在第二個引數內,讀取了107個位元組。

5. stat64判斷客戶端請求的html檔案是否存在,返回值為0表示存在。

6. open/fstat64開啟並獲取檔案狀態資訊。open檔案返回的檔案描述符為9,後面幾個系統呼叫都用到這個值。

7. writev把響應頭通過檔案描述符3代表的socket套接字發給客戶端。

8. sendfile64把檔案描述符9代表的響應體通過檔案描述符3代表的socket套接字發給客戶端。

9. 再往檔案描述符4代表的日誌檔案內write一條日誌資訊。

10. recv看客戶端是否還發了其他待處理的請求/資訊。

11. 最後關閉檔案描述符3代表的socket套接字。

由於strace能夠提供Nginx執行過程中的這些內部資訊,所以在出現一些奇怪現象時,比如Nginx啟動失敗、響應的檔案資料和預期不一致、莫名其妙的Segment Fault段錯誤、存在效能瓶頸(利用-T選項跟蹤各個函式的消耗時間),利用strace也許能提供一些相關幫助。最後,要退出strace跟蹤,按ctrl+c即可。

命令strace跟蹤的是系統呼叫,對於Nginx本身的函式呼叫關係無法給出更為明朗的資訊,如果我們發現Nginx當前執行不正常,想知道Nginx當前內部到底在執行什麼函式,那麼命令pstack就是一個非常方便實用的工具。

pstack的使用也非常簡單,後面跟程式ID即可。比如在無客戶端請求的情況下,Nginx阻塞在epoll_wait系統呼叫處,此時利用pstack檢視到的Nginx函式呼叫堆疊關係,如圖2-4所示。

 

從main()函式到epoll_wait()函式的呼叫關係一目瞭然,和在gdb內看到的堆疊資訊一模一樣,其實因為命令pstack本身也就是一個利用gdb實現的shellShell指令碼,關於這點,感興趣的讀者可以自己看下pstack對應的指令碼程式。

via http://book.51cto.com/art/201305/395383.htm

相關文章