震撼!全網第一張源碼分析全景圖揭秘Nginx


不管是C/C++技術棧,還是PHP,Java技術棧,從事后端開發的朋友對nginx一定不會陌生。

想要深入學習nginx,閱讀源碼一定是非常重要的一環,但nginx源碼量畢竟還是不算少,一不小心就容易陷入某個細節,迷失在茫茫碼海之中。

如果有一張地圖,讓我們開啟上帝視角,總覽全局,幫助我們快速學習整體框架結構,又能不至於迷失其中那就再好不過了!

看到這篇文章的你有福了,筆者花了不少時間,把這件事給做了,先來看個全貌(限於平台圖片尺寸設定,這里只能看個大概,想獲取高清大圖請看文末):

下面選取一些關鍵部分來一窺神秘的nginx。

主進程啟動

nginx主進程啟動后,進行一系列的初始化,包括但不限於:

  • 命令行參數解析
  • 時間初始化
  • 日志初始化
  • ssl初始化
  • 操作系統相關初始化
  • 一致性hash表初始化
  • 模塊編號處理

核心初始化

另外一個最重要的初始化由ngx_init_cycle()函數完成,該函數圍繞nginx中非常核心的一個全局數據結構ngx_cycle_t展開。

該函數完成了幾個核心初始化:

  • 配置文件解析
  • 創建並監聽socket
  • 初始化nginx各模塊

nginx核心模塊群

nginx是一個模塊化設計的軟件,優秀的架構設計使得nginx可以擴展非常多的模塊。

要一一描繪出這些模塊顯得有些雜亂和工作量巨大,僅選取一些關鍵核心模塊進行了展示:

每個模塊有一個支持的命令解析列表,在初始化過程中,主進程將會遍歷所有模塊的命令列表,進行配置文件中的命令解析,如經常用的ngx_http_proxy_module:

ngx_http_core_module模塊:

main函數的最后,根據是否啟用多進程模型,分別進入多進程版本的ngx_master_process_cycle和單進程版本的ngx_single_process_cycle()

以常見的多進程版本為例,進入該函數后,首先設置進程名稱為:"master process",隨后啟動各工作子進程。

啟動子進程
經過幾層封裝,最終通過fork啟動多個子進程:

除了工作子進程,還啟動了緩存管理進程。

之后主進程進入工作循環,周期性更新時間並檢查各全局標記,根據不同情況給子進程發送不同信號。

子進程工作循環

子進程啟動后,進入ngx_worker_process_cycle,進行一些工作進程的初始化,隨后修改進程名稱為:"worker process"

接着進入工作循環函數ngx_process_events_and_timers,在該函數中主要負責:

  • 競爭互斥鎖,拿到鎖的進程才能執行accept接受新的連接,以此在多進程之間解決驚群效應
  • 通過epoll異步IO模型處理網絡IO事件,包括新的連接事件和已建立連接發生的讀寫事件
  • 處理定時器隊列中到期的定時器事件,定時器通過紅黑樹的方式存儲

HTTP請求預處理

當連接有數據產生時,工作線程讀取socket中到來的數據,並根據HTTP協議格式進行解析,最終封裝成ngx_request_t請求對象,提交處理。

HTTP請求處理的11個階段

在nginx中各HTTP模塊是以掛載的形式串接而成,以流水線工作模式進行HTTP請求的處理,nginx將一個HTTP請求的處理划分為11個階段。

typedef enum {
    NGX_HTTP_POST_READ_PHASE = 0,
    NGX_HTTP_SERVER_REWRITE_PHASE,
    NGX_HTTP_FIND_CONFIG_PHASE,
    NGX_HTTP_REWRITE_PHASE,
    NGX_HTTP_POST_REWRITE_PHASE,
    NGX_HTTP_PREACCESS_PHASE,
    NGX_HTTP_ACCESS_PHASE,
    NGX_HTTP_POST_ACCESS_PHASE,
    NGX_HTTP_PRECONTENT_PHASE,
    NGX_HTTP_CONTENT_PHASE,
    NGX_HTTP_LOG_PHASE
} ngx_http_phases;

每階段(部分階段保留,不允許掛載)允許多個模塊掛載,一個模塊也可以掛載到多個階段。因此,初次完成掛載的存儲結構是一個二維數組的形式。

不過在初始化過程中,ngx_http_init_phase_handlers函數將該二維數組轉換成了一維數組。下圖是nginx中各模塊掛載情況:

全景圖

最后,再來看一看全貌:

總結

nginx不僅是一款優秀的高性能web服務器,對於C/C++技術棧的同學來說,還是一個很好的學習對象,其良好的架構設計,優美的代碼風格和經典的編程技法無一不值得細細品來。

不過限於筆者水平和時間有限,雖然號稱全景圖,但依然無法覆蓋到nginx的方方面面,歡迎讀者朋友留言交流,讓此圖日漸完善,謝謝大家。

獲取完整高清大圖,可在公眾號里回復“nginx”自動獲取。

往期熱門回顧

一個Java對象的回憶錄:那些被鎖住的日子

一個整數+1引發的災難

一網打盡!每個程序猿都該了解的黑客技術大匯總

看過無數Java GC文章,這5個問題你也未必知道!

Python一鍵轉Jar包,Java調用Python新姿勢!

一個Java對象的回憶錄:垃圾回收

內核地址空間大冒險3:權限管理

誰動了你的HTTPS流量?

路由器里的廣告秘密

內核地址空間大冒險2:中斷與異常

DDoS攻擊:無限戰爭

一條SQL注入引出的驚天大案

內核地址空間大冒險:系統調用

一個HTTP數據包的奇幻之旅

一個DNS數據包的驚險之旅

我是一個流氓軟件線程

掃碼關注,更多精彩



免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM