在了解了網絡事件以及事件分發收集器以后,讓我們來了解 Nginx 是怎么樣處理事件的?
Nginx 事件循環

當 Nginx 剛剛啟動時,在等待事件部分,也就是打開了 80 或 443 端口,這個時候在等待新的事件進來,比如新的客戶端連上了 Nginx 向我們發起了連接,此步往往對應 epoll 的 epoll wait 方法,這個時候的 Nginx 其實是處於 sleep 這樣一個進程狀態的。當操作系統收到了一個建立 TCP 連接的握手報文時並且處理完握手流程以后,操作系統就會通知 epoll wait 這個阻塞方法,告訴它可以往下走了,同時喚醒 Nginx worker 進程。
接着往下走之后,會去找操作系統索要要事件,操作系統會把他准備好的事件,放在事件隊列中,從這個事件隊列中可以獲取到需要處理的事件。比如建立連接或者收到一個 TCP 請求報文。

取出以后就會進行循環處理事件,如上就是處理事件的一個循環:當發現隊列中不為空,就把事件取出來開始處理事件;在處理事件的過程中,可能又生成新的事件,比如說發現一個連接新建立了,可能要添加一個超時時間,比如默認的 60 秒,也就是說 60 秒之內如果瀏覽器不向 Nginx 發送請求的話,Nginx 就會把這個連接關掉;又比如說當 Nginx 發現已經收完了完整的 HTTP 請求以后,可以生成 HTTP 響應了,那么這個生成響應是需要 Nginx 可以向操作系統的寫緩存中心里面去把響應寫進去,要求操作系統盡快的把這樣一段響應內容發到瀏覽器上,也就是說可能在處理過程中可能會產生新的事件,就是循環處理事件部分指向的事件隊列部分,等待下一次來處理。
如果所有的事件都處理完成以后呢,又會返回到等待事件部分。
在學習了 Nginx 事件循環后,我們再去理解,有時候使用一些第三方模塊,這些第三方模塊可能會做大量的 CPU 運算,這樣的計算任務會導致處理一個事件的時間非常的長;在上面的一個流程圖中,可以看到會導致隊列中的大量事件會長時間得不到處理,從而引發惡性循環,也就是他們的超時時間可能到了;大量的 CPU、Nginx 的任務都消耗在處理連接不正常的斷開,所以 Nginx 不能容忍有些第三方模塊長時間的消耗大量的 CPU 進行計算任務就是這樣一個原因。我們可以看到像 GZIP 這樣的模塊,他們都不會在一次使用大量的 CPU 而是分段使用,這些都與 Nginx 的事件循環有關的。
總結
本篇文章主要講解了 Nginx 是如何處理事件的以及 Nginx 事件循環的流程是怎么樣的,為下一步講解 Nginx 事件循環流程中是如何從操作系統中獲取等待處理的事件做鋪墊,並且通過事件循環了解到為什么 Nginx 不期望第三方模塊中出現大量 CPU 的計算任務。
