1. 程式人生 > >Nginx 究竟如何處理事件?

Nginx 究竟如何處理事件?

在瞭解了網路事件以及事件分發收集器以後,讓我們來了解 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 的計算任務