Nginx 源碼的 跟蹤與調試

來源:互聯網
上載者:User

在學習優秀的原始碼時是 少不了源碼的跟蹤與調試,它不僅是我們解決程式bug的有效途徑 也是我們理解、學習優秀源碼的有效途徑。

本文主要介紹一些源碼調試的方法,並結合Nginx 源碼進行樣本。

1, 利用GDB調試

   a,首先你應該熟悉 GDB 調試的一些基本命令(不熟悉的移步 至
用GDB偵錯工具 ,熟悉step,run,break,list,info,continue等命令)。

   b,  下載nginx 源碼,這裡使用nginx-1.0.14,解壓檔案。其中auto檔案夾裡包含了configure 運行時的各種命令集合,src是源碼。為了利用

        GDB調試Nginx,需要在產生Nginx程式時把 -g 編譯選項開啟。我們需要修改 
auto/cc/conf 檔案 把 ngx_compile_opt="-c"  加上  -g 選項

         變為 ngx_compile_opt="-c -g", 下一步執行configure命令: sudo ./configure  ,然後運行命令:vim  objs/Makefile  確認一下-g參數是

         否加上了。效果如。

        

         -g  編譯選項已開啟,然後執行命令: sudo make .(如果之前已經執行過make,那麼第二次make時 需要 確保能夠重新編譯,此時可以通過

            重新整理所有源檔案時間戳記,間接達到重新編譯出一個新的Nginx可執行程式,命令為: find . -name "*.c" | xargs touch ), 好了,Nginx編譯成功。

     c, 啟動 nginx ,在objs目錄下執行命令:sudo  ./nginx ,成功運行nginx後執行命令: ps -ef | grep nginx, 查看nginx的master及worker進程的PID,

       

        如果對nginx 背景工作處理序 2177進行gdb調試,那麼可以利用gdb的 -p 選項。 命令:
gdb  -p 2177.

      當有多個背景工作處理序時 調試起來比較麻煩。我們可以修改配置項,修改檔案 nginx.conf 。加入master_process  off;  單進程模式 將監控進程和工作

      進程邏輯全部合在一個 進程裡。    此時只有一個進程,可以進行gdb調試效果

我們知道背景工作處理序會停留在epoll_wait處等待相應的事件發生,而這個函數調用被封裝在ngx_process_events_and_timers 中。於是我們在這個函數出設定一個斷點:

 b ngx_event.c:ngx_process_events_and_timers ,結合gdb 命令c ,s,n  :

  採用命令c,使得nginx一直運行,直到遇到第一個斷點,處理事件的方法是ngx_process_events,於是我們用命令 s 跟蹤進去這個函數 .當執行到epoll_wait函數的時候,發

  現進程停留在這裡,不能在向下執行。這就證明了 worker子進程阻塞在epoll_wait函數調用處。

  此時我們在另一個終端執行下列命令,以向nginx發送訊息: curl -I localhost . 可以看到請求已經發送,正在等待回應。

此時繼續執行命令 c  即可在另一終端得到 回應。此時可以通過bt 命令查看單進程模式下函數調用的過程。。

 curl

 gdb  bt

2,利用strace、  pstack 調試 nginx

   a, strace 常用來跟蹤進程執行時的系統調用和所接收的訊號。 在Linux世界,進程不能直接存取硬體裝置,當進程需要訪問硬體裝置(比如讀取磁碟檔案,

   接收網路資料等等)時,必須由使用者態模式切換至核心態模式,通 過系統調用訪問硬體裝置。strace可以跟蹤到一個進程產生的系統調用,包括參數,

   傳回值,執行消耗的時間。 此外命令 ltrace 用來查看 動態庫函數調用。

 b, 那具體是哪一個函數調用呢?在strace輸出結果中並不能找到答案,因其輸出顯示都是系統調用,要顯示程式中函數調用棧資訊,就輪到pstack上場了。

    pstack是一個指令碼工具,其核心實現就是使用了gdb以及thread apply all bt命令.

  可以通過命令 man 來 查看 Man手冊中 strace、ltrace、pstack的具體具體用法。

 我們在此 修改 nginx的設定檔 nginx.conf  使其為 僅具有 一個 master 進程和一個 worker進程.  把1中修改的 master_process  off; 註解掉 加上 #

 並在設定檔上加上 worker_processes  1;

 關閉之前的nginx 重新啟動 nginx。 利用命令: ps -ef | grep nginx  查看當前存在的nginx進程,然後用strace 命令的參數 -p 選項跟蹤 Nginx 背景工作處理序,。

  可以看到背景工作處理序阻塞在 epoll_wait 系統調用上,因為此時沒有用戶端請求,nginx就阻塞於此,在另一個終端執行curl 命令: curl -I localhost ,

  再來看strace輸出 結果。

strace輸出的每一行記錄一次系統調用,等號左邊是系統調用名以及調用參數,等號右邊是該系統調用的傳回值。

通過上面的系統調用我們可以做出如下分析:

 ⑴.   epoll_wait傳回值為1,表示有1個描述符存在可讀/寫事件,這裡當然是可讀事件。
 ⑵.   accept4接受該請求,返回的數字3表示socket的檔案描述符。
 ⑶.   epoll_ctl把accept4建立的socket通訊端(注意參數3)加入到事件監聽機制裡。
 ⑷.   recv從發生可讀事件的socket檔案描述符內讀取資料,讀取的資料存在第二個參數內,讀取了79個位元組。
 ⑸.   stat64判斷用戶端請求的html檔案是否存在,傳回值為0表示存在。
 ⑹.   open/fstat64開啟並擷取檔案狀態資訊。open檔案返回的檔案描述符為9,後面幾個系統調用都用到這個值。
 ⑺.   writev把回應標頭通過檔案描述符3代表的socket通訊端發給用戶端。
 ⑻.   sendfile64把檔案描述符9代表的響應體通過檔案描述符3代表的socket通訊端發給用戶端。
 ⑼.   再往檔案描述符4代表的記錄檔內write一條日誌資訊。
 ⑽.   recv看用戶端是否還發了其它待處理的請求/資訊。
 ⑾.   最後關閉檔案描述符3代表的socket通訊端。
由於strace能夠提供nginx執行過程中的這些內部資訊,所以在出現一些奇怪現象,比如nginx啟動失敗、響應的檔案資料和預期不一致、莫名其妙的Segment Fault段錯誤、

存在效能瓶頸(利用-T選項跟蹤各個函數的消耗時間),利用strace也許能提供一些相關協助。最後,要退出strace跟蹤,按ctrl+c即可。

命令strace跟蹤的是系統調用,對於nginx本身的函數調用關係無法給出更為明朗的資訊,如果我們發現nginx當前運行不正常,想知道nginx當前內部到底在執行什麼函數,

那麼命令pstack就是一個非常方便實用的工具。pstack的使用也非常簡單,後面跟進程id即可,比如在無用戶端請求的情況下,nginx阻塞在epoll_wait系統調用處,此時

利用pstack查看到的nginx函數呼叫堆疊關係如下:

從main()函數到epoll_wait()函數的調用關係一目瞭然,和在gdb內看到的堆棧資訊一樣。我們可以利用此進行分析最佳化等。

除了 1,2 還有方法 加樁調試等方法在此不再敘述。以後有機會可以介紹下特殊應用邏輯的調試。

好了,多謝閱讀。

參考資料:

http://code.google.com/p/nginxsrp/wiki/NginxCodeReview

<深入剖析Nginx>

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.