国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

Nginx 工作原理簡介

這篇具有很好參考價(jià)值的文章主要介紹了Nginx 工作原理簡介。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

在了解Nginx工作原理之前,我們先來了解下幾個(gè)基本的概念 以及常見的I/O模型。

基本概念

  • 同步:就是指調(diào)用方發(fā)起一個(gè)調(diào)用,在沒有得到調(diào)用結(jié)果之前,該調(diào)用不返回。換句話說,也就是調(diào)用方發(fā)起一個(gè)調(diào)用后,一直等待被調(diào)用方返回結(jié)果,直到獲取結(jié)果后才執(zhí)行后續(xù)操作。

    生活中的同步場(chǎng)景:等電梯:

    1. 按電梯方向鍵 --> 用戶發(fā)起一個(gè)調(diào)用
    2. 電梯不在當(dāng)前樓層,不做別的事情,繼續(xù)等待 --> 一直等待結(jié)果
    3. 電梯到了,開門 --> 獲取到結(jié)果
  • 異步:就是指調(diào)用方發(fā)起一個(gè)調(diào)用,在沒得到調(diào)用結(jié)果之前,返回該調(diào)用。換句話說,也就說調(diào)用方發(fā)起一個(gè)調(diào)用后,不等待被調(diào)用方返回結(jié)果,繼續(xù)執(zhí)行后續(xù)操作。這種情況下,被調(diào)用方一般會(huì)在處理完調(diào)用請(qǐng)求后,通過狀態(tài)、通知、或者調(diào)用回調(diào)函數(shù)、接口(由調(diào)用方發(fā)起調(diào)用請(qǐng)求時(shí)按要求提供)來通知調(diào)用方處理結(jié)果。

    生活中的異步場(chǎng)景:使用洗衣機(jī)洗衣服:

    1. 將待洗衣服放進(jìn)洗衣機(jī)
    2. 用戶按開始運(yùn)行按鈕 --> 用戶發(fā)起一個(gè)調(diào)用
    3. 洗衣機(jī)開始洗衣服 --> 調(diào)用方開始處理請(qǐng)求
    4. 用戶去做別的事情,比如打掃衛(wèi)生、煮飯
    5. 洗衣機(jī)洗完衣服,發(fā)出鳴叫聲 --> 通知調(diào)用方處理結(jié)果
  • 阻塞:計(jì)算機(jī)中,主要指進(jìn)程、線程的因?yàn)檎诘却硞€(gè)事件的完成,暫時(shí)不具備運(yùn)行條件而停止運(yùn)行的一種狀態(tài)。也稱為等待狀態(tài)。

    生活中的阻塞場(chǎng)景:交通堵車

    1. 道路寬敞,交通順暢,汽車啟動(dòng),快速行駛 --> 具備運(yùn)行條件,運(yùn)行狀態(tài)
    2. 前方出現(xiàn)堵車,剎車,停止運(yùn)行,等待交通暢順 --> 失去運(yùn)行條件,進(jìn)入阻塞狀態(tài)
    3. 交通順暢,啟動(dòng)汽車,繼續(xù)前行 --> 獲取運(yùn)行條件,恢復(fù)運(yùn)行狀態(tài)。
  • 非阻塞

    阻塞的對(duì)立面,不多解釋。

將以上幾個(gè)概念進(jìn)行組合,便可得到以下概念:

  • 同步阻塞
  • 同步非阻塞
  • 異步非阻塞

總結(jié)

  • 同步和異步關(guān)注的是消息通信機(jī)制,關(guān)注調(diào)用方發(fā)起調(diào)用后是否主動(dòng)等待調(diào)用結(jié)果還是由被動(dòng)等待被調(diào)用方通知。

  • 阻塞和非阻塞關(guān)注的是調(diào)用方在等待調(diào)用結(jié)果時(shí)的狀態(tài)。來看下以下這段話可能更好理解。

    如果發(fā)起一個(gè)同步調(diào)用, 因?yàn)闆]有得到結(jié)果不返回, 那它毫無疑問就是被"阻塞"了(即調(diào)用方處于 “等待” 狀態(tài))。如果調(diào)用發(fā)出了以后就直接返回了, 毫無疑問, 調(diào)用方?jīng)]有被“阻塞”。

    舉個(gè)例子:socket通信。

    我們都知道,socket服務(wù)器進(jìn)程建立監(jiān)聽后,需要執(zhí)行accept調(diào)用,來讀取客戶端建立連接請(qǐng)求,這個(gè)就是一個(gè)同步調(diào)用,此時(shí),如果可以獲取到請(qǐng)求,就會(huì)立即返回(同步非阻塞),但是此時(shí),如果獲取不到連接請(qǐng)求,那么該調(diào)用不會(huì)返回,進(jìn)程會(huì)一直等待(同步阻塞),

常見I/O模型

基礎(chǔ)知識(shí)

內(nèi)核態(tài)/用戶態(tài)

操作系統(tǒng)為了保護(hù)自己,設(shè)計(jì)了用戶態(tài)、內(nèi)核態(tài)兩個(gè)狀態(tài)。應(yīng)用程序一般工作在用戶態(tài),當(dāng)調(diào)用一些底層操作的時(shí)候(比如 I/O 操作),就需要切換到內(nèi)核態(tài)才可以進(jìn)行。

應(yīng)用程序從網(wǎng)絡(luò)中接收數(shù)據(jù)的大致流程

服務(wù)器從網(wǎng)絡(luò)接收的大致流程如下:

  1. 數(shù)據(jù)通過計(jì)算機(jī)網(wǎng)絡(luò)來到了網(wǎng)卡
  2. 把網(wǎng)卡的數(shù)據(jù)讀取到 socket 緩沖區(qū)
  3. 把 socket 緩沖區(qū)讀取到用戶緩沖區(qū),之后應(yīng)用程序就可以使用了

Nginx 工作原理簡介

以兩個(gè)應(yīng)用程序通訊為例,當(dāng)“A”向"B" 發(fā)送一條消息,大致會(huì)經(jīng)過以下流程:

第一步: 應(yīng)用A把消息發(fā)送到 TCP發(fā)送緩沖區(qū)。

第二步: TCP發(fā)送緩沖區(qū)再把消息發(fā)送出去,經(jīng)過網(wǎng)絡(luò)傳遞后,消息會(huì)發(fā)送到B服務(wù)器的TCP接收緩沖區(qū)。

第三步: B再從TCP接收緩沖區(qū)去讀取屬于自己的數(shù)據(jù)。

Nginx 工作原理簡介

因?yàn)閼?yīng)用之間發(fā)送消息是間斷性的,所以,當(dāng)應(yīng)用嘗試從TCP緩沖區(qū)接收數(shù)據(jù)時(shí),并不一定能讀取到數(shù)據(jù),此外,

TCP緩沖區(qū)是有大小限制的,當(dāng)緩沖區(qū)因?yàn)閷懭胨俾蔬^快被“填滿”時(shí),也無法繼續(xù)寫入數(shù)據(jù),這就是為啥會(huì)有I/O阻塞的原因之一(除此之外,數(shù)據(jù)從socket緩沖區(qū)拷貝到用戶空間也是需要時(shí)間的,即也可能造成阻塞)。

I/O類型劃分

根據(jù)是否造成阻塞,可以將I/O類型分成阻塞和非阻塞:

  • 阻塞I/O

    指在進(jìn)行 I/O 操作時(shí),如果數(shù)據(jù)沒有準(zhǔn)備好或無法立即讀取/寫入,程序會(huì)被阻塞(阻塞調(diào)用)等待數(shù)據(jù)準(zhǔn)備好或操作完成,然后才能繼續(xù)執(zhí)行后續(xù)的操作。阻塞 I/O 是一種同步 I/O 操作。

  • 非阻塞IO

    是指在進(jìn)行 I/O 操作時(shí),如果數(shù)據(jù)沒有準(zhǔn)備好或無法立即讀取/寫入,程序會(huì)立即返回,并繼續(xù)執(zhí)行后續(xù)的操作。在非阻塞 I/O 中,程序不會(huì)等待 I/O 操作的完成,而是立即返回,繼續(xù)執(zhí)行其他任務(wù),然后通過輪詢或選擇函數(shù)(如 select、poll、epoll 等)來檢查是否有 I/O 可用。非阻塞 I/O 是一種異步 I/O 操作。

根據(jù)是否同步,可以將I/O類型劃分成同步和異步:

  • 同步IO

    它是指程序在進(jìn)行 I/O 操作時(shí),必須等待 I/O 完成后才能繼續(xù)執(zhí)行后續(xù)的操作。

  • 異步I/O

    是指程序發(fā)起 I/O 請(qǐng)求后進(jìn)行 I/O 操作時(shí),不需要等待 I/O 操作的完成,繼續(xù)執(zhí)行其他任務(wù),是一種非阻塞的 I/O 操作方式。當(dāng) I/O 操作完成后,系統(tǒng)會(huì)通知程序,程序再去獲取或處理完成的 I/O 結(jié)果。

    異步I/O常見的2種實(shí)現(xiàn)方式

    1. callback 回調(diào)函數(shù)

      通過注冊(cè)回調(diào)函數(shù),在 I/O 操作完成時(shí)由操作系統(tǒng)或庫調(diào)用該函數(shù)處理結(jié)果。

    2. 信號(hào)(signal)

      通過使用信號(hào)機(jī)制,在 I/O 操作完成時(shí)由操作系統(tǒng)發(fā)送相應(yīng)的信號(hào)給進(jìn)程,進(jìn)程通過信號(hào)處理函數(shù)來處理 I/O 完成的事件。

接下來,就上圖B應(yīng)用從TCP緩沖區(qū)讀取數(shù)據(jù)為例,來了解下常見的幾種I/O模型。

阻塞型I/O

在應(yīng)用調(diào)用recvfrom讀取數(shù)據(jù)時(shí),其系統(tǒng)調(diào)用直到數(shù)據(jù)包到達(dá)且被復(fù)制到應(yīng)用緩沖區(qū)中或者發(fā)送錯(cuò)誤時(shí)才返回,在此期間一直會(huì)等待,即被阻塞

Nginx 工作原理簡介

非阻塞型I/O

在應(yīng)用調(diào)用recvfrom讀取數(shù)據(jù)時(shí),如果該緩沖區(qū)沒有數(shù)據(jù)的話,系統(tǒng)會(huì)直接返回一個(gè)EWOULDBLOCK錯(cuò)誤,不會(huì)讓應(yīng)用一直等待。

在沒有數(shù)據(jù)的時(shí)候會(huì)即刻返回錯(cuò)誤標(biāo)識(shí),那也意味著如果應(yīng)用要讀取數(shù)據(jù)就需要不斷的調(diào)用recvfrom請(qǐng)求,直到讀取到它數(shù)據(jù)要的數(shù)據(jù)為止。

Nginx 工作原理簡介

復(fù)用型I/O

如果在并發(fā)的環(huán)境下,可能會(huì)N個(gè)人向應(yīng)用B發(fā)送消息,這種情況下我們的應(yīng)用就必須創(chuàng)建多個(gè)線程去讀取數(shù)據(jù),每個(gè)線程都會(huì)自己調(diào)用recvfrom 去讀取數(shù)據(jù)。那么此時(shí)情況可能如下圖:

Nginx 工作原理簡介

如上圖,并發(fā)情況下服務(wù)器很可能一瞬間會(huì)收到幾十上百萬的請(qǐng)求,這種情況下應(yīng)用B就需要?jiǎng)?chuàng)建幾十上百萬的線程去讀取數(shù)據(jù),同時(shí)又因?yàn)閼?yīng)用線程是不知道什么時(shí)候會(huì)有數(shù)據(jù)讀取,為了保證消息能及時(shí)讀取到,那么這些線程自己必須不斷的向內(nèi)核發(fā)送recvfrom 請(qǐng)求來讀取數(shù)據(jù);

那么問題來了,這么多的線程不斷調(diào)用recvfrom 請(qǐng)求數(shù)據(jù),且不說服務(wù)器能不能扛得住這么多線程,就算扛得住那么很明顯這種方式是不是太浪費(fèi)資源了。

所以,有人就提出了一個(gè)思路,能不能提供一種方式,可以由一個(gè)線程監(jiān)控多個(gè)通信socket(每個(gè)socket對(duì)應(yīng)一個(gè)文件描述符fd),這樣就可以只需要一個(gè)或幾個(gè)線程就可以完成數(shù)據(jù)狀態(tài)詢問的操作,當(dāng)有數(shù)據(jù)準(zhǔn)備就緒之后再分配對(duì)應(yīng)的線程去讀取數(shù)據(jù),這么做就可以節(jié)省出大量的線程資源出來,這個(gè)就是I/O復(fù)用模型的思路,如下圖

Nginx 工作原理簡介

進(jìn)程通過將一個(gè)或多個(gè)fd傳遞給select,阻塞在select操作上,select幫我們偵測(cè)多個(gè)fd是否準(zhǔn)備就緒,當(dāng)有fd準(zhǔn)備就緒時(shí),select返回?cái)?shù)據(jù)可讀狀態(tài),應(yīng)用程序再調(diào)用recvfrom讀取數(shù)據(jù)。

Nginx 工作原理簡介

說明:復(fù)用I/O的基本思路就是通過selectpollepoll 來監(jiān)控多fd ,來達(dá)到不必為每個(gè)fd創(chuàng)建一個(gè)對(duì)應(yīng)的監(jiān)控線程,從而減少線程資源創(chuàng)建的目的。

信號(hào)驅(qū)動(dòng)型I/O

復(fù)用I/O模型解決了一個(gè)線程可以監(jiān)控多個(gè)fd的問題,但是select是采用輪詢的方式來監(jiān)控多個(gè)fd的,通過不斷的輪詢fd的可讀狀態(tài)來知道是否有可讀的數(shù)據(jù),而無腦的輪詢就顯得有點(diǎn)暴力,因?yàn)榇蟛糠智闆r下的輪詢都是無效的,所以有人就想,能不能不要我總是去問你是否數(shù)據(jù)準(zhǔn)備就緒,能不能我發(fā)出請(qǐng)求后等你數(shù)據(jù)準(zhǔn)備好了就通知我,所以就衍生了信號(hào)驅(qū)動(dòng)I/O模型。

于是信號(hào)驅(qū)動(dòng)I/O不是用循環(huán)請(qǐng)求詢問的方式去監(jiān)控?cái)?shù)據(jù)就緒狀態(tài),而是在調(diào)用sigaction時(shí)候建立一個(gè)SIGIO的信號(hào)聯(lián)系,當(dāng)內(nèi)核數(shù)據(jù)準(zhǔn)備好之后再通過SIGIO信號(hào)通知線程數(shù)據(jù)準(zhǔn)備好后的可讀狀態(tài),當(dāng)線程收到可讀狀態(tài)的信號(hào)后,此時(shí)再向內(nèi)核發(fā)起recvfrom讀取數(shù)據(jù)的請(qǐng)求,因?yàn)樾盘?hào)驅(qū)動(dòng)I/O的模型下應(yīng)用線程在發(fā)出信號(hào)監(jiān)控后即可返回,不會(huì)阻塞,所以這樣的方式下,一個(gè)應(yīng)用線程也可以同時(shí)監(jiān)控多個(gè)fd,如下圖。

Nginx 工作原理簡介

首先開啟套接口信號(hào)驅(qū)動(dòng)I/O功能,并通過系統(tǒng)調(diào)用sigaction執(zhí)行一個(gè)信號(hào)處理函數(shù),此時(shí)請(qǐng)求即刻返回,當(dāng)數(shù)據(jù)準(zhǔn)備就緒時(shí),就生成對(duì)應(yīng)進(jìn)程的SIGIO信號(hào),通過信號(hào)回調(diào)通知應(yīng)用線程調(diào)用recvfrom來讀取數(shù)據(jù)

Nginx 工作原理簡介

說明:信號(hào)驅(qū)動(dòng) I/O 和多路復(fù)用型I/O的主要區(qū)別在于:信號(hào)驅(qū)動(dòng)型 I/O 的底層實(shí)現(xiàn)機(jī)制是事件通知,而多路復(fù)型用 I/O 的底層實(shí)現(xiàn)機(jī)制是遍歷+回調(diào)

異步I/O

不管是I/O復(fù)用還是信號(hào)驅(qū)動(dòng),要讀取一個(gè)數(shù)據(jù)總是要發(fā)起兩階段的請(qǐng)求,第一次發(fā)送select請(qǐng)求,詢問數(shù)據(jù)狀態(tài)是否準(zhǔn)備好,第二次發(fā)送recevform請(qǐng)求讀取數(shù)據(jù)。

有沒有有一種方式,我只要發(fā)送一個(gè)請(qǐng)求我告訴內(nèi)核我要讀取數(shù)據(jù),然后我就什么都不管了,然后內(nèi)核去幫我去完成剩下的所有事情?

于是有人設(shè)計(jì)了一種方案,應(yīng)用只需要向內(nèi)核發(fā)送一個(gè)read 請(qǐng)求,告訴內(nèi)核它要讀取數(shù)據(jù)后即刻返回;內(nèi)核收到請(qǐng)求后會(huì)建立一個(gè)信號(hào)聯(lián)系,當(dāng)數(shù)據(jù)準(zhǔn)備就緒,內(nèi)核會(huì)主動(dòng)把數(shù)據(jù)從內(nèi)核復(fù)制到用戶空間,等所有操作都完成之后,內(nèi)核會(huì)發(fā)起一個(gè)通知告訴應(yīng)用,我們稱這種模式為異步IO模型。

Nginx 工作原理簡介

Nginx工作原理

眾所周知,Nginx采用多進(jìn)程和異步非阻塞事件驅(qū)動(dòng)模型對(duì)外提供服務(wù)。

多進(jìn)程機(jī)制

生產(chǎn)環(huán)境,Nginx服務(wù)實(shí)現(xiàn)基本采用的都是多進(jìn)程模式:一個(gè)master進(jìn)程和N個(gè)worker進(jìn)程(其中N>=1,雖然可以配置為0,但是沒有意義),每個(gè)worker進(jìn)程只包含一個(gè)主線程,進(jìn)程間通過共享內(nèi)存的方式,來共享緩存數(shù)據(jù)、會(huì)話持久性數(shù)據(jù)等

master 進(jìn)程并不處理網(wǎng)絡(luò)請(qǐng)求,主要用于管理worker進(jìn)程,具體包括以下主要功能:

  1. 接收來自外界的信號(hào)。

  2. 向各worker進(jìn)程發(fā)送信號(hào)。

  3. 監(jiān)控woker進(jìn)程的運(yùn)行狀態(tài)

    當(dāng)worker進(jìn)程因?yàn)槌霈F(xiàn)異常而退出時(shí),自動(dòng)重新啟動(dòng)新的worker進(jìn)程

  4. 停啟用worker進(jìn)程。

    當(dāng)woker進(jìn)程退出后(異常情況下),master會(huì)自動(dòng)啟動(dòng)新的woker進(jìn)程。

而worker 進(jìn)程則負(fù)責(zé)處理網(wǎng)絡(luò)請(qǐng)求與響應(yīng)。每個(gè)請(qǐng)求只會(huì)在一個(gè) worker 進(jìn)程中處理,每個(gè)worker進(jìn)程,只能處理自己接收的請(qǐng)求。

Nginx 在啟動(dòng)時(shí),會(huì)先解析配置文件,得到需要監(jiān)聽的IP地址和端口,然后在 master 進(jìn)程中創(chuàng)建socket,并綁定要監(jiān)聽的IP地址和端口,再執(zhí)行端口監(jiān)聽,接著fork worker進(jìn)程(關(guān)于fork介紹參見下文),由于worker進(jìn)程是由master進(jìn)程fork出來的,所以worker進(jìn)程將繼承master進(jìn)程的socket文件描述符。worker進(jìn)程創(chuàng)建后,都會(huì)執(zhí)行accept等待并提取全連接隊(duì)列中的連接請(qǐng)求。所以,當(dāng)有連接請(qǐng)求時(shí),所有worker進(jìn)程都會(huì)收到通知,并“爭著”與客戶端建立連接,這就是所謂的“驚群現(xiàn)象”。但是由于只有一個(gè)連接請(qǐng)求,所以,同時(shí)只會(huì)有一個(gè)worker進(jìn)程能成功建立連接,并創(chuàng)建已連接描述符,然后通過已連接描述符來與客戶端通信,讀取請(qǐng)求 -> 解析請(qǐng)求 -> 處理請(qǐng)求 -> 返回響應(yīng)給客戶端 ,最后才斷開連接 ,未成功建立連接的請(qǐng)求將再次被掛起。

這就好比你往一群正在睡覺的鴿子中間扔一塊較大的食物,瞬間驚動(dòng)所有的鴿子,然后所有鴿子都去爭搶那塊食物,最終只有一只鴿子搶到食物,沒搶到食物的鴿子回去繼續(xù)睡覺,等待下一塊食物到來。這樣,每扔一塊食物,都會(huì)驚動(dòng)所有的鴿子,即為驚群。

大量的進(jìn)程被激活又掛起,顯然,在請(qǐng)求連接數(shù)量比較低的情況下,這種方式會(huì)比較消耗系統(tǒng)資源。為了避免這種驚群效應(yīng),Nginx提供了一個(gè)accept_mutex指令,將設(shè)置指令值為on,可以確保工作進(jìn)程按序獲取連接。具體實(shí)現(xiàn)其實(shí)是添加了一個(gè)全局互斥鎖,每個(gè)工作進(jìn)程在執(zhí)行accept調(diào)用之前先去申請(qǐng)鎖,申請(qǐng)到則繼續(xù)處理,獲取不到則放棄accept, 這樣就保證了同一時(shí)刻只有一個(gè)work進(jìn)程能accept連接,避免了驚群問題。

Nginx 工作原理簡介

worker進(jìn)程會(huì)競(jìng)爭監(jiān)聽客戶端的連接請(qǐng)求:這種方式可能會(huì)帶來一個(gè)問題,就是可能所有的請(qǐng)求都被一個(gè)worker進(jìn)程給競(jìng)爭獲取了,導(dǎo)致其他進(jìn)程都比較空閑,而某一個(gè)進(jìn)程會(huì)處于忙碌的狀態(tài),這種狀態(tài)可能還會(huì)導(dǎo)致無法及時(shí)響應(yīng)連接而丟棄掉本有能力處理的請(qǐng)求。針對(duì)這種現(xiàn)象,Nginx使用了一個(gè)名為ngx_accept_disabled的變量控制worker進(jìn)程是否去競(jìng)爭獲取accept_mutex鎖。

Nginx代碼(ngx_event_accept.c)實(shí)現(xiàn)中,ngx_accept_disabled被賦值為nginx單個(gè)進(jìn)程的所有連接總數(shù)/8,減去剩余空閑連接數(shù)量,其中,單個(gè)進(jìn)程的所有連接總數(shù)即為nginx.conf里配置的worker_connections值。

ngx_accept_disabled = ngx_cycle->connection_n / 8
                              - ngx_cycle->free_connection_n;

ngx_event.c

void ngx_process_events_and_timers(ngx_cycle_t *cycle)
{
    # 略...
    if (ngx_use_accept_mutex) {
        if (ngx_accept_disabled > 0) {
            ngx_accept_disabled--;

        } else {
            if (ngx_trylock_accept_mutex(cycle) == NGX_ERROR) {
                return;
            }

            if (ngx_accept_mutex_held) {
                flags |= NGX_POST_EVENTS;

            } else {
                if (timer == NGX_TIMER_INFINITE
                    || timer > ngx_accept_mutex_delay)
                {
                    timer = ngx_accept_mutex_delay;
                }
            }
        }
    }

    # ...略
}

由以上代碼可知,當(dāng)且僅當(dāng)剩余連接數(shù)小于總連接數(shù)的八分之一時(shí),ngx_accept_disabled值才大于0。當(dāng)ngx_accept_disabled大于0時(shí),不會(huì)去獲取accept_mutex鎖,也就是等于讓出獲取連接的機(jī)會(huì),很顯然可以看出,當(dāng)空閑連接越少時(shí),ngx_accept_disable越大,于是讓出的機(jī)會(huì)就越多,這樣其它進(jìn)程獲取鎖的機(jī)會(huì)也就越大,就這樣,實(shí)現(xiàn)不同worker之間的負(fù)載均衡。

注意:Nginx 1.11.3版本之前,accept_mutex指令默認(rèn)值為on,1.11.3版本之后默認(rèn)為off,即默認(rèn)關(guān)閉。

支持EPOLLEXCLUSIVE標(biāo)識(shí)的系統(tǒng)(Linux 4.5+,glibc 2.24 )或者listen指令中使用reuseport選項(xiàng)時(shí),不必開啟accept_mutex。

EPOLLEXCLUSIVE說明:

為被附加到目標(biāo)文件描述符fd的epfd文件描述符設(shè)置獨(dú)占喚醒模式。因此,當(dāng)一個(gè)事件發(fā)生,并且多個(gè)epfd文件描述符附加到同一個(gè)使用EPOLLEXCLUSIVE的目標(biāo)文件時(shí),一個(gè)或多個(gè)epfd將收到具有epoll_wait(2)的事件。此場(chǎng)景默認(rèn)(當(dāng)未設(shè)置EPOLLEXCLUSIVE時(shí))所有epfd接收事件。

EPOLLEXCLUSIVE只能與 EPOLL_CTL_ADD操作一起指定。

說明:EPOLLEXCLUSIVE 功能支持的實(shí)現(xiàn)代碼中也用到了ngx_accept_disabled變量,如下

ngx_event.c

static void
ngx_reorder_accept_events(ngx_listening_t *ls)
{
    ngx_connection_t  *c;

    /*
     * Linux with EPOLLEXCLUSIVE usually notifies only the process which
     * was first to add the listening socket to the epoll instance.  As
     * a result most of the connections are handled by the first worker
     * process.  To fix this, we re-add the socket periodically, so other
     * workers will get a chance to accept connections.
     */

    if (!ngx_use_exclusive_accept) {
        return;
    }

#if (NGX_HAVE_REUSEPORT)

    if (ls->reuseport) {
        return;
    }

#endif

    c = ls->connection;

    if (c->requests++ % 16 != 0
        && ngx_accept_disabled <= 0)
    {
        return;
    }

    if (ngx_del_event(c->read, NGX_READ_EVENT, NGX_DISABLE_EVENT)
        == NGX_ERROR)
    {
        return;
    }

    if (ngx_add_event(c->read, NGX_READ_EVENT, NGX_EXCLUSIVE_EVENT)
        == NGX_ERROR)
    {
        return;
    }
}

#endif

reuseport配置示例:

http {
    server {
        listen 80 reuseport
        ...
    }
}

reuseport選項(xiàng)說明

此參數(shù) (Nginx 1.9.1)指示為每個(gè)工作進(jìn)程創(chuàng)建一個(gè)單獨(dú)的偵聽套接字(在Linux 3.9+和DragonFly BSD上使用SO_REUSEPORT套接字選項(xiàng),或在FreeBSD 12+上使用SO_REUSEPORT_LB),允許系統(tǒng)內(nèi)核在工作進(jìn)程之間分配傳入連接。這目前僅適用于Linux 3.9+、DragonFly BSD和FreeBSD 12+(1.15.1)。

fork簡介

什么是fork?fork是復(fù)制進(jìn)程的函數(shù),程序開始運(yùn)行時(shí)會(huì)產(chǎn)生一個(gè)進(jìn)程,當(dāng)這個(gè)進(jìn)程(代碼)執(zhí)行到fork()時(shí),就會(huì)通過復(fù)制當(dāng)前進(jìn)程(包括代碼、數(shù)據(jù)等)來創(chuàng)建一個(gè)新進(jìn)程,我們稱之為子進(jìn)程,而當(dāng)前被復(fù)制的進(jìn)程我們稱之為父進(jìn)程,此時(shí)父子進(jìn)程是共存的,他們一起向下執(zhí)行代碼。除了少部分內(nèi)容(比如進(jìn)程ID),子進(jìn)程和父進(jìn)程幾乎完全相同,可以做完全相同的事情,當(dāng)然,如果初始參數(shù)或者傳入的變量不同,兩個(gè)進(jìn)程也可以做不同的事。

Nginx進(jìn)程模型

Nginx 工作原理簡介

異步非阻塞事件驅(qū)動(dòng)模型

事件驅(qū)動(dòng)模型概述

所謂事件驅(qū)動(dòng)就是指在持續(xù)事務(wù)管理過程中,進(jìn)行決策的一種策略,即根據(jù)當(dāng)前出現(xiàn)的事件,調(diào)動(dòng)可用資源,執(zhí)行相關(guān)任務(wù),使不斷出現(xiàn)的問題得以解決,防止事務(wù)堆積。

在計(jì)算機(jī)編程領(lǐng)域,事件驅(qū)動(dòng)模型對(duì)應(yīng)一種程序設(shè)計(jì)方式,該設(shè)計(jì)的基本結(jié)構(gòu)一般由事件收集器、事件發(fā)送器事件處理器組成。其中,事件收集器專門負(fù)責(zé)收集所有事件,包括來自用戶的(如鼠標(biāo)點(diǎn)擊、鍵盤輸入事件等)、來自硬件的(如時(shí)鐘事件等)和來自軟件的(如操作系統(tǒng)、應(yīng)用程序本身等)。事件發(fā)送器負(fù)責(zé)將收集器收集到的事件分發(fā)到目標(biāo)對(duì)象中。事件處理器做具體的事件響應(yīng)工作。

事件驅(qū)動(dòng)模型一般會(huì)采用這種實(shí)現(xiàn)思路:設(shè)計(jì)一個(gè)事件循環(huán),不斷地檢查目前要處理的事件信息,然后使用事件發(fā)送器將待處理事件傳遞給事件處理器進(jìn)行處理(事件處理器要事先在事件收集器里注冊(cè)自己想要處理的事件)。

Nginx中的事件驅(qū)動(dòng)模型

為什么幾個(gè)worker進(jìn)程能支持高并發(fā)的請(qǐng)求呢?這得益于Nginx采用的異步非阻塞事驅(qū)動(dòng)模型,毫無例外。

對(duì)于傳統(tǒng)的web服務(wù)器(比如Apache)而言,其所采用的事件驅(qū)動(dòng)往往局限于TCP連接建立、關(guān)閉事件上,一個(gè)連接建立以后,在其關(guān)閉之前的所有操作都不再是事件驅(qū)動(dòng),而是退化成順序執(zhí)行每個(gè)操作的批處理模式,這樣每個(gè)請(qǐng)求在連接建立后都將始終占用著系統(tǒng)資源,直到關(guān)閉才會(huì)釋放資源。其事件消費(fèi)者一般是一個(gè)線程、進(jìn)程。

傳統(tǒng)的web服務(wù)器不同,Nginx將一個(gè)請(qǐng)求劃分為多個(gè)階段來異步處理,每個(gè)階段只處理請(qǐng)求的一部分,如果請(qǐng)求的這一部分發(fā)生阻塞,Nginx不會(huì)等待,它會(huì)處理其他請(qǐng)求的某一部分。每個(gè)階段對(duì)應(yīng)不同的事件,都采用事件驅(qū)動(dòng)的方式進(jìn)行處理。整個(gè)執(zhí)行過程中,Nginx不會(huì)為每個(gè)消費(fèi)事件創(chuàng)建一個(gè)進(jìn)程或線程,其事件消費(fèi)者只能是某個(gè)模塊,僅在被調(diào)用時(shí)占用當(dāng)前進(jìn)程資源,這樣避免了由于創(chuàng)建大量線程、進(jìn)程帶來的頻繁上下文切換繁,從而避免過高的CPU資源占用,同時(shí)也降低了對(duì)服務(wù)器其它資源(比如內(nèi)存)的占用。

由于Nginx工作性質(zhì)決定了每個(gè)請(qǐng)求的大部份生命都是在網(wǎng)絡(luò)傳輸中,實(shí)際上花費(fèi)在服務(wù)器自身的時(shí)間片不多,這就是分階段異步處理請(qǐng)求的情況下,為數(shù)不多的進(jìn)程就能解決高并發(fā)的秘密所在。

Nginx支持多種事件驅(qū)動(dòng)模型并在創(chuàng)建worker進(jìn)程時(shí),初始化對(duì)應(yīng)的事件驅(qū)動(dòng)模型,不指定使用特定模型的情況下,如果平臺(tái)支持多種模型,Nginx通常會(huì)自動(dòng)選擇最高效的模型,如果需要,也可以使用use指令顯式指定使用的模型。以下是支持的模型(庫):

  • select -- 標(biāo)準(zhǔn)方法。Nginx編譯過程中如果沒有其他更效率事件驅(qū)動(dòng)模型庫,它將自動(dòng)編譯該庫??梢允褂?code>--with-select_module和--without-select_module兩個(gè)參數(shù)強(qiáng)制啟用或禁用此模塊的構(gòu)建。

  • poll -- 標(biāo)準(zhǔn)方法。Nginx編譯過程中如果沒有其他更效率事件驅(qū)動(dòng)模型庫,它將自動(dòng)編譯該庫??梢允褂?code>--with-poll_module和--without-poll_module兩個(gè)參數(shù)強(qiáng)制啟用或禁用此模塊的構(gòu)建。

  • kqueue — 用于FreeBSD 4.1+, OpenBSD 2.9+, NetBSD 2.0, 和macOS的高效方法。

  • epoll — 用于Linux 2.6+的高效方法

    1.11.3版本開始,支持 EPOLLRDHUP (Linux 2.6.17, glibc 2.8) 和EPOLLEXCLUSIVE (Linux 4.5, glibc 2.24) 標(biāo)識(shí)

    一些舊發(fā)行版本比如SuSE 8.2提供添加epoll支持的補(bǔ)丁到2.4內(nèi)核。

  • /dev/poll — 用于Solaris 7 11/99+, HP/UX 11.22+ (eventport), IRIX 6.5.15+, 和Tru64 UNIX 5.1A+的高效方法。

  • eventport — event port方法用于 Solaris 10+ (推薦使用 /dev/poll 替代該方法)。

select,poll,epoll是較為常見的3種模型,其中epoll最效率,是poll的增強(qiáng)版,是Nginx的默認(rèn)事件驅(qū)動(dòng)模型,也是Nginx能支持高并發(fā)的關(guān)鍵因素。相對(duì)于select、poll來說,具有以下優(yōu)點(diǎn):

  1. 支持一個(gè)進(jìn)程打開最大文件描述符數(shù)量

  2. I/O效率不隨文件描述符數(shù)量的增加而線性下降

    pollselect都是創(chuàng)建一個(gè)待處理事件列表,然后把這個(gè)列表發(fā)給內(nèi)核,返回的時(shí)候,再去輪詢檢查這個(gè)列表。以判斷這個(gè)事件是否發(fā)生。在描述符太多的情況下,效率就明顯低下了。

    epoll則把事件描述符列表的管理交給內(nèi)核。一旦有某個(gè)事件發(fā)生,內(nèi)核將發(fā)生事件的事件描述符交給Nginx的進(jìn)程,而不是將整個(gè)事件描述符列表交給進(jìn)程,讓進(jìn)程去輪詢具體是哪個(gè)描述符。epoll避免了輪詢整個(gè)事件描述符列表,所以效率更高。

  3. 使用mmap加速內(nèi)核與用戶空間的消息傳遞

從流程上來講,epoll模型的使用主要分為三步:

  1. 創(chuàng)建epoll實(shí)例的句柄
  2. 往句柄中添加需要監(jiān)聽的事件文件描述符
  3. 等待需要監(jiān)聽的文件描述符上對(duì)應(yīng)的事件的觸發(fā)。

這里的句柄可以簡單的理解為一個(gè)eventpoll結(jié)構(gòu)體實(shí)例,這個(gè)結(jié)構(gòu)體中有一個(gè)紅黑樹和一個(gè)隊(duì)列,紅黑樹中主要存儲(chǔ)需要監(jiān)聽的文件描述符,而隊(duì)列則是存儲(chǔ)所監(jiān)聽的文件描述符中發(fā)生的目標(biāo)事件。

Nginx每個(gè)worker進(jìn)程都維護(hù)了一個(gè)epoll句柄,在創(chuàng)建完句柄之后,會(huì)通過epoll_ctl()方法,將監(jiān)聽socket對(duì)應(yīng)的文件描述符添加到句柄中(對(duì)應(yīng)eventpoll紅黑樹中的一個(gè)節(jié)點(diǎn))。此外,調(diào)用epoll_ctl()方法添加文件描述符之后,會(huì)將其與相應(yīng)的設(shè)備(網(wǎng)卡)進(jìn)行關(guān)聯(lián),當(dāng)設(shè)備驅(qū)動(dòng)發(fā)生某個(gè)事件時(shí),就會(huì)回調(diào)當(dāng)前文件描述符的回調(diào)方法ep_poll_callback(),生成一個(gè)事件,并且將該事件添加到eventpoll的事件隊(duì)列中。最后,事件循環(huán)中通過調(diào)用epoll_wait()方法從epoll句柄中獲取對(duì)應(yīng)的事件(本質(zhì)就是檢查eventpoll的事件隊(duì)列是否為空,如果有事件則將其返回,否則就會(huì)等待事件的發(fā)生)。這里獲取的事件一般都是accept事件,即接收到客戶端請(qǐng)求,在處理這個(gè)事件的時(shí)候,會(huì)獲取與客戶端通信用的已連接文件描述符,并繼續(xù)通過epoll_ctl()方法將其添加到當(dāng)前的epoll句柄中,繼續(xù)通過epoll_wait()方法等待其數(shù)據(jù)的讀取和寫入事件以接收和發(fā)送數(shù)據(jù)給客戶端。

Nginx熱部署原理

Nginx 工作原理簡介

如上圖,master進(jìn)程充當(dāng)整個(gè)進(jìn)程組與用戶的交互接口,可以通過向master進(jìn)程發(fā)送信號(hào)來實(shí)現(xiàn)相關(guān)操作。比如執(zhí)行kill -HUP masterPID命令,給master進(jìn)程發(fā)送KILL -HUP信號(hào),告訴Nginx,平滑重啟nginx,要求重啟過程中不能中斷服務(wù)。

master進(jìn)程接收到KILL -HUP信號(hào)后會(huì)執(zhí)行以下操作:

  1. 重新加載配置文件
  2. 啟動(dòng)新的worker進(jìn)程,并向所有老的worker進(jìn)程發(fā)送信號(hào),告訴他們可以光榮退休了。
  3. 新的worker在啟動(dòng)后,就開始接收新的請(qǐng)求,而老的worker進(jìn)程在收到來自master的信號(hào)后,不再接收新的請(qǐng)求,并繼續(xù)處理當(dāng)前進(jìn)程已接收的請(qǐng)求直至所有請(qǐng)求處理完成,最后退出。

Nginx 工作原理簡介

直接給master進(jìn)程發(fā)送信號(hào),這是比較傳統(tǒng)的操作方式,Nginx 0.8本之后,引入了一系列命令行參數(shù),來方便我們管理Nginx。比如,nginx -s reload,平滑重啟nginx,nginx -s stop,停止運(yùn)行Nginx。命令本質(zhì)也是給master進(jìn)程發(fā)送信號(hào)。

KILL -HUP簡介

在Linux中,Kill 命令用于發(fā)送信號(hào)給進(jìn)程,其中SIGHUP代表Hangup,在UNIX系統(tǒng)中,這個(gè)信號(hào)通常被用來重新讀配置文件,而對(duì)于一些進(jìn)程而言,重新讀取配置文件之后,它們會(huì)嘗試將自己的行為變?yōu)槟J(rèn)行為,而不需要重啟或重載。

Kill -HUP,簡單理解就是發(fā)送給進(jìn)程的一種信號(hào),它能夠讓進(jìn)程重讀它的配置文件并且重新打開它的日志文件。在發(fā)送Kill -HUP信號(hào)時(shí),操作系統(tǒng)會(huì)把SIGHUP信號(hào)發(fā)送到進(jìn)程表,然后內(nèi)核會(huì)從內(nèi)核級(jí)別的進(jìn)程表中查找那些進(jìn)程已經(jīng)注冊(cè)了SIGHUP信號(hào)。如果它們對(duì)SIGHUP信號(hào)進(jìn)行了處理或者忽略了該信號(hào),則不做處理,否則內(nèi)核就會(huì)把SIGHUP信號(hào)發(fā)送給進(jìn)程。

當(dāng)某個(gè)進(jìn)程接收到SIGHUP信號(hào)后,它會(huì)根據(jù)自己的處理方式來處理該信號(hào),通常包括:如果進(jìn)程正在運(yùn)行,則進(jìn)程暫停,然后運(yùn)行信號(hào)處理程序;如果進(jìn)程處于休眠狀態(tài),則先喚醒進(jìn)程,再運(yùn)行信號(hào)處理程序文章來源地址http://www.zghlxwxcb.cn/news/detail-760517.html

到了這里,關(guān)于Nginx 工作原理簡介的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • android remount 工作原理簡介

    android remount 工作原理簡介

    ????????android remount 在調(diào)試android 系統(tǒng)的時(shí)候是個(gè)非常有用的調(diào)試手段, 有remount 的幫助, 可以輕松的修改系統(tǒng)分區(qū)的某些文件,或者在系統(tǒng)分區(qū)添加刪除文件。但有時(shí)候remount 也會(huì)因?yàn)橐恍﹙erity, checkpoint ,和remount 自身的一些原因不能正常工作。最近因?yàn)楣ぷ髟?,?duì)

    2024年02月09日
    瀏覽(20)
  • FPGA簡介、工作原理、優(yōu)勢(shì)與劣勢(shì)

    目錄 一、FPGA簡介 二、FPGA工作原理 三、FPGA的優(yōu)勢(shì)與劣勢(shì) FPGA(Field-Programmable Gate Array)是一種基于可編程邏輯門陣列(PLA)和可編程交叉開關(guān)(PCS)的可編程邏輯器件。與傳統(tǒng)的ASIC(Application-Specific Integrated Circuit)相比,F(xiàn)PGA具有更高的靈活性和可重構(gòu)性。FP

    2024年02月13日
    瀏覽(27)
  • 一文了解什么什么是加密貨幣及其工作原理

    一文了解什么什么是加密貨幣及其工作原理

    加密貨幣是基于區(qū)塊鏈技術(shù)并由密碼學(xué)保護(hù)的去中心化數(shù)字貨幣。要理解加密貨幣,首先需要理解三個(gè)術(shù)語——區(qū)塊鏈、去中心化和密碼學(xué)。 ? 一、加密貨幣如何運(yùn)作 簡而言之,加密貨幣中的區(qū)塊鏈?zhǔn)且环N數(shù)字分類賬,其訪問權(quán)限分布在授權(quán)用戶之間。該分類賬記錄了與一

    2024年01月23日
    瀏覽(19)
  • 一文了解大模型工作原理——以ChatGPT為例

    一文了解大模型工作原理——以ChatGPT為例

    2022年11月30日,ChatGPT模型問世后,立刻在全球范圍內(nèi)掀起了軒然大波。無論AI從業(yè)者還是非從業(yè)者,都在熱議ChatGPT極具沖擊力的交互體驗(yàn)和驚人的生成內(nèi)容。這使得廣大群眾重新認(rèn)識(shí)到人工智能的潛力和價(jià)值。對(duì)于AI從業(yè)者來說,ChatGPT模型成為一種思路的擴(kuò)充,大模型不再是

    2024年02月09日
    瀏覽(28)
  • Nginx工作原理

    本文分享自天翼云開發(fā)者社區(qū)《Nginx工作原理》,作者:王****秀 Nginx的進(jìn)程模型 Nginx服務(wù)器由一個(gè)Master進(jìn)程和多個(gè)Worker進(jìn)程組成: Master進(jìn)程:管理Worker進(jìn)程。對(duì)外接口:接收外部的操作(信號(hào));對(duì)內(nèi)轉(zhuǎn)發(fā):根據(jù)外部操作的不同,通過信號(hào)管理Worker;監(jiān)聽:監(jiān)控Worker進(jìn)程的運(yùn)

    2024年02月08日
    瀏覽(15)
  • 集群、負(fù)載均衡集群、高可用集群簡介,LVS工作結(jié)構(gòu)、工作模式、調(diào)度算法和haproxy/nginx模式拓?fù)浣榻B

    集群、負(fù)載均衡集群、高可用集群簡介,LVS工作結(jié)構(gòu)、工作模式、調(diào)度算法和haproxy/nginx模式拓?fù)浣榻B

    目錄 一.集群的定義 1.定義 2.分類 (1)負(fù)載均衡集群(LBC/LB) (2)高可用集群(HAC) 二.使用集群的意義 1.高性價(jià)比和性能比 2.高可用性 3.可伸縮性強(qiáng) 4.持久和透明性高 三.常見的兩種集群模式拓?fù)?1.LVS(-DR)集群模式 (1)工作架構(gòu) (2)LVS下的相關(guān)術(shù)語 (3)LVS的工作模式

    2024年02月13日
    瀏覽(18)
  • 一篇文章帶你了解-selenium工作原理詳解

    一篇文章帶你了解-selenium工作原理詳解

    前言 Selenium是一個(gè)用于Web應(yīng)用程序自動(dòng)化測(cè)試工具。Selenium測(cè)試直接運(yùn)行在瀏覽器中,就像真正的用戶在操作一樣。支持的瀏覽器包括IE(7, 8, 9, 10, 11),Mozilla Firefox,Safari,Google Chrome,Opera等。 主要功能包括:測(cè)試與瀏覽器的兼容性——測(cè)試你的應(yīng)用程序看是否能夠很好得

    2024年02月10日
    瀏覽(26)
  • PCIe簡介/體系架構(gòu)/工作原理/資源分配/錯(cuò)誤定位

    目錄 一、PCIe簡介 二、體系結(jié)構(gòu) 三、層次結(jié)構(gòu) 四、工作原理 五、不同版本及傳輸速率、吞吐量 六、資源分配 ID資源 PCIe資源分配原理 七、Lane和Link PCIe插槽 八、MSI和MSI-X 九、SR-IOV 十、AER 十一、lspci命令 PCIe(Peripheral Component Interconnect Express)是一種用于連接計(jì)算機(jī)內(nèi)部硬件

    2024年02月16日
    瀏覽(30)
  • nginx基礎(chǔ)1——工作原理、安裝配置、命令參數(shù)

    nginx基礎(chǔ)1——工作原理、安裝配置、命令參數(shù)

    nginx簡介: nginx是一款輕量級(jí)的Web服務(wù)器、反向代理服務(wù)器及電子郵件(IMAP/POP3)代理服務(wù)器,并在一個(gè)BSD-like協(xié)議下發(fā)行。 nginx由俄羅斯的程序設(shè)計(jì)師Igor Sysoev所開發(fā),最初供俄國大型的入口網(wǎng)站及搜尋引擎Rambler使用。 nginx第一個(gè)公開版本0.1.0發(fā)布于2004年10月4日。其將源代碼

    2024年02月16日
    瀏覽(18)
  • “深入剖析JVM內(nèi)部機(jī)制:了解Java虛擬機(jī)的工作原理“

    標(biāo)題:深入剖析JVM內(nèi)部機(jī)制:了解Java虛擬機(jī)的工作原理 摘要:本文將深入剖析JVM內(nèi)部機(jī)制,詳細(xì)介紹Java虛擬機(jī)的工作原理。我們將探討JVM的組成部分、類加載過程、內(nèi)存管理、垃圾回收以及即時(shí)編譯等關(guān)鍵概念。此外,還將提供示例代碼來幫助讀者更好地理解JVM的內(nèi)部機(jī)制

    2024年02月11日
    瀏覽(29)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包