一,Nginx是異步非阻塞多進程,io多路復用
1、master進程:管理進程
master進程主要用來管理worker進程,具體包括如下4個主要功能: (1)接收來自外界的信號。 (2)向各worker進程發送信號。 (3)監控woker進程的運行狀態。 (4)當woker進程退出后(異常情況下),會自動重新啟動新的woker進程。
2、worker進程:處理請求
而基本的網絡事件,則是放在worker進程中來處理了。多個worker進程之間是對等的,他們同等競爭來自客戶端的請求,各進程互相之間是獨立的。一個請求,只可能在一個worker進程中處理,一個worker進程,不可能處理其它進程的請求。worker進程的個數是可以設置的,一般我們會設置與機器cpu核數一致,這里面的原因與nginx的進程模型以及事件處理模型是分不開的。
worker進程之間是平等的,每個進程,處理請求的機會也是一樣的。當我們提供80端口的http服務時,一個連接請求過來,每個進程都有可能處理這個連接,怎么做到的呢?
Nginx采用異步非阻塞的方式來處理網絡事件,類似于Libevent,具體過程如下:
1)接收請求:首先,每個worker進程都是從master進程fork過來,在master進程建立好需要listen的socket(listenfd)之后,然后再fork出多個worker進程。所有worker進程的listenfd會在新連接到來時變得可讀,每個work進程都可以去accept這個socket(listenfd)。當一個client連接到來時,所有accept的work進程都會受到通知,但只有一個進程可以accept成功,其它的則會accept失敗。
2)處理請求:當一個worker進程在accept這個連接之后,就開始讀取請求,解析請求,處理請求,產生數據后,再返回給客戶端,最后才斷開連接,這樣一個完整的請求就是這樣的了
我們可以看到,一個請求,完全由worker進程來處理,而且只在一個worker進程中處理。worker進程之間是平等的,每個進程,處理請求的機會也是一樣的。
雖然nginx采用多worker的方式來處理請求,每個worker里面只有一個主線程,那能夠處理的并發數很有限啊,多少個worker就能處理多少個并發,何來高并發呢?非也,這就是nginx的高明之處,nginx采用了異步非阻塞的方式來處理請求,也就是說,nginx是可以同時處理成千上萬個請求的。一個worker進程可以同時處理的請求數只受限于內存大小,Worker 進程 不再同步阻塞的去處理一個請求,而是可以同時處理多個請求,無需 I/O 等待。請求r1-1,r1-2,r1-2都再在woker1進程中,如果r1-1發生阻塞需要等待,worker1就會去處理r1-2,等到r1-1處理好了由事件通知再將結果返回。
二,php-fpm是阻塞式單線程模型
- 客戶端發送的請求到達nginx后nginx會解析后轉發給php-fpm進程管理器
- php-fpm在master進程中創建多個work進程,調用一個work進程處理php代碼。有請求到達work后阻塞在fcgi_accept_request()上,各自accept請求然后處理,這期間是不會接收其他請求的,也就是說work進程同時只能響應一個請求,只有把這個請求處理完了才會處理下一個。
- 如果所有的work都處于忙碌狀態(阻塞),那么這些請求就會阻塞在master進程上。
- 所有work均是搶占模式來處理請求。
- 搶占模式:每個進程都可以得到一定CPU時間片的時間處理,時間片結束或是進程發生阻塞(數據庫連接、網絡請求I/O(如發送短信、郵件第三方接口)、讀寫文件、sleep等待)就會觸發上下文切換,CPU會經由調度程序去處理下一個進程的內容。等待阻塞結束再將進程由阻塞態加入就緒態隊列(此時的進程處于就緒隊列高等級),等待cpu調度執行。
- php從代碼級別的執行上是單線程的, 但是由php-fpm進程管理機制是多進程單線程的, 也就是php是多進程執行的. 有效提高并發的響應效率。