Nginx 是一個事件驅動的框架,所謂事件主要指的是網絡事件,Nginx 每一個網絡鏈接會對應兩個網絡事件,一個讀事件一個寫事件。在深刻了解 Nginx 各類原理及在極端場景下的一些錯誤場景處理時,須要首先理解什麼是網絡事件。windows
接下來看上面這張圖,好比主機 A 就是一臺家裏的筆記本電腦,那麼主機 B 就是一臺服務器,上面跑着 Nginx 服務。從主機 A 發送一個 HTTP 的 GET 請求到主機 B,這樣的一個過程當中主要經歷了哪些事件?經過上圖數據流部分能夠看出:瀏覽器
應用層裏發送了一個 GET 請求 -> 到了傳輸層,這一步主要在作一件事,就是瀏覽器打開了一個端口,在 windows 的任務管理器中能夠看到這一點,他會把這個端口記下來以及把 Nginx 打開的端口好比 80 或者 443 也記到傳輸層 -> 而後在網絡層會記下咱們主機所在的 IP 和目標主機,也就是 Nginx 所在服務器公網 IP -> 到鏈路層之後 -> 通過以太網 -> 到達家裏的路由器(網絡層),家中的路由器會記錄下所在運營商的一些下一段的 IP -> 經過廣域網 -> 跳轉到主機 B 所在的機器中 -> 報文會通過鏈路層 -> 網絡層 -> 到傳輸層,在傳輸層操做系統就知道是給那個打開了 80 或者 443 的進程,這個進程天然就是 Nginx -> 那麼 Nginx 在他的 HTTP 狀態處理機裏面(應用層)就會處理這個請求。服務器
在上述過程當中網絡報文扮演了一個怎樣的角色呢?網絡
數據鏈路層會在數據的前面 Header 部分和 Footer 部分添加上源 MAC 地址和源目的地址 -> 到了網絡層則是 Nginx 的公網地址(目的 IP 地址)和瀏覽器的公網地址(源 IP 地址)-> 到了 TCP 層(傳輸層),指定了 Nginx 打開的端口(目的端口)和瀏覽器打開的端口(源端口)-> 而後應用層就是 HTTP 協議了。框架
這就是一個報文,也就是說咱們發送的 HTTP 協議會被切割成不少小的報文,在網絡層會切割叫 MTU,以太網的每一個 MTU 是 1500 字節;在 TCP 層(傳輸層)呢會考慮中間每一個環節中最大的一個 MTU 值,這個時候每每每一個報文只有幾百字節,這個報文大小咱們稱爲叫 MSS ,因此每收到一個 MSS 小於這麼大小的一個報文時其實就是一個網絡事件。異步
這個時候,咱們來看下 TCP 協議中許多事件是怎樣和咱們平常調用的一些接口(好比 Accept、Read、Write、Close)是怎樣關聯在一塊兒的?工具
請求創建 TCP 鏈接事件其實是發送了一個 TCP 報文,經過上面第二部分講解的那樣的一個流程到達了 Nginx,對應的是讀事件。由於對於 Nginx 來講,我讀取到了一個報文,因此就是 Accept 創建連接事件。操作系統
若是是 TCP 鏈接可讀事件,就是發送了一個消息,對於 Nginx 也是一個讀事件,就是 Read 讀消息。blog
若是是對端(也就是瀏覽器)主動地關掉了,至關於 windows 操做系統會去發送一個要求關閉連接的一個事件,對於 Nginx 來講仍是一個讀事件,由於他只是去讀取一個報文。接口
那什麼是寫事件呢?當咱們的瀏覽器須要向瀏覽器發送響應的時候,須要把消息寫到操做系統中,要求操做系統發送到網絡中,這就是一個寫事件。
像這樣的一些網絡讀寫事件,一般在 Nginx 中或者任何一個異步事件的處理框架中,他會有個東西叫事件收集、分發器。會定義每類事件處理的消費者,也就是說事件是一個生產者,是經過網絡中自動的生產到咱們的 Nginx 中的,咱們要對每種事件創建一個消費者。好比鏈接創建事件消費者,就是對 Accept 調用,HTTP 模塊就會去創建一個新的鏈接。還有不少讀消息或者寫消息,在 HTTP 狀態機中不一樣的時間段會調用不一樣的方法也就是每一個消費者處理。
以上就是一個事件分發、消費器,包括 AIO 像異步讀寫磁盤事件,還有定時器事件,好比是否超時(worker_shutdown_timeout)。
上面介紹了網絡報文的發送以及對應的 Nginx 中的網絡事件,好比 Accept 創建一條新鏈接實際上是收到一條讀事件,接下來咱們經過抓包來分析創建三次握手時時怎麼樣讓 Nginx 收到讀事件,使用的抓包工具是 Wireshark。
首先咱們安裝 Wireshark 軟件,並對 Nginx 所在 IP 和端口進行抓包,而後訪問頁面,在 TCP 層主要說兩件事情:
IP 層主要解決機器與機器之間怎樣互相找到的問題。
三次握手也就是 windows 先向 Nginx 發送了一次 [SYN],那麼相反的 Nginx 所在的服務器也會向 windows 發送一個 [SYN],這個時候 Nginx 是沒有感知到的,由於這個鏈接仍是處於半打開的狀態。直到這臺 windows 服務器再次發送 [ACK] 到 Nginx 所在的服務器之上時,Nginx 所在的操做系統纔會去通知 Nginx 咱們收到了一個讀事件,這個讀事件對應是創建一個新鏈接,因此此時 Nginx 應該調用 Accept 方法去創建一個新的鏈接。
以上咱們經過 Wireshark 抓包演示了正常的三次握手是怎麼樣引起一個讀事件來使得 Nginx 去處理這樣一個讀事件來創建新的鏈接的。
這篇文章主要講解了網絡事件,並經過抓包來分析 Nginx 網絡事件,這對咱們理解 Nginx 異步處理框架是很是有幫助的,包括 OpenResty 也是強依賴於網絡事件以及事件分發的。