nginx是以多程式的方式來工作的

亮子zl發表於2016-10-04

http://blog.csdn.net/xxb2008/article/details/42238557

nginx是以多程式的方式來工作的。

nginx在啟動後,會有一個master程式和多個worker程式。




master程式主要用來管理worker程式:
包含:
1、接收來自外界的訊號,向各worker程式傳送訊號。
2、監控worker程式的執行狀態,當worker程式退出後(異常情況下),會自動重新啟動新的worker程式。


而基本的網路事件,則是放在worker程式中來處理了。worker程式之間是對等的,一個請求,只可能在一個worker程式中處理,一個worker程式,不可能處理其它程式的請求。
worker程式的個數,一般會設定與機器cpu核數一致。當我們提供80埠的http服務時,一個連線請求過來,每個程式都有可能處理這個連線。




處理過程如下:
master(master程式會先建立好需要listen的socket)--------fork生成子程式workers,繼承socket(此時workers子程式們都繼承了父程式master的所有屬性,當然也包括已經
建立好的socket,當然不是同一個socket,只是每個程式的這個socket會監控在同一個ip地址與埠,這個在網路協議裡面是允許的)------當一個連線進入,產生驚群現象。
一般來說,當一個連線進來後,所有在accept在這個socket上面的程式,都會收到通知,而只有一個程式可以accept這個連線,其它的則accept失敗。




驚群現象:指一個fd的事件被觸發後,等候這個fd的所有執行緒/程式都被喚醒。雖然都被喚醒,但是隻有一個會去響應。最常見的例子就是對於socket的accept操作,當多個
使用者程式/執行緒監聽在同一個埠上時,由於實際只可能accept一次,因此就會產生驚群現象,




Nginx對驚群現象的處理:
     nginx提供了一個accept_mutex這個東西,這是一個加在accept上的一把共享鎖。有了這把鎖之後,同一時刻,就只會有一個程式在accpet連線,這樣
就不會有驚群問題了。accept_mutex是一個可控選項,我們可以顯示地關掉,預設是開啟的。




worker程式工作:

     當一個worker程式在accept這個連線之後,就開始讀取請求,解析請求,處理請求,產生資料後,再返回給客戶端,最後才斷開連線,一個完整的請求。一個請求,完全由
worker程式來處理,而且只在一個worker程式中處理。


小結:
1)一個完整的請求讀取請求、解析請求、處理請求,產生資料後,再返回給客戶端,最後斷開連線。
2)一個完整的請求完全由一個worker程式處理。


好處:
     1)節省鎖帶來的開銷。每個worker程式都是獨立的程式,不共享資源,不需要加鎖。同時在程式設計以及問題查上時,也會方便很多。
     2)獨立程式,減少風險。採用獨立的程式,可以讓互相之間不會影響,一個程式退出後,其它程式還在工作,服務不會中斷,master程式則很快重新啟動新的worker程式。當然,worker程式的異常退出,肯定是程式有bug了,異常退出,會導致當前worker上的所有請求失敗,不過不會影響到所有請求,所以降低了風險。


Nginx的事件處理機制


       對於一個基本的web伺服器來說,事件通常有三種型別:網路事件、訊號、定時器。Nginx採用非同步非阻塞的事件處理機制,由程式迴圈處理多個準備好的事件,從而實現

高併發和輕量級。


        以epoll為例:當事件沒有準備好時,就放入epoll裡面。如果有事件準備好了,那麼就去處理;如果事件返回的是EAGAIN,那麼繼續將其放入epoll裡面。從而,只要有事件準備好了,我們就去處理她,只有當所有時間都沒有準備好時,才在epoll裡面等著。這樣,我們就可以併發處理大量的併發了,當然,這裡的併發請求,是指未處理完的請求,執行緒只有一個,所以同時能處理的請求當然只有一個了,只是在請求間進行不斷地切換而已,切換也是因為非同步事件未準備好,而主動讓出的。這裡的切換是沒有任何代價,你可以理解為迴圈處理多個準備好的事件,事實上就是這樣的。




問題1: Nginx採用worker程式來處理請求,一個worker程式只有一個主執行緒,那麼有多少個worker子程式就能處理多少個併發,那麼能夠處理的併發數有限。概括的講,Nginx如何實現高併發?
        回答1:採用非同步非阻塞的事件處理機制。之所以能夠併發處理大量的未處理完的請求,是通過非同步非阻塞方式,由程式迴圈處理多個準備好的事件。以epoll為例,為準備好的事件都會放入epoll中,只要有事件準備好,就會進行處理。                   


問題2:何為非同步非阻塞方式
        回答2:http://www.ibm.com/developerworks/cn/linux/l-async/


問題3:Nginx與Apache對於高併發處理上的區別。
        回答3:對於Apache,每個請求都會獨佔一個工作執行緒,當併發數到達幾千時,就同時有幾千的執行緒在處理請求了。這對於作業系統來說,佔用的記憶體非常大,執行緒的上下文切換帶來的cpu開銷也很大,效能就難以上去,同時這些開銷是完全沒有意義的。

     對於Nginx來講,一個程式只有一個主執行緒,通過非同步非阻塞的事件處理機制,實現了迴圈處理多個準備好的事件,從而實現輕量級和高併發。


問題4:為何推薦worker的個數為cpu的個數?
        回答4:因為更多的worker數,只會導致程式相互競爭cpu資源,從而帶來不必要的上下文切換

相關文章