直接上圖
Master-Worker模式
1、Nginx 在啟動后,會有一個 master 進程和多個相互獨立的 worker 進程。
2、接收來自外界的信號,向各worker進程發送信號,每個進程都有可能來處理這個連接。
3、Master進程能監控Worker進程的運行狀態,當 worker 進程退出后(異常情況下),會自動啟動新的 worker 進程。
accept_mutex
由於所有子進程都繼承了父進程的 sockfd,那么當連接進來時,所有子進程都將收到通知並“爭着”與它建立連接,這就叫“驚群現象”。大量的進程被激活又掛起,只有一個進程可以accept() 到這個連接,這當然會消耗系統資源。Nginx 提供了一個 accept_mutex 這個東西,這是一個加在accept上的一把共享鎖。即每個 worker 進程在執行 accept 之前都需要先獲取鎖,獲取不到就放棄執行 accept()。有了這把鎖之后,同一時刻,就只會有一個進程去 accpet(),這樣就不會有驚群問題了。
當一個 worker 進程在 accept() 這個連接之后,就開始讀取請求,解析請求,處理請求,產生數據后,再返回給客戶端,最后才斷開連接,完成一個完整的請求。一個請求,完全由 worker 進程來處理,而且只能在一個 worker 進程中處理。
用進程而不用線程的好處
1、節省鎖帶來的開銷。每個 worker 進程都是獨立的進程,不共享資源,不需要加鎖。同時在編程以及問題查上時,也會方便很多。
2、獨立進程,減少風險。采用獨立的進程,可以讓互相之間不會影響,一個進程退出后,其它進程還在工作,服務不會中斷,master 進程則很快重新啟動新的 worker 進程。當然,worker 進程的也能發生意外退出。
IO多路復用
對於Nginx來講,一個進程只有一個主線程,那么它是怎么實現高並發的呢
采用了IO多路復用的原理,通過異步非阻塞的事件處理機制,( IO多路復用的三種機制Select,Poll,Epoll)里的 epoll模型,實現了輕量級和高並發。
nginx是如何具體實現的呢,簡單來說:每進來一個request,會有一個worker進程去處理。但不是全程的處理,處理到什么程度呢?處理到可能發生阻塞的地方,比如向上游(后端)服務器轉發request,並等待請求返回。那么,這個處理的worker不會這么傻等着,他會在發送完請求后,注冊一個事件:“如果upstream返回了,告訴我一聲,我再接着干”。於是他就休息去了。此時,如果再有request 進來,他就可以很快再按這種方式處理。而一旦上游服務器返回了,就會觸發這個事件,worker才會來接手,這個request才會接着往下走。由於web server的工作性質決定了每個request的大部份生命都是在網絡傳輸中,實際上花費在server機器上的時間片不多,這就是幾個進程就能解決高並發的秘密所在