1. worker進程工作機制
現在我們了解了當我們在操作nginx的時候,nginx內部做的一些事情,那么worker進程又是如何處理請求的呢?
我們前面有提到,worker進程之間是平等的,每個進程,處理請求的機會也是一樣的。
當我們提供80端口的http服務時,一個連接請求過來,每個進程都有可能處理這個連接,怎么做到的呢?
首先,每個worker進程都是從master進程fork過來,在master進程里面,先建立好需要listen的socket(listenfd)之后,這句話的意思就是說master進程會監聽來自客戶端的請求,然后再fork出多個worker進程。且所有worker進程的listenfd會在新連接到來時變得可讀,為了保證只有一個進程處理該連接,所有worker進程在注冊listenfd讀事件前搶accept_mutex ,worker進程處理請求的過程大概如下圖所示:
看圖順序是先看綠色,然后再看藍色,最后看紅色。
綠色部分表示客戶端發送的請求,藍色部分表示master進程管理(fork)的worker進程,紅色部分表示worker進程搶奪accept_mutex,灰色部分表示注冊事件,然后accpet接受連接並處理。
對於nginx的搶占機制來說,當master進程listen到來自client發送的請求時,會讓所有處於空閑狀態的worker進程搶奪accept_mutex ,搶到accept_mutex(互斥鎖)的worker進程注冊listenfd讀事件,然后在讀事件里調用accept接收並處理client的請求。
注意:**所有**處於空閑狀態的worker進程在進行accept接收client的請求之前,都會先對client的accept_mutex鎖進行try_lock嘗試加鎖,需要強調的是這個過程是競爭式的。
另外要明白的一點是,這里為什么是try_lock(嘗試加鎖),而不是lock(加鎖)。
假設是lock的話,除了對client的請求的accept_mutex進行加鎖(lock)成功的worker進程外,其他所有對client的accept_mutex鎖進行lock加鎖的worker進程都會阻塞,除非已經對client請求的accept_mutex加鎖成功的worker進程調用unlock進行解鎖釋放(在解鎖的同時會喚醒阻塞在此accept_mutex的其他所有worker進程),否則其他worker進程會一直阻塞在此處於空閑狀態,這勢必會造成資源浪費。
而如果是try_lock的話,那么其他worker進程對client嘗試加鎖失敗就會立即返回,去處理其他client的請求,因此不會有其他worker進程阻塞在這,也就不會造成資源浪費了。
當一個worker進程對client的accept_mutex加鎖成功,accept這個連接並注冊讀事件,就開始讀取請求,解析請求,處理請求,產生數據后,再返回給客戶端,最后才斷開連接,一個完整的請求就是這樣的了。
2. nginx處理請求過程
nginx使用一個多進程模型來對外提供服務,一個master進程和多個worker進程,master進程負責管理nginx本身和其他worker進程。
所有實際上的業務處理邏輯都在worker進程。worker進程中有一個函數,執行無限循環,不斷處理收到的來自客戶端的請求,並進行處理,直到整個nginx服務被停止。
worker進程中,ngx_worker_process_cycle()函數就是這個無限循環的處理函數。在這個函數中,一個請求的簡單處理流程如下:
操作系統提供的機制(例如epoll, kqueue等)產生相關的事件。
接收和處理這些事件,如是接受到數據,則產生更高層的request對象。
處理request的header和body。
產生響應,處理響應數據並發送回客戶端。
完成request的處理。
重新初始化定時器及其他事件,斷開連接。
---------------------
轉自:https://blog.csdn.net/qq_35733751/article/details/79832005