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


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

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資源,從而帶來不必要的上下文切換
參考 http://tengine.taobao.org/book/chapter_2.html#connection 初探Nginx架構
=======================================================================================================

Nginx比較Apache:事件驅動適合於IO密集型服務,多進程或線程適合於CPU密集型服務

1)Nginx更主要是作為反向代理,而非Web服務器使用。其網絡模式是事件驅動(select、poll、epoll)。
2)事件驅動的本質還是IO事件,應用程序在多個IO句柄間快速切換,實現所謂的異步IO。
3)事件驅動服務器,最適合做的就是這種IO密集型工作,如反向代理,它在客戶端與WEB服務器之間起一個數據中轉作用,純粹是IO操作,自身並不涉及到復雜計算。
4)反向代理用事件驅動來做,顯然更好,一個工作進程就可以run了,沒有進程、線程管理的開銷,CPU、內存消耗都小。
5)當然,Nginx也可以是多進程 + 事件驅動的模式,幾個進程跑libevent,不需要Apache那樣動輒數百的進程數。
6)Nginx處理靜態文件效果也很好,那是因為靜態文件本身也是磁盤IO操作,處理過程一樣。至於說多少萬的並發連接,這個毫無意義。我隨手寫個網絡程序都能處理幾萬7)的並發,但如果大部分客戶端阻塞在那里,就沒什么價值。

再看看Apache或者Resin這類應用服務器,之所以稱他們為應用服務器,是因為他們真的要跑具體的業務應用,如科學計算、圖形圖像、數據庫讀寫等。它們很可能是CPU密集型的服務,事件驅動並不合適。

1)例如一個計算耗時2秒,那么這2秒就是完全阻塞的,什么event都沒用。想想MySQL如果改成事件驅動會怎么樣,一個大型的join或sort就會阻塞住所有客戶端。
2)這個時候多進程或線程就體現出優勢,每個進程各干各的事,互不阻塞和干擾。當然,現代CPU越來越快,單個計算阻塞的時間可能很小,但只要有阻塞,事件編程就毫無優勢。所以進程、線程這類技術,並不會消失,而是與事件機制相輔相成,長期存在。
總結之,事件驅動適合於IO密集型服務,多進程或線程適合於CPU密集型服務,它們各有各的優勢,並不存在誰取代誰的傾向。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM