天天看點

《深入剖析Nginx》——2.3 利用strace/pstack調試Nginx

本節書摘來自異步社群《深入剖析nginx》一書中的第2章,第2.3節,作者: 高群凱 更多章節内容可以通路雲栖社群“異步社群”公衆号檢視。

linux下有兩個指令strace1和ltrace2可以分别用來檢視一個應用程式在運作過程中所發起的系統函數調用和動态庫函數調用,這對作為标準應用程式的nginx自然同樣可用。由于這兩個指令大同小異,下面就僅以strace為例做簡單介紹,大緻了解一些它能幫助我們擷取哪些有用的調試資訊。關于strace/ltrace以及後面介紹的pstack更多的用法請參考對應的man手冊。

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

p pid:通過程序号來指定被跟蹤的程序。

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

f:跟蹤其通過frok調用産生的子程序。

t:輸出每一個系統調用的發起時間。

t:輸出每一個系統調用消耗的時間。

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

《深入剖析Nginx》——2.3 利用strace/pstack調試Nginx

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

《深入剖析Nginx》——2.3 利用strace/pstack調試Nginx

通過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 ation fault段錯誤、存在性能瓶頸(利用-t選項跟蹤各個函數的消耗時間),利用strace也許能提供一些相關幫助。最後,要退出strace跟蹤,按ctrl+c即可。

指令strace跟蹤的是系統調用,對于nginx本身的函數調用關系無法給出更為明朗的資訊,如果我們發現nginx目前運作不正常,想知道nginx目前内部到底在執行什麼函數,那麼指令pstack就是一個非常友善實用的工具。

pstack的使用也非常簡單,後面跟程序id即可。比如在無用戶端請求的情況下,nginx阻塞在epoll_wait系統調用處,此時利用pstack檢視到的nginx函數調用堆棧關系,如圖2-4所示。

《深入剖析Nginx》——2.3 利用strace/pstack調試Nginx

從main()函數到epoll_wait()函數的調用關系一目了然,和在gdb内看到的堆棧資訊一模一樣,其實指令pstack本身也就是一個利用gdb實作的shell腳本,關于這點,感興趣的讀者可以自己看下pstack對應的腳本程式。