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

事件驅(qū)動(dòng)并不是計(jì)算機(jī)編程領(lǐng)域的專業(yè)詞匯,它是一種比較古老的響應(yīng)事件的模型,在計(jì)算機(jī)編程、公共關(guān)系、經(jīng)濟(jì)活動(dòng)等領(lǐng)域均有很廣泛的應(yīng)用。顧名思義,事件驅(qū)動(dòng)就是在持續(xù)事務(wù)管理過程中,由當(dāng)前時(shí)間點(diǎn)上出現(xiàn)的事件引發(fā)的調(diào)動(dòng)可用資源執(zhí)行相關(guān)任務(wù),解決不斷出現(xiàn)的問題,防止事務(wù)堆積的一種策略。在計(jì)算機(jī)編程領(lǐng)域,事件驅(qū)動(dòng)模型對(duì)應(yīng)一種程序設(shè)計(jì)方式,Event-driven programming,即事件驅(qū)動(dòng)程序設(shè)計(jì)。

Nginx服務(wù)器響應(yīng)和處理Web請(qǐng)求的過程,就是基于事件驅(qū)動(dòng)模型的,它也包含事件收集器、事件發(fā)送器和事件處理器等三部分基本單元。通過上面的內(nèi)容,大家應(yīng)該已經(jīng)了解了事件驅(qū)動(dòng)模型的基本概念。那么,Nginx服務(wù)器是如何使用事件驅(qū)動(dòng)模型來工作的呢?它的“事件收集器”和“事件發(fā)送器”的實(shí)現(xiàn)沒有太大的特點(diǎn),我們重點(diǎn)介紹一下它的“事件處理器”。

通常,我們?cè)诰帉懛?wù)器處理模型的程序時(shí),基于事件驅(qū)動(dòng)模型,“目標(biāo)對(duì)象”中的“事件處理器”可以有以下幾種實(shí)現(xiàn)辦法:

  • “事件發(fā)送器”每傳遞過來一個(gè)請(qǐng)求,“目標(biāo)對(duì)象”就創(chuàng)建一個(gè)新的進(jìn)程,調(diào)用“事件處理器”來處理該請(qǐng)求。
  • “事件發(fā)送器”每傳遞過來一個(gè)請(qǐng)求,“目標(biāo)對(duì)象”就創(chuàng)建一個(gè)新的線程,調(diào)用“事件處理器”來處理該請(qǐng)求。
  • “事件發(fā)送器”每傳遞過來一個(gè)請(qǐng)求,“目標(biāo)對(duì)象”就將其放入一個(gè)待處理事件的列表,使用非阻塞I/O方式調(diào)用“事件處理器”來處理該請(qǐng)求。

上面的三種處理方式,各有特點(diǎn),第一種方式,由于創(chuàng)建新的進(jìn)程的開銷比較大,會(huì)導(dǎo)致服務(wù)器性能比較差,但其實(shí)現(xiàn)相對(duì)來說比較簡(jiǎn)單;第二種方式,由于要涉及到線程的同步,故可能會(huì)面臨死鎖、同步等一系列問題,編碼比較復(fù)雜;第三種方式,在編寫程序代碼時(shí),邏輯比前面兩種都復(fù)雜。大多數(shù)網(wǎng)絡(luò)服務(wù)器采用了第三種方式,逐漸形成了所謂的“事件驅(qū)動(dòng)處理庫”。

事件驅(qū)動(dòng)處理庫又被稱為多路IO復(fù)用方法,最常見的包括以下三種:select模型、poll模型和epoll模型。Nginx服務(wù)器還支持rtsig模型、kqueue模型、dev/poll模型和eventport模型等。通過Nginx配置可以使得Nginx服務(wù)器支持這幾種事件驅(qū)動(dòng)處理模型。

select庫

select庫,是各個(gè)版本的Linux和Windows平臺(tái)都支持的基本事件驅(qū)動(dòng)模型庫,并且在接口的定義上也基本相同,只是部分參數(shù)的含義略有差異。使用select庫的步驟一般是:

首先,創(chuàng)建所關(guān)注事件的描述符集合。對(duì)于一個(gè)描述符,可以關(guān)注其上面的讀(Read)事件、寫(Write)事件以及異常發(fā)生(Exception)事件,所以要?jiǎng)?chuàng)建三類事件描述符集合,分別用來收集讀事件的描述符、寫事件的描述符和異常事件的描述符。
其次,調(diào)用底層提供的select()函數(shù),等待事件發(fā)生。這里需要注意的一點(diǎn)是,select的阻塞與是否設(shè)置非阻塞I/O是沒有關(guān)系的。
然后,輪詢所有事件描述符集合中的每一個(gè)事件描述符,檢查是否有相應(yīng)的事件發(fā)生,如果有,就進(jìn)行處理。
Nginx服務(wù)器在編譯過程中如果沒有為其指定其他高性能事件驅(qū)動(dòng)模型庫,它將自動(dòng)編譯該庫。我們可以使用--with-select_module和--without-select_module兩個(gè)參數(shù)強(qiáng)制Nginx是否編譯該庫。

poll庫

poll庫,作為L(zhǎng)inux平臺(tái)上的基本事件驅(qū)動(dòng)模型,是在Linux 2.1.23中引入的。Windows平臺(tái)不支持poll庫。

poll與select的基本工作方式是相同的,都是先創(chuàng)建一個(gè)關(guān)注事件的描述符集合,再去等待這些事件發(fā)生,然后再輪詢描述符集合,檢查有沒有事件發(fā)生,如果有,就進(jìn)行處理。

poll庫與select庫的主要區(qū)別在于,select庫需要為讀事件、寫事件和異常事件分別創(chuàng)建一個(gè)描述符集合,因此在最后輪詢的時(shí)候,需要分別輪詢這三個(gè)集合。而poll庫只需要?jiǎng)?chuàng)建一個(gè)集合,在每個(gè)描述符對(duì)應(yīng)的結(jié)構(gòu)上分別設(shè)置讀事件、寫事件或者異常事件,最后輪詢的時(shí)候,可以同時(shí)檢查這三種事件是否發(fā)生??梢哉f,poll庫是select庫的優(yōu)化實(shí)現(xiàn)。

Nginx服務(wù)器在編譯過程中如果沒有為其指定其他高性能事件驅(qū)動(dòng)模型庫,它將自動(dòng)編譯該庫。我們可以使用--with-poll_module和--without-poll_module兩個(gè)參數(shù)強(qiáng)制Nginx是否編譯該庫。

epoll庫

epoll庫是Nginx服務(wù)器支持的高性能事件驅(qū)動(dòng)庫之一,它是公認(rèn)的非常優(yōu)秀的事件驅(qū)動(dòng)模型,和poll庫及select庫有很大的不同。epoll屬于poll庫的一個(gè)變種,是在Linux 2.5.44中引入的,在Linux 2.6及以上的版本都可以使用它。poll庫和select庫在實(shí)際工作中,最大的區(qū)別在于效率。

從前面的介紹我們知道,它們的處理方式都是創(chuàng)建一個(gè)待處理事件列表,然后把這個(gè)列表發(fā)給內(nèi)核,返回的時(shí)候,再去輪詢檢查這個(gè)列表,以判斷事件是否發(fā)生。這樣在描述符比較多的應(yīng)用中,效率就顯得比較低下了。一種比較好的做法是,把描述符列表的管理交由內(nèi)核負(fù)責(zé),一旦有某種事件發(fā)生,內(nèi)核把發(fā)生事件的描述符列表通知給進(jìn)程,這樣就避免了輪詢整個(gè)描述符列表。epoll庫就是這樣一種模型。

首先,epoll庫通過相關(guān)調(diào)用通知內(nèi)核創(chuàng)建一個(gè)有N個(gè)描述符的事件列表;然后,給這些描述符設(shè)置所關(guān)注的事件,并把它添加到內(nèi)核的事件列表中去,在具體的編碼過程中也可以通過相關(guān)調(diào)用對(duì)事件列表中的描述符進(jìn)行修改和刪除。

完成設(shè)置之后,epoll庫就開始等待內(nèi)核通知事件發(fā)生了。某一事件發(fā)生后,內(nèi)核將發(fā)生事件的描述符列表上報(bào)給epoll庫。得到事件列表的epoll庫,就可以進(jìn)行事件處理了。

epoll庫在Linux平臺(tái)上是高效的。它支持一個(gè)進(jìn)程打開大數(shù)目的事件描述符,上限是系統(tǒng)可以打開文件的最大數(shù)目;同時(shí),epoll庫的IO效率不隨描述符數(shù)目增加而線性下降,因?yàn)樗粫?huì)對(duì)內(nèi)核上報(bào)的“活躍”的描述符進(jìn)行操作。

rtsig模型

rtsig是Real-Time Signal的縮寫,是實(shí)時(shí)信號(hào)的意思。從嚴(yán)格意義上說,rtsig模型并不是常用的事件驅(qū)動(dòng)模型,但Nginx服務(wù)器提供了使用實(shí)時(shí)信號(hào)對(duì)事件進(jìn)行響應(yīng)的支持,官方文檔中將rtsig模型與其他的事件驅(qū)動(dòng)模型并列,rtsig模型在Linux 2.2.19及以上的版本中可以使用。

使用rtsig模型時(shí),工作進(jìn)程會(huì)通過系統(tǒng)內(nèi)核建立一個(gè)rtsig隊(duì)列用于存放標(biāo)記事件發(fā)生(在Nginx服務(wù)器應(yīng)用中特指客戶端請(qǐng)求發(fā)生)的信號(hào)。每個(gè)事件發(fā)生時(shí),系統(tǒng)內(nèi)核就會(huì)產(chǎn)生一個(gè)信號(hào)存放到rtsig隊(duì)列中等待工作進(jìn)程的處理。

需要指出的是,rtsig隊(duì)列有長(zhǎng)度限制,超過該長(zhǎng)度后就會(huì)發(fā)生溢出。默認(rèn)情況下,Linux系統(tǒng)事件信號(hào)隊(duì)列的最大長(zhǎng)度設(shè)置為1024,也就是同時(shí)最多可以存放1024個(gè)發(fā)生事件的信號(hào)。在Linux 2.6.6-mm2之前的版本中,系統(tǒng)各個(gè)進(jìn)程的事件信號(hào)隊(duì)列是由內(nèi)核統(tǒng)一管理的,用戶可以通過修改內(nèi)核參數(shù)/proc/sys/kernel/rtsig-max來自定義該長(zhǎng)度設(shè)置。在Linux 2.6.6-mm2之后的版本中,該內(nèi)核參數(shù)被取消,系統(tǒng)各個(gè)進(jìn)程分別擁有各自的事件信號(hào)隊(duì)列,這個(gè)隊(duì)列的大小由Linux系統(tǒng)的RLIMIT_SIGPENDING參數(shù)定義,在執(zhí)行setrlimit()系統(tǒng)調(diào)用時(shí)確定該大小。Nginx提供了worker_rlimit_sigpending參數(shù)用于調(diào)節(jié)這種情況下的事件信號(hào)隊(duì)列長(zhǎng)度。

當(dāng)rtsig隊(duì)列發(fā)生溢出時(shí),Nginx將暫時(shí)停止使用rtsig模型,而調(diào)用poll庫處理未處理的事件,直到rtsig信號(hào)隊(duì)列全部清空,然后再次啟動(dòng)rtsig模型,以防止新的溢出發(fā)生。

Nginx在配置文件中提供了相關(guān)的參數(shù)對(duì)rtsig模型的使用進(jìn)行配置,細(xì)節(jié)內(nèi)容在后邊討論Nginx服務(wù)器事件驅(qū)動(dòng)模型時(shí)將會(huì)詳細(xì)闡述。編譯Nginx服務(wù)器時(shí),使用-with-rtsig_module配置選項(xiàng)來啟用rtsig模型的編譯。

其他事件驅(qū)動(dòng)模型

除了以上四種主要的事件驅(qū)動(dòng)模型,Nginx服務(wù)器針對(duì)特定的Linux平臺(tái)提供了響應(yīng)的事件驅(qū)動(dòng)模型支持。目前實(shí)現(xiàn)的主要有kqueue模型、/dev/poll模型和eventport模型等。

kqueue模型

用于支持BSD系列平臺(tái)的高效事件驅(qū)動(dòng)模型,主要用在FreeBSD 4.1及以上版本、OpenBSD 2.9及以上版本、NetBSD 2.0及以上版本以及Mac OS X平臺(tái)上。該模型也是poll庫的一個(gè)變種,其和epoll庫的處理方式?jīng)]有本質(zhì)上的區(qū)別,都是通過避免輪詢操作提供效率。該模型同時(shí)支持條件觸發(fā)(level-triggered,也叫水平觸發(fā),只要滿足條件就觸發(fā)一個(gè)事件)和邊緣觸發(fā)(edge-triggered,每當(dāng)狀態(tài)變化時(shí),觸發(fā)一個(gè)事件)。如果大家在這些平臺(tái)下使用Nginx服務(wù)器,建議選擇該模型用于請(qǐng)求處理,以提高Nginx服務(wù)器的處理性能。

/dev/poll模型

用于支持Unix衍生平臺(tái)的高效事件驅(qū)動(dòng)模型,其主要在Solaris711/99及以上版本、HP/UX 11.22及以上版本、IRIX 6.5.15及以上版本和Tru64 UNIX 5.1A及以上版本的平臺(tái)中使用。該模型是Sun公司在開發(fā)Solaris系列平臺(tái)時(shí)提出的用于完成事件驅(qū)動(dòng)機(jī)制的方案,它使用了虛擬的/dev/poll設(shè)備,開發(fā)人員可以將要監(jiān)視的文件描述符加入這個(gè)設(shè)備,然后通過ioctl()調(diào)用來獲取事件通知。在以上提到的平臺(tái)中,建議使用該模型處理請(qǐng)求。

eventport模型

用于支持Solaris 10及以上版本平臺(tái)的高效事件驅(qū)動(dòng)模型。該模型也是Sun公司在開發(fā)Solaris系列平臺(tái)時(shí)提出的用于完成事件驅(qū)動(dòng)機(jī)制的方案,它可以有效防止內(nèi)核崩潰等情況的發(fā)生,Nginx服務(wù)器為此提供了支持。
以上就是Nginx服務(wù)器支持的事件驅(qū)動(dòng)庫??梢钥吹?,Nginx服務(wù)器針對(duì)不同的Linux或Unix衍生平臺(tái)提供了多種事件驅(qū)動(dòng)模型的處理,盡量發(fā)揮系統(tǒng)平臺(tái)本身的優(yōu)勢(shì),最大程度地提高處理客戶端請(qǐng)求事件的能力。在實(shí)際工作中,我們需要根據(jù)具體情況和應(yīng)用情景選擇使用不同的事件驅(qū)動(dòng)模型,以保證Nginx服務(wù)器的高效運(yùn)行。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 事件驅(qū)動(dòng)模型是Nginx服務(wù)器保障完整功能和具有良好性能的重要機(jī)制之一。 事件驅(qū)動(dòng)模型概述 實(shí)際上,事件驅(qū)動(dòng)并不是...
    吃瓜的東閱讀 4,960評(píng)論 0 3
  • Nginx服務(wù)器架構(gòu)初探 Nginx模塊化結(jié)構(gòu) 核心模塊,是指Nginx服務(wù)器正常運(yùn)行必不可少的模塊,它們提供了N...
    漸丶忘閱讀 682評(píng)論 1 0
  • 事件驅(qū)動(dòng)模型就是在持續(xù)事務(wù)管理過程中,有當(dāng)前時(shí)間點(diǎn)上出現(xiàn)的事件引發(fā)的調(diào)動(dòng)可用資源還行相關(guān)任務(wù),解決不斷出現(xiàn)的問題,...
    愛吃豆包閱讀 1,404評(píng)論 0 0
  • UNIX Network Programming第六章節(jié) 前序概念: 文件描述符(File Descriptor)...
    mualex閱讀 856評(píng)論 0 1
  • python之路——IO模型 IO模型介紹 為了更好地了解IO模型,我們需要事先回顧下:同步、異步、阻塞、非阻塞 ...
    go以恒閱讀 596評(píng)論 0 2

友情鏈接更多精彩內(nèi)容