Nginx(發(fā)音為“ engine x”)是由俄羅斯軟件工程師Igor Sysoev編寫(xiě)的免費(fèi)開(kāi)源Web服務(wù)器。自2004年公開(kāi)發(fā)布以來(lái),nginx一直致力于高性能,高并發(fā)性和低內(nèi)存使用率。Web服務(wù)器功能之上的其他功能,例如負(fù)載平衡,緩存,訪問(wèn)和帶寬控制,以及與各種應(yīng)用程序高效集成的能力,已使Nginx成為現(xiàn)代網(wǎng)站體系結(jié)構(gòu)的理想選擇。當(dāng)前,nginx是Internet上第二受歡迎的開(kāi)源Web服務(wù)器。
為什么高并發(fā)很重要?
如今,互聯(lián)網(wǎng)是如此的廣泛和無(wú)所不在,很難想象十年前它并不完全存在。它已經(jīng)從基于NCSA的簡(jiǎn)單html產(chǎn)生可點(diǎn)擊文本,然后基于Apache Web服務(wù)器發(fā)展到了始終在線的通信介質(zhì),該通信介質(zhì)已被全世界超過(guò)20億用戶使用。隨著永久連接的PC,移動(dòng)設(shè)備和最近的平板電腦的普及,互聯(lián)網(wǎng)格局正在迅速變化,整個(gè)經(jīng)濟(jì)體已經(jīng)實(shí)現(xiàn)了數(shù)字化連接。在線服務(wù)變得更加復(fù)雜,并且對(duì)即時(shí)可用的實(shí)時(shí)信息和娛樂(lè)有明顯的偏見(jiàn)。運(yùn)行在線業(yè)務(wù)的安全性方面也已發(fā)生重大變化。因此,網(wǎng)站現(xiàn)在比以前復(fù)雜得多,
并發(fā)一直是網(wǎng)站架構(gòu)師面臨的最大挑戰(zhàn)之一。自Web服務(wù)開(kāi)始以來(lái),并發(fā)水平一直在不斷提高。一個(gè)受歡迎的網(wǎng)站為成千上萬(wàn)甚至數(shù)百萬(wàn)的同時(shí)用戶提供服務(wù)的情況并不少見(jiàn)。十年前,并發(fā)的主要原因是客戶端速度較慢,即具有ADSL或撥號(hào)連接的用戶。如今,并發(fā)是由移動(dòng)客戶端和較新的應(yīng)用程序體系結(jié)構(gòu)的結(jié)合引起的,這些體系結(jié)構(gòu)通常基于維護(hù)持久性連接,該持久性連接允許使用新聞,推文,朋友供稿等更新客戶端。導(dǎo)致并發(fā)性增加的另一個(gè)重要因素是現(xiàn)代瀏覽器的行為發(fā)生了變化,現(xiàn)代瀏覽器打開(kāi)了網(wǎng)站的四到六個(gè)同時(shí)連接,以提高頁(yè)面加載速度。
為了說(shuō)明客戶端速度慢的問(wèn)題,請(qǐng)想象一個(gè)簡(jiǎn)單的基于Apache的Web服務(wù)器,它會(huì)產(chǎn)生相對(duì)較短的100 KB響應(yīng),即帶有文本或圖像的Web頁(yè)面。生成或檢索此頁(yè)面僅需不到一秒鐘的時(shí)間,但是將其傳輸?shù)綆挒?0 kbps(10 KB / s)的客戶端需要10秒鐘。從本質(zhì)上講,Web服務(wù)器將相對(duì)快速地提取100 KB的內(nèi)容,然后在繁忙的10秒鐘之內(nèi)緩慢地將此內(nèi)容發(fā)送到客戶端,然后再釋放其連接。現(xiàn)在,假設(shè)您有1,000個(gè)同時(shí)連接的客戶端,他們請(qǐng)求了類似的內(nèi)容。如果每個(gè)客戶端僅分配1 MB的額外內(nèi)存,則將導(dǎo)致1000 MB(約1 GB)的額外內(nèi)存專用于僅為1000個(gè)客戶端提供100 KB的內(nèi)容。事實(shí)上,典型的基于Apache的Web服務(wù)器通常為每個(gè)連接分配超過(guò)1 MB的額外內(nèi)存,令人遺憾的是,數(shù)十kbps仍然經(jīng)常是移動(dòng)通信的有效速度。盡管可以通過(guò)增加操作系統(tǒng)內(nèi)核套接字緩沖區(qū)的大小在某種程度上改善將內(nèi)容發(fā)送到速度較慢的客戶端的情況,但這并不是解決問(wèn)題的一般方法,并且可能會(huì)帶來(lái)不良的副作用。
對(duì)于持久連接,處理并發(fā)性的問(wèn)題更加明顯,因?yàn)橐苊馀c建立新的HTTP連接相關(guān)的延遲,客戶端將保持連接狀態(tài),并且對(duì)于每個(gè)連接的客戶端,Web服務(wù)器都會(huì)分配一定數(shù)量的內(nèi)存。
因此,為了處理與不斷增長(zhǎng)的受眾相關(guān)的工作量增加以及更高級(jí)別的并發(fā)性并能夠持續(xù)做到這一點(diǎn),網(wǎng)站應(yīng)基于許多非常有效的構(gòu)建基塊。雖然等式的其他部分(例如硬件(CPU,內(nèi)存,磁盤(pán)),網(wǎng)絡(luò)容量,應(yīng)用程序和數(shù)據(jù)存儲(chǔ)體系結(jié)構(gòu))很重要,但在Web服務(wù)器軟件中,接受并處理了客戶端連接。因此,Web服務(wù)器應(yīng)該能夠隨著每秒同時(shí)發(fā)生的連接和請(qǐng)求數(shù)量的增長(zhǎng)而非線性擴(kuò)展。
Apache不適合嗎
Apache,至今仍在互聯(lián)網(wǎng)上占主導(dǎo)地位的Web服務(wù)器軟件,其起源可追溯到1990年代初。最初,它的體系結(jié)構(gòu)與當(dāng)時(shí)存在的操作系統(tǒng)和硬件相匹配,但也與Internet的狀態(tài)相匹配,在Internet上,網(wǎng)站通常是運(yùn)行單個(gè)Apache實(shí)例的獨(dú)立物理服務(wù)器。到2000年代初,很明顯,無(wú)法輕松地復(fù)制獨(dú)立的Web服務(wù)器模型來(lái)滿足不斷增長(zhǎng)的Web服務(wù)的需求。盡管Apache為將來(lái)的開(kāi)發(fā)提供了堅(jiān)實(shí)的基礎(chǔ),但它的架構(gòu)是為每個(gè)新連接生成自己的副本,這不適用于網(wǎng)站的非線性可伸縮性。最終,Apache成為了通用Web服務(wù)器,致力于提供許多不同的功能,各種第三方擴(kuò)展,以及對(duì)幾乎任何類型的Web應(yīng)用程序開(kāi)發(fā)的普遍適用性。但是,價(jià)格不菲,而且在單個(gè)軟件中擁有如此豐富而通用的工具組合的缺點(diǎn)是可伸縮性較差,這是因?yàn)槊總€(gè)連接的CPU和內(nèi)存使用量增加了。
因此,當(dāng)服務(wù)器硬件,操作系統(tǒng)和網(wǎng)絡(luò)資源不再是網(wǎng)站增長(zhǎng)的主要限制時(shí),全世界的Web開(kāi)發(fā)人員開(kāi)始四處尋找運(yùn)行Web服務(wù)器的更有效方法。大約十年前,著名的軟件工程師Daniel Kegel宣稱“現(xiàn)在是Web服務(wù)器同時(shí)處理一萬(wàn)個(gè)客戶端的時(shí)候了”,并預(yù)測(cè)了我們現(xiàn)在所說(shuō)的Internet云服務(wù)。凱格爾(Kegel)的C10K清單激發(fā)了許多嘗試來(lái)解決Web服務(wù)器優(yōu)化問(wèn)題,以同時(shí)處理大量客戶端,而Nginx證明是最成功的解決方案之一。
為了解決10,000個(gè)并發(fā)連接的C10K問(wèn)題,nginx在編寫(xiě)時(shí)就考慮了另一種體系結(jié)構(gòu),該體系結(jié)構(gòu)更適合于同時(shí)連接數(shù)和每秒請(qǐng)求數(shù)方面的非線性可伸縮性。nginx是基于事件的,因此它不遵循Apache的樣式來(lái)為每個(gè)網(wǎng)頁(yè)請(qǐng)求生成新的進(jìn)程或線程。最終結(jié)果是,即使負(fù)載增加,內(nèi)存和CPU使用率仍可控制。現(xiàn)在,nginx可以在具有典型硬件的服務(wù)器上提供數(shù)以萬(wàn)計(jì)的并發(fā)連接。
Nginx的第一個(gè)版本發(fā)布時(shí),它打算與Apache一起部署,以便Nginx處理諸如HTML,css,JAVAScript和圖像之類的靜態(tài)內(nèi)容,以減輕基于Apache的應(yīng)用程序服務(wù)器的并發(fā)性和延遲處理。在其開(kāi)發(fā)過(guò)程中,nginx通過(guò)使用FastCGI,uswgi或SCGI協(xié)議以及與分布式內(nèi)存對(duì)象緩存系統(tǒng)(如memcached),增加了與應(yīng)用程序的集成。還添加了其他有用的功能,例如帶有負(fù)載平衡和緩存的反向代理。這些附加功能使Nginx變成了可在其上構(gòu)建可伸縮Web基礎(chǔ)結(jié)構(gòu)的工具的有效組合。
2012年2月,Apache 2.4.x分支向公眾發(fā)布。盡管此最新版本的Apache添加了旨在增強(qiáng)可伸縮性和性能的新的多處理核心模塊和新的代理模塊,但現(xiàn)在判斷其性能,并發(fā)性和資源利用率是否與純事件同等或尚好還為時(shí)過(guò)早。驅(qū)動(dòng)的Web服務(wù)器。不過(guò),很高興看到Apache應(yīng)用服務(wù)器在新版本上可以更好地?cái)U(kuò)展,因?yàn)樗梢跃徑夂蠖朔矫娴钠款i,而瓶頸通常在典型的nginx-plus-Apache Web配置中仍然無(wú)法解決。
使用nginx還有更多優(yōu)勢(shì)嗎
始終以高性能和高效率來(lái)處理高并發(fā)性一直是部署nginx的主要好處。但是,現(xiàn)在有更多有趣的好處。
在過(guò)去的幾年中,Web架構(gòu)師接受了將應(yīng)用程序基礎(chǔ)結(jié)構(gòu)與Web服務(wù)器分離和分離的想法。但是,以前以基于LAMP(linux,Apache,MySQL,php,Python或Perl)的網(wǎng)站形式存在的網(wǎng)站現(xiàn)在可能不再僅僅是基于LEMP的網(wǎng)站(“ E”代表“ Engine x”)。 ,但越來(lái)越多的做法是將Web服務(wù)器推向基礎(chǔ)架構(gòu)的邊緣,并以不同的方式在其周圍集成相同或經(jīng)過(guò)改進(jìn)的一組應(yīng)用程序和數(shù)據(jù)庫(kù)工具。
nginx非常適合于此,因?yàn)樗峁┝朔奖愕男遁d并發(fā),延遲處理,SSL(安全套接字層),靜態(tài)內(nèi)容,壓縮和緩存,連接和請(qǐng)求限制以及甚至來(lái)自應(yīng)用程序的HTTP媒體流傳輸所需的關(guān)鍵功能。層到效率更高的邊緣Web服務(wù)器層。它還允許直接與memcached / redis或其他“ NoSQL”解決方案集成,以在為大量并發(fā)用戶提供服務(wù)時(shí)提高性能。
隨著近來(lái)開(kāi)發(fā)工具包和編程語(yǔ)言的廣泛使用,越來(lái)越多的公司正在改變其應(yīng)用程序開(kāi)發(fā)和部署習(xí)慣。nginx已成為這些不斷變化的范例中最重要的組成部分之一,它已經(jīng)幫助許多公司在預(yù)算范圍內(nèi)快速啟動(dòng)和開(kāi)發(fā)其Web服務(wù)。
nginx的第一行寫(xiě)于2002年。2004年,根據(jù)兩節(jié)BSD許可向公眾發(fā)布。從那時(shí)起,nginx用戶的數(shù)量一直在增長(zhǎng),他們提供了很多想法,并提交了對(duì)整個(gè)社區(qū)都非常有用和有益的錯(cuò)誤報(bào)告,建議和觀察結(jié)果。
Nginx代碼庫(kù)是原始的,完全是用C編程語(yǔ)言完全從頭編寫(xiě)的。nginx已被移植到許多體系結(jié)構(gòu)和操作系統(tǒng),包括Linux,F(xiàn)reeBSD,Solaris,mac OS X,AIX和Microsoft windows。nginx擁有自己的庫(kù),并且其標(biāo)準(zhǔn)模塊在系統(tǒng)的C庫(kù)之外使用很少,除了zlib,PCRE和OpenSSL外,如果不需要或由于潛在的許可證沖突,可以選擇將其從構(gòu)建中排除。
關(guān)于Windows版本的Nginx的幾句話。盡管nginx在Windows環(huán)境中工作,但Windows版本的nginx更像是概念驗(yàn)證,而不是功能齊全的端口。Nginx和Windows內(nèi)核體系結(jié)構(gòu)存在某些局限性,目前無(wú)法很好地進(jìn)行交互。Windows的nginx版本的已知問(wèn)題包括并發(fā)連接數(shù)少得多,性能下降,沒(méi)有緩存和沒(méi)有帶寬策略。適用于Windows的Nginx的未來(lái)版本將更接近主流功能。
Nginx架構(gòu)概述
傳統(tǒng)的基于進(jìn)程或線程的處理并發(fā)連接的模型涉及使用單獨(dú)的進(jìn)程或線程處理每個(gè)連接,并阻塞網(wǎng)絡(luò)或輸入/輸出操作。根據(jù)應(yīng)用程序的不同,它在內(nèi)存和CPU消耗方面可能效率很低。生成單獨(dú)的進(jìn)程或線程需要準(zhǔn)備新的運(yùn)行時(shí)環(huán)境,包括分配堆和堆棧內(nèi)存以及創(chuàng)建新的執(zhí)行上下文。創(chuàng)建這些項(xiàng)目也要花費(fèi)額外的CPU時(shí)間,由于過(guò)度的上下文切換導(dǎo)致線程崩潰,最終可能導(dǎo)致性能下降。所有這些復(fù)雜性都在Apache之類的較舊的Web服務(wù)器體系結(jié)構(gòu)中體現(xiàn)出來(lái)。這是在提供豐富的一組普遍適用的功能與優(yōu)化使用服務(wù)器資源之間的權(quán)衡。
從一開(kāi)始,nginx就是一種專用工具,可實(shí)現(xiàn)更高的性能,密度和服務(wù)器資源的經(jīng)濟(jì)使用,同時(shí)實(shí)現(xiàn)網(wǎng)站的動(dòng)態(tài)增長(zhǎng),因此它采用了不同的模型。實(shí)際上,它受到了各種操作系統(tǒng)中基于事件的高級(jí)機(jī)制的持續(xù)開(kāi)發(fā)的啟發(fā)。結(jié)果就是模塊化,事件驅(qū)動(dòng),異步,單線程,無(wú)阻塞的體系結(jié)構(gòu),該體系結(jié)構(gòu)成為nginx代碼的基礎(chǔ)。
nginx大量使用多路復(fù)用和事件通知,并將特定任務(wù)專用于分離進(jìn)程。連接在數(shù)量有限的稱為workers的單線程進(jìn)程中以高效的運(yùn)行循環(huán)進(jìn)行處理。每個(gè)workernginx內(nèi)每秒可以處理數(shù)千個(gè)并發(fā)連接和請(qǐng)求。
代碼結(jié)構(gòu)
Nginxworker代碼包括核心和功能模塊。nginx的核心負(fù)責(zé)維護(hù)緊密的運(yùn)行循環(huán),并在請(qǐng)求處理的每個(gè)階段執(zhí)行模塊代碼的適當(dāng)部分。模塊構(gòu)成了大多數(shù)表示層和應(yīng)用程序?qū)庸δ堋<せ畲砗螅K可從網(wǎng)絡(luò)讀取和寫(xiě)入網(wǎng)絡(luò)和存儲(chǔ),轉(zhuǎn)換內(nèi)容,進(jìn)行出站篩選,應(yīng)用服務(wù)器端包含操作并將請(qǐng)求傳遞給上游服務(wù)器。
nginx的模塊化體系結(jié)構(gòu)通常允許開(kāi)發(fā)人員在不修改nginx核心的情況下擴(kuò)展Web服務(wù)器功能集。nginx模塊的形式略有不同,即核心模塊,事件模塊,階段處理程序,協(xié)議,變量處理程序,過(guò)濾器,上游和負(fù)載平衡器。目前,nginx不支持動(dòng)態(tài)加載的模塊。即,在構(gòu)建階段將模塊與核心一起進(jìn)行編譯。但是,計(jì)劃在將來(lái)的主要版本中支持可裝載模塊和ABI。有關(guān)不同模塊的角色的更多詳細(xì)信息,請(qǐng)參見(jiàn)第14.4節(jié)。
同時(shí)處理各種具有接受,處理和管理的網(wǎng)絡(luò)連接和內(nèi)容檢索,nginx的用途事件通知機(jī)制和多個(gè)磁盤(pán)I /在Linux,Solaris和O性能增強(qiáng)基于BSD操作系統(tǒng),等等相關(guān)聯(lián)的動(dòng)作kqueue,epoll和event ports。目標(biāo)是為操作系統(tǒng)提供盡可能多的提示,以獲取針對(duì)入站和出站流量,磁盤(pán)操作,套接字的讀寫(xiě)操作,超時(shí)等的及時(shí)異步反饋。對(duì)于nginx所運(yùn)行的每個(gè)基于Unix的操作系統(tǒng),都對(duì)使用不同方法進(jìn)行多路復(fù)用和高級(jí)I / O操作進(jìn)行了優(yōu)化。
下圖給出了Nginx架構(gòu)的高級(jí)概述。
Nginx的架構(gòu)圖
Worker模型
如前所述,nginx不會(huì)為每個(gè)連接生成一個(gè)進(jìn)程或線程。取而代之的是,worker進(jìn)程接受來(lái)自共享“偵聽(tīng)”套接字的新請(qǐng)求,并在每個(gè)worker進(jìn)程內(nèi)部執(zhí)行高效的運(yùn)行循環(huán),以每個(gè)進(jìn)程處理數(shù)千個(gè)連接worker。worker在nginx中,沒(méi)有專門(mén)的仲裁或分配到s的連接;這項(xiàng)工作是由OS內(nèi)核機(jī)制完成的。啟動(dòng)時(shí),將創(chuàng)建一組初始的偵聽(tīng)套接字。worker然后在處理HTTP請(qǐng)求和響應(yīng)的同時(shí)不斷接受,讀取和寫(xiě)入套接字。
運(yùn)行循環(huán)是Nginxworker代碼中最復(fù)雜的部分。它包括全面的內(nèi)部調(diào)用,并且在很大程度上依賴于異步任務(wù)處理的思想。異步操作是通過(guò)模塊化,事件通知,回調(diào)函數(shù)的廣泛使用和經(jīng)過(guò)微調(diào)的計(jì)時(shí)器來(lái)實(shí)現(xiàn)的。總體而言,關(guān)鍵原則是盡可能不阻塞。nginx仍然可以阻止的唯一情況是,當(dāng)worker進(jìn)程的磁盤(pán)存儲(chǔ)性能不足時(shí)。
由于nginx不會(huì)為每個(gè)連接派生一個(gè)進(jìn)程或線程,因此在大多數(shù)情況下,內(nèi)存使用非常保守且非常高效。nginx還可以節(jié)省CPU周期,因?yàn)檫M(jìn)程或線程沒(méi)有持續(xù)的create-destroy模式。nginx的作用是檢查網(wǎng)絡(luò)和存儲(chǔ)的狀態(tài),初始化新連接,將它們添加到運(yùn)行循環(huán)中,并異步處理直到完成,這時(shí)將連接釋放并從運(yùn)行循環(huán)中刪除。結(jié)合使用syscalls的謹(jǐn)慎使用和對(duì)接口(如池和平板內(nèi)存分配器)的支持的準(zhǔn)確實(shí)現(xiàn),即使在極端的工作負(fù)載下,nginx通常也可以實(shí)現(xiàn)中等到低的CPU使用率。
由于nginx產(chǎn)生幾個(gè)workers來(lái)處理連接,因此它可以在多個(gè)內(nèi)核之間很好地?cái)U(kuò)展。通常,worker每個(gè)內(nèi)核使用單獨(dú)的內(nèi)核可以充分利用多核體系結(jié)構(gòu),并防止線程崩潰和鎖定。沒(méi)有資源匱乏,并且資源控制機(jī)制被隔離在單線程worker進(jìn)程中。該模型還允許跨物理存儲(chǔ)設(shè)備更大的可伸縮性,促進(jìn)更多的磁盤(pán)利用率,并避免阻塞磁盤(pán)I / O。結(jié)果,服務(wù)器資源可以更有效地利用,并且在多個(gè)工作人員之間共享工作負(fù)載。
對(duì)于某些磁盤(pán)使用情況和CPU負(fù)載模式,worker應(yīng)調(diào)整nginx的數(shù)量。這些規(guī)則在這里有些基本,系統(tǒng)管理員應(yīng)針對(duì)其工作負(fù)載嘗試一些配置。一般建議如下:如果負(fù)載模式是CPU密集型的(例如,處理大量TCP / IP,執(zhí)行SSL或壓縮),則nginxworker的數(shù)量應(yīng)與CPU內(nèi)核的數(shù)量匹配;如果負(fù)載主要是受磁盤(pán)I / O約束的(例如,從存儲(chǔ)服務(wù)中提供不同的內(nèi)容集或進(jìn)行大量代理),則workers的數(shù)量可能是內(nèi)核數(shù)量的一半到兩倍。有些工程師worker根據(jù)單個(gè)存儲(chǔ)單元的數(shù)量來(lái)選擇s的數(shù)量,盡管這種方法的效率取決于磁盤(pán)存儲(chǔ)的類型和配置。
Nginx開(kāi)發(fā)人員將在即將發(fā)布的版本中解決的一個(gè)主要問(wèn)題是如何避免磁盤(pán)I / O的大部分阻塞。目前,如果沒(méi)有足夠的存儲(chǔ)性能來(lái)滿足特定磁盤(pán)所生成的磁盤(pán)操作worker,則worker可能仍無(wú)法從磁盤(pán)進(jìn)行讀/寫(xiě)操作。存在許多機(jī)制和配置文件指令來(lái)減輕此類磁盤(pán)I / O阻塞的情況。最值得注意的是,諸如sendfile和AIO之類的選項(xiàng)組合通常會(huì)為磁盤(pán)性能產(chǎn)生很大的擴(kuò)展空間。應(yīng)該基于數(shù)據(jù)集,可用于nginx的內(nèi)存量以及基礎(chǔ)存儲(chǔ)架構(gòu)來(lái)規(guī)劃nginx的安裝。
現(xiàn)有worker模型的另一個(gè)問(wèn)題與對(duì)嵌入式腳本的有限支持有關(guān)。首先,使用標(biāo)準(zhǔn)的nginx發(fā)行版,僅支持嵌入Perl腳本。對(duì)此有一個(gè)簡(jiǎn)單的解釋:關(guān)鍵問(wèn)題是嵌入式腳本可能阻塞任何操作或意外退出。兩種類型的行為都將立即導(dǎo)致工人被吊死的情況,同時(shí)影響成千上萬(wàn)的連接。計(jì)劃進(jìn)行更多工作,以使使用nginx的嵌入式腳本更簡(jiǎn)單,更可靠,并適合更廣泛的應(yīng)用程序。
nginx流程角色
nginx在內(nèi)存中運(yùn)行多個(gè)進(jìn)程;有一個(gè)主過(guò)程和幾個(gè)worker過(guò)程。還有兩個(gè)特殊目的的過(guò)程,特別是緩存加載器和緩存管理器。所有進(jìn)程在nginx的1.x版本中都是單線程的。所有進(jìn)程主要使用共享內(nèi)存機(jī)制進(jìn)行進(jìn)程間通信。主進(jìn)程以root用戶身份運(yùn)行。緩存加載器,緩存管理器和worker均以非特權(quán)用戶身份運(yùn)行。
主流程負(fù)責(zé)以下任務(wù):
- 讀取并驗(yàn)證配置
- 創(chuàng)建,綁定和關(guān)閉套接字
- 啟動(dòng),終止和維護(hù)配置的worker進(jìn)程數(shù)
- 重新配置而不會(huì)中斷服務(wù)
- 控制不間斷二進(jìn)制升級(jí)(啟動(dòng)新二進(jìn)制并在必要時(shí)回滾)
- 重新打開(kāi)日志文件
- 編譯嵌入式Perl腳本
該worker過(guò)程接受來(lái)自客戶端的處理和過(guò)程連接,提供反向代理和過(guò)濾功能,并做幾乎其他一切nginx的是可以勝任的。關(guān)于監(jiān)視nginx實(shí)例的行為,系統(tǒng)管理員應(yīng)密切注意workers,因?yàn)樗鼈兪欠从砏eb服務(wù)器實(shí)際日常操作的過(guò)程。
緩存加載器進(jìn)程負(fù)責(zé)檢查磁盤(pán)上的緩存項(xiàng),并使用緩存元數(shù)據(jù)填充nginx的內(nèi)存數(shù)據(jù)庫(kù)。本質(zhì)上,緩存加載器準(zhǔn)備nginx實(shí)例,以與已經(jīng)存儲(chǔ)在磁盤(pán)上的文件(以特別分配的目錄結(jié)構(gòu))一起工作。它遍歷目錄,檢查緩存內(nèi)容元數(shù)據(jù),更新共享內(nèi)存中的相關(guān)條目,然后在一切準(zhǔn)備就緒且可用時(shí)退出。
緩存管理器主要負(fù)責(zé)緩存的過(guò)期和失效。在正常的Nginx操作期間,它會(huì)保留在內(nèi)存中,如果發(fā)生故障,它將由主進(jìn)程重新啟動(dòng)。
Nginx緩存概述
nginx中的緩存以文件系統(tǒng)上分層數(shù)據(jù)存儲(chǔ)的形式實(shí)現(xiàn)。高速緩存鍵是可配置的,并且可以使用不同的特定于請(qǐng)求的參數(shù)來(lái)控制進(jìn)入高速緩存的內(nèi)容。緩存鍵和緩存元數(shù)據(jù)存儲(chǔ)在共享內(nèi)存段中,緩存加載器,緩存管理器和worker可以訪問(wèn)這些共享內(nèi)存段。當(dāng)前,除了操作系統(tǒng)的虛擬文件系統(tǒng)機(jī)制所隱含的優(yōu)化之外,沒(méi)有任何文件內(nèi)的內(nèi)存緩存。每個(gè)緩存的響應(yīng)都放置在文件系統(tǒng)上的不同文件中。層次結(jié)構(gòu)(級(jí)別和命名詳細(xì)信息)由nginx配置指令控制。將響應(yīng)寫(xiě)入高速緩存目錄結(jié)構(gòu)時(shí),文件的路徑和名稱是從代理URL的MD5哈希得出的。
將內(nèi)容放置在緩存中的過(guò)程如下:當(dāng)nginx從上游服務(wù)器讀取響應(yīng)時(shí),首先將內(nèi)容寫(xiě)入到緩存目錄結(jié)構(gòu)之外的臨時(shí)文件中。當(dāng)nginx完成對(duì)請(qǐng)求的處理后,它將重命名臨時(shí)文件并將其移至緩存目錄。如果用于代理的臨時(shí)文件目錄位于另一個(gè)文件系統(tǒng)上,則將復(fù)制該文件,因此建議將臨時(shí)目錄和緩存目錄都保留在同一文件系統(tǒng)上。當(dāng)需要顯式清除文件時(shí),從緩存目錄結(jié)構(gòu)中刪除文件也是非常安全的。Nginx有第三方擴(kuò)展,可以遠(yuǎn)程控制緩存的內(nèi)容,并且計(jì)劃將更多功能集成到主發(fā)行版中。
nginx配置
Nginx的配置系統(tǒng)受到Igor Sysoev在Apache方面的經(jīng)驗(yàn)的啟發(fā)。他的主要見(jiàn)解是,可伸縮的配置系統(tǒng)對(duì)于Web服務(wù)器至關(guān)重要。在維護(hù)具有許多虛擬服務(wù)器,目錄,位置和數(shù)據(jù)集的大型復(fù)雜配置時(shí),遇到了主要的擴(kuò)展問(wèn)題。在相對(duì)較大的Web設(shè)置中,如果在應(yīng)用程序級(jí)別和系統(tǒng)工程師本人均未正確執(zhí)行的話,這可能是一場(chǎng)噩夢(mèng)。
因此,nginx配置旨在簡(jiǎn)化日常操作,并為進(jìn)一步擴(kuò)展Web服務(wù)器配置提供簡(jiǎn)便的方法。
nginx配置保存在許多通常位于/usr/local/etc/nginx或中的純文本文件中/etc/nginx。主要配置文件通常稱為nginx.conf。為了使它整潔,可以將部分配置放在單獨(dú)的文件中,這些文件可以自動(dòng)包含在主文件中。但是,此處應(yīng)注意,nginx當(dāng)前不支持Apache樣式的分布式配置(即.htaccess文件)。與nginx Web服務(wù)器行為有關(guān)的所有配置都應(yīng)駐留在一組集中的配置文件中。
最初由主進(jìn)程讀取并驗(yàn)證配置文件。worker從主進(jìn)程派生出來(lái)的進(jìn)程可以使用nginx配置的已編譯只讀形式。配置結(jié)構(gòu)由通常的虛擬內(nèi)存管理機(jī)制自動(dòng)共享。
nginx的配置有幾種不同的情況下main,http,server,upstream,location(也mail指示為郵件代理)塊。上下文永遠(yuǎn)不會(huì)重疊。例如,沒(méi)有將location塊放在main指令塊中的事情。另外,為避免不必要的歧義,沒(méi)有類似“全局Web服務(wù)器”的配置。nginx配置的目的是干凈邏輯,允許用戶維護(hù)包含數(shù)千個(gè)指令的復(fù)雜配置文件。Sysoev在一次私下交談中說(shuō):“全局服務(wù)器配置中的位置,目錄和其他塊是我在Apache中從未喜歡的功能,因此這就是為什么它們從未在nginx中實(shí)現(xiàn)的原因。”
配置語(yǔ)法,格式和定義遵循所謂的C樣式約定。各種各樣的開(kāi)放源代碼和商業(yè)軟件應(yīng)用程序已經(jīng)使用了這種制作配置文件的特殊方法。通過(guò)設(shè)計(jì),C風(fēng)格的配置非常適合嵌套的描述,邏輯性強(qiáng),易于創(chuàng)建,閱讀和維護(hù),并且受到許多工程師的喜愛(ài)。Nginx的C樣式配置也可以輕松實(shí)現(xiàn)自動(dòng)化。
盡管某些nginx指令類似于Apache配置的某些部分,但是設(shè)置nginx實(shí)例卻是完全不同的體驗(yàn)。例如,nginx支持重寫(xiě)規(guī)則,盡管它需要管理員手動(dòng)調(diào)整舊版Apache重寫(xiě)配置以匹配nginx樣式。重寫(xiě)引擎的實(shí)現(xiàn)也有所不同。
通常,nginx設(shè)置還支持多種原始機(jī)制,這些機(jī)制作為精益Web服務(wù)器配置的一部分非常有用。簡(jiǎn)要提及變量和try_files指令是有意義的,這在nginx中是唯一的。開(kāi)發(fā)nginx中的變量是為了提供附加的甚至更強(qiáng)大的機(jī)制來(lái)控制Web服務(wù)器的運(yùn)行時(shí)配置。優(yōu)化了變量以進(jìn)行快速評(píng)估,并在內(nèi)部將其預(yù)編譯為索引。評(píng)估是按需完成的;也就是說(shuō),變量的值通常只計(jì)算一次,并在特定請(qǐng)求的生存期內(nèi)進(jìn)行緩存。變量可以與不同的配置指令一起使用,從而為描述條件請(qǐng)求處理行為提供了額外的靈活性。
該try_files指令最初旨在以if一種更適當(dāng)?shù)姆绞街饾u替換條件配置語(yǔ)句,并且該指令旨在快速有效地嘗試/匹配不同的URI到內(nèi)容的映射。總體而言,該try_files指令運(yùn)行良好,并且可能非常有效和有用。建議讀者徹底檢查該try_files指令,并在適用的情況下采用該指令。
nginx內(nèi)部
如前所述,nginx代碼庫(kù)由一個(gè)核心和許多模塊組成。Nginx的核心負(fù)責(zé)提供Web服務(wù)器,Web和郵件反向代理功能的基礎(chǔ);它啟用了底層網(wǎng)絡(luò)協(xié)議的使用,構(gòu)建了必要的運(yùn)行時(shí)環(huán)境,并確保了不同模塊之間的無(wú)縫交互。但是,大多數(shù)特定于協(xié)議和應(yīng)用程序的功能是由nginx模塊而不是核心完成的。
在內(nèi)部,nginx通過(guò)模塊的管道或鏈來(lái)處理連接。換句話說(shuō),對(duì)于每個(gè)操作,都有一個(gè)模塊在做相關(guān)的工作。例如,壓縮,修改內(nèi)容,執(zhí)行服務(wù)器端包含,通過(guò)FastCGI或uwsgi協(xié)議與上游應(yīng)用程序服務(wù)器進(jìn)行通信,或與memcached進(jìn)行通信。
在內(nèi)核和真正的“功能”模塊之間的某個(gè)位置有幾個(gè)nginx模塊。這些模塊是http和mail。這兩個(gè)模塊在核心組件和較低級(jí)別的組件之間提供了附加的抽象級(jí)別。在這些模塊中,實(shí)現(xiàn)了與相應(yīng)的應(yīng)用程序?qū)訁f(xié)議(如HTTP,SMTP或IMAP)關(guān)聯(lián)的事件序列的處理。這些上層模塊與nginx核心結(jié)合,負(fù)責(zé)維護(hù)對(duì)各個(gè)功能模塊的正確調(diào)用順序。目前,HTTP協(xié)議已作為該http模塊的一部分實(shí)現(xiàn),但由于需要支持SPDY等其他協(xié)議,因此計(jì)劃在將來(lái)將其分成功能模塊。SPDY:一種用于更快Web的實(shí)驗(yàn)性協(xié)議”)。
功能模塊可分為事件模塊,階段處理程序,輸出過(guò)濾器,變量處理程序,協(xié)議,上游和負(fù)載平衡器。盡管事件模塊和協(xié)議也用于,但大多數(shù)這些模塊都是nginx的HTTP功能的補(bǔ)充mail。事件模塊提供了特定于OS的事件通知機(jī)制,例如kqueue或epoll。Nginx使用的事件模塊取決于操作系統(tǒng)功能和構(gòu)建配置。協(xié)議模塊允許nginx通過(guò)HTTPS,TLS / SSL,SMTP,POP3和IMAP進(jìn)行通信。
一個(gè)典型的HTTP請(qǐng)求處理周期如下所示。
- 客戶端發(fā)送HTTP請(qǐng)求。
- nginx核心根據(jù)與請(qǐng)求匹配的已配置位置選擇適當(dāng)?shù)碾A段處理程序。
- 如果配置為這樣做,則負(fù)載平衡器將選擇上游服務(wù)器進(jìn)行代理。
- 階段處理程序執(zhí)行其工作,并將每個(gè)輸出緩沖區(qū)傳遞給第一個(gè)過(guò)濾器。
- 第一個(gè)過(guò)濾器將輸出傳遞到第二個(gè)過(guò)濾器。
- 第二個(gè)過(guò)濾器將輸出傳遞到第三個(gè)(依此類推)。
- 最終響應(yīng)將發(fā)送給客戶端。
nginx模塊的調(diào)用是高度可定制的。它通過(guò)使用指向可執(zhí)行函數(shù)的指針的一系列回調(diào)來(lái)執(zhí)行。但是,這樣做的缺點(diǎn)是可能給希望編寫(xiě)自己的模塊的程序員帶來(lái)沉重負(fù)擔(dān),因?yàn)樗麄儽仨殰?zhǔn)確定義模塊的運(yùn)行方式和運(yùn)行時(shí)間。nginx API和開(kāi)發(fā)人員的文檔都得到了改進(jìn),可以緩解這種情況。
模塊可以連接的位置的一些示例是:
- 在讀取和處理配置文件之前
- 對(duì)于該位置及其所在的服務(wù)器的每個(gè)配置指令
- 初始化主配置時(shí)
- 服務(wù)器(即主機(jī)/端口)初始化時(shí)
- 服務(wù)器配置與主配置合并時(shí)
- 當(dāng)配置配置被初始化或與父服務(wù)器配置合并時(shí)
- 主進(jìn)程開(kāi)始或退出時(shí)
- 當(dāng)新的工作進(jìn)程啟動(dòng)或退出時(shí)
- 處理請(qǐng)求時(shí)
- 過(guò)濾響應(yīng)標(biāo)頭和正文時(shí)
- 在選擇,啟動(dòng)和重新啟動(dòng)對(duì)上游服務(wù)器的請(qǐng)求時(shí)
- 處理上游服務(wù)器的響應(yīng)時(shí)
- 完成與上游服務(wù)器的交互時(shí)
在內(nèi)worker,導(dǎo)致運(yùn)行循環(huán)(在其中生成響應(yīng))的操作序列如下所示:
- 開(kāi)始ngx_worker_process_cycle()。
- 使用操作系統(tǒng)特定的機(jī)制(例如epoll或kqueue)處理事件。
- 接受事件并調(diào)度相關(guān)動(dòng)作。
- 流程/代理請(qǐng)求標(biāo)頭和正文。
- 生成響應(yīng)內(nèi)容(標(biāo)題,正文)并將其流式傳輸?shù)娇蛻舳恕?/li>
- 完成請(qǐng)求。
- 重新初始化計(jì)時(shí)器和事件。
運(yùn)行循環(huán)本身(第5步和第6步)確保增量生成響應(yīng)并將其流傳輸?shù)娇蛻舳恕?/p>
處理HTTP請(qǐng)求的更詳細(xì)的視圖可能如下所示:
- 初始化請(qǐng)求處理。
- 進(jìn)程頭。
- 工藝體。
- 調(diào)用關(guān)聯(lián)的處理程序。
- 運(yùn)行處理階段。
這使我們進(jìn)入了階段。當(dāng)nginx處理HTTP請(qǐng)求時(shí),它將通過(guò)多個(gè)處理階段傳遞它。在每個(gè)階段都有處理程序要調(diào)用。通常,階段處理程序處理請(qǐng)求并產(chǎn)生相關(guān)輸出。相位處理程序?qū)⒏郊拥脚渲梦募卸x的位置。
階段處理程序通常做四件事:獲取位置配置,生成適當(dāng)?shù)捻憫?yīng),發(fā)送標(biāo)頭和發(fā)送正文。處理程序只有一個(gè)參數(shù):描述請(qǐng)求的特定結(jié)構(gòu)。請(qǐng)求結(jié)構(gòu)具有許多有關(guān)客戶端請(qǐng)求的有用信息,例如請(qǐng)求方法,URI和標(biāo)頭。
讀取HTTP請(qǐng)求標(biāo)頭后,nginx會(huì)查找關(guān)聯(lián)的虛擬服務(wù)器配置。如果找到了虛擬服務(wù)器,則請(qǐng)求將經(jīng)歷六個(gè)階段:
- 服務(wù)器重寫(xiě)階段
- 定位階段
- 位置重寫(xiě)階段(可以將請(qǐng)求帶回到上一個(gè)階段)
- 訪問(wèn)控制階段
- try_files階段
- 對(duì)數(shù)階段
為了響應(yīng)請(qǐng)求生成必要的內(nèi)容,nginx將請(qǐng)求傳遞給合適的內(nèi)容處理程序。根據(jù)確切位置的配置,nginx的可先試用所謂的無(wú)條件處理,如perl,proxy_pass,flv,mp4,等。如果請(qǐng)求不通過(guò)下面的處理程序之一匹配任何內(nèi)容處理器之上,這是挑選的,在這個(gè)確切順序?yàn)椋簉andom index,index,autoindex,gzip_static,static。
可以在Nginx文檔中找到索引模塊的詳細(xì)信息,但是這些模塊處理帶有尾部斜杠的請(qǐng)求。如果像這樣的專用模塊mp4或autoindex不合適的模塊,則將內(nèi)容視為磁盤(pán)上的文件或目錄(即靜態(tài)),并由static內(nèi)容處理程序提供服務(wù)。對(duì)于目錄,它將自動(dòng)重寫(xiě)URI,以使結(jié)尾的斜杠始終存在(然后發(fā)出HTTP重定向)。
然后,內(nèi)容處理程序的內(nèi)容將傳遞到過(guò)濾器。過(guò)濾器也附加到位置,并且可以為一個(gè)位置配置多個(gè)過(guò)濾器。過(guò)濾器執(zhí)行操作處理程序產(chǎn)生的輸出的任務(wù)。過(guò)濾器的執(zhí)行順序在編譯時(shí)確定。對(duì)于開(kāi)箱即用的過(guò)濾器,它是預(yù)定義的,對(duì)于第三方過(guò)濾器,可以在構(gòu)建階段進(jìn)行配置。在現(xiàn)有的nginx實(shí)現(xiàn)中,過(guò)濾器只能進(jìn)行出站更改,并且目前沒(méi)有機(jī)制可以編寫(xiě)和附加過(guò)濾器來(lái)進(jìn)行輸入內(nèi)容轉(zhuǎn)換。輸入過(guò)濾將出現(xiàn)在Nginx的未來(lái)版本中。
過(guò)濾器遵循特定的設(shè)計(jì)模式。一個(gè)過(guò)濾器被調(diào)用,開(kāi)始工作,并調(diào)用下一個(gè)過(guò)濾器,直到調(diào)用鏈中的最后一個(gè)過(guò)濾器為止。之后,nginx完成響應(yīng)。過(guò)濾器不必等待上一個(gè)過(guò)濾器完成。一旦前一個(gè)過(guò)濾器的輸入可用(功能非常類似于Unix管道),鏈中的下一個(gè)過(guò)濾器就可以開(kāi)始自己的工作。反過(guò)來(lái),可以在接收到來(lái)自上游服務(wù)器的整個(gè)響應(yīng)之前,將生成的輸出響應(yīng)傳遞給客戶端。
有標(biāo)題過(guò)濾器和主體過(guò)濾器。nginx將響應(yīng)的標(biāo)頭和正文分別饋送到關(guān)聯(lián)的過(guò)濾器。
標(biāo)頭過(guò)濾器包含三個(gè)基本步驟:
- 決定是否對(duì)此響應(yīng)進(jìn)行操作。
- 根據(jù)響應(yīng)進(jìn)行操作。
- 調(diào)用下一個(gè)過(guò)濾器。
主體過(guò)濾器可轉(zhuǎn)換生成的內(nèi)容。身體過(guò)濾器的示例包括:
- 服務(wù)器端包含
- XSLT過(guò)濾
- 圖像過(guò)濾(例如,即時(shí)調(diào)整圖像大小)
- 字符集修改
- gzip 壓縮
- 分塊編碼
在過(guò)濾器鏈之后,響應(yīng)將傳遞到編寫(xiě)器。除編寫(xiě)器外,還有其他幾個(gè)特殊用途的過(guò)濾器,即copy過(guò)濾器和postpone過(guò)濾器。該copy過(guò)濾器是負(fù)責(zé)填充內(nèi)存緩沖區(qū)有可能被存儲(chǔ)在一個(gè)代理臨時(shí)目錄相關(guān)的響應(yīng)內(nèi)容。該postpone過(guò)濾器用于子請(qǐng)求。
子請(qǐng)求是用于請(qǐng)求/響應(yīng)處理的非常重要的機(jī)制。子請(qǐng)求也是Nginx最強(qiáng)大的方面之一。通過(guò)子請(qǐng)求,nginx可以從與客戶端最初請(qǐng)求的URL不同的URL返回結(jié)果。一些Web框架將其稱為內(nèi)部重定向。但是,nginx更進(jìn)一步-過(guò)濾器不僅可以執(zhí)行多個(gè)子請(qǐng)求并將輸出組合到單個(gè)響應(yīng)中,而且子請(qǐng)求還可以嵌套和分層。子請(qǐng)求可以執(zhí)行自己的子子請(qǐng)求,并且子子請(qǐng)求可以發(fā)起子子子請(qǐng)求。子請(qǐng)求可以映射到硬盤(pán),其他處理程序或上游服務(wù)器上的文件。子請(qǐng)求對(duì)于基于原始響應(yīng)中的數(shù)據(jù)插入其他內(nèi)容最有用。例如,include帶有指定URL內(nèi)容的指令。或者,它可能是制作過(guò)濾器的示例,該過(guò)濾器將文檔的全部?jī)?nèi)容視為要檢索的URL,然后將新文檔附加到URL本身。
上游和負(fù)載均衡器也值得簡(jiǎn)要描述。上游用于實(shí)現(xiàn)可以識(shí)別為內(nèi)容處理程序的內(nèi)容,該內(nèi)容處理程序是反向代理(proxy_pass處理程序)。上游模塊通常會(huì)準(zhǔn)備要發(fā)送到上游服務(wù)器(或“后端”)的請(qǐng)求,并從上游服務(wù)器接收響應(yīng)。這里沒(méi)有對(duì)輸出過(guò)濾器的調(diào)用。上游模塊確切執(zhí)行的操作是在準(zhǔn)備好寫(xiě)入和讀取上游服務(wù)器時(shí)調(diào)用設(shè)置的回調(diào)。存在實(shí)現(xiàn)以下功能的回調(diào):
- 制作請(qǐng)求緩沖區(qū)(或它們的鏈)以發(fā)送到上游服務(wù)器
- 重新初始化/重置與上游服務(wù)器的連接(在再次創(chuàng)建請(qǐng)求之前發(fā)生)
- 處理上游響應(yīng)的第一位并保存指向從上游服務(wù)器接收的有效負(fù)載的指針
- 終止請(qǐng)求(在客戶端過(guò)早終止時(shí)發(fā)生)
- 當(dāng)Nginx完成從上游服務(wù)器的讀取時(shí)完成請(qǐng)求
- 整理響應(yīng)主體(例如,移除拖車)
負(fù)載平衡器模塊連接到proxy_pass處理程序,以在有多個(gè)上游服務(wù)器符合條件時(shí)提供選擇上游服務(wù)器的能力。負(fù)載平衡器注冊(cè)一個(gè)啟用配置文件指令,提供其他上游初始化功能(以解析DNS中的上游名稱等),初始化連接結(jié)構(gòu),決定將請(qǐng)求路由到何處,并更新統(tǒng)計(jì)信息。當(dāng)前,nginx支持兩種標(biāo)準(zhǔn)規(guī)范來(lái)平衡上游服務(wù)器的負(fù)載:輪詢和ip-hash。
上游和負(fù)載平衡處理機(jī)制包括用于檢測(cè)故障上游服務(wù)器并將新請(qǐng)求重新路由到其余請(qǐng)求的算法,盡管計(jì)劃進(jìn)行許多其他工作來(lái)增強(qiáng)此功能。通常,計(jì)劃在負(fù)載平衡器上進(jìn)行更多工作,并且在Nginx的下一版本中,將大大改善跨不同上游服務(wù)器分配負(fù)載以及運(yùn)行狀況檢查的機(jī)制。
還有兩個(gè)其他有趣的模塊,它們提供了一組在配置文件中使用的變量。雖然nginx中的變量是在不同的模塊之間創(chuàng)建和更新的,但有兩個(gè)完全專用于變量的模塊:geo和map。該geo模塊用于根據(jù)客戶端的IP地址促進(jìn)對(duì)客戶端的跟蹤。該模塊可以創(chuàng)建依賴于客戶端IP地址的任意變量。另一個(gè)模塊map允許從其他變量創(chuàng)建變量,從本質(zhì)上講,它提供了對(duì)主機(jī)名和其他運(yùn)行時(shí)變量進(jìn)行靈活映射的功能。這種模塊可以稱為變量處理程序。
在單個(gè)nginx內(nèi)實(shí)現(xiàn)的內(nèi)存分配機(jī)制在worker某種程度上受到Apache的啟發(fā)。Nginx內(nèi)存管理的高級(jí)描述如下:對(duì)于每個(gè)連接,動(dòng)態(tài)分配,鏈接必需的內(nèi)存緩沖區(qū),將其用于存儲(chǔ)和處理請(qǐng)求和響應(yīng)的標(biāo)頭和主體,然后在連接釋放時(shí)釋放它們。請(qǐng)務(wù)必注意,nginx會(huì)盡量避免在內(nèi)存中復(fù)制數(shù)據(jù),并且大多數(shù)數(shù)據(jù)是通過(guò)指針值傳遞的,而不是通過(guò)調(diào)用傳遞的memcpy。
更深入一點(diǎn),當(dāng)模塊生成響應(yīng)時(shí),將檢索到的內(nèi)容放入內(nèi)存緩沖區(qū)中,然后將其添加到緩沖區(qū)鏈鏈接中。隨后的處理也與此緩沖區(qū)鏈鏈接一起工作。在Nginx中,緩沖區(qū)鏈非常復(fù)雜,因?yàn)楦鶕?jù)模塊類型的不同,有多種處理方案。例如,在實(shí)現(xiàn)主體過(guò)濾器模塊時(shí)精確地管理緩沖區(qū)可能非常棘手。這樣的模塊一次只能在一個(gè)緩沖區(qū)(鏈鏈接)上運(yùn)行,并且必須決定是覆蓋輸入緩沖區(qū),用新分配的緩沖區(qū)替換該緩沖區(qū),還是在相關(guān)緩沖區(qū)之前或之后插入新緩沖區(qū)。使事情復(fù)雜化的是,有時(shí)模塊會(huì)接收多個(gè)緩沖區(qū),因此它具有不完整的緩沖區(qū)鏈,必須對(duì)其進(jìn)行操作。然而,
關(guān)于上述方法的注釋是,在連接的整個(gè)生命周期中都分配了內(nèi)存緩沖區(qū),因此對(duì)于壽命長(zhǎng)的連接,會(huì)保留一些額外的內(nèi)存。同時(shí),在空閑的keepalive連接上,nginx僅花費(fèi)550字節(jié)的內(nèi)存。對(duì)于Nginx的將來(lái)版本,可能的優(yōu)化方法是重用和共享內(nèi)存緩沖區(qū)以用于長(zhǎng)期連接。
管理內(nèi)存分配的任務(wù)由Nginx池分配器完成。共享內(nèi)存區(qū)域用于接受互斥,高速緩存元數(shù)據(jù),SSL會(huì)話高速緩存以及與帶寬管制和管理(限制)相關(guān)的信息。在nginx中實(shí)現(xiàn)了一個(gè)平板分配器來(lái)管理共享內(nèi)存分配。為了允許同時(shí)安全地使用共享內(nèi)存,可以使用多種鎖定機(jī)制(互斥體和信號(hào)量)。為了組織復(fù)雜的數(shù)據(jù)結(jié)構(gòu),nginx還提供了一個(gè)紅黑樹(shù)實(shí)現(xiàn)。紅黑樹(shù)用于將緩存元數(shù)據(jù)保留在共享內(nèi)存中,跟蹤非正則表達(dá)式位置定義以及執(zhí)行其他一些任務(wù)。
不幸的是,上述所有內(nèi)容從未以一致和簡(jiǎn)單的方式進(jìn)行描述,這使得為nginx開(kāi)發(fā)第三方擴(kuò)展的工作變得相當(dāng)復(fù)雜。盡管存在一些有關(guān)nginx內(nèi)部的良好文檔(例如,由Evan Miller編寫(xiě)的文檔),但此類文檔仍需要大量的逆向工程工作,并且nginx模塊的實(shí)現(xiàn)對(duì)于許多人來(lái)說(shuō)仍然是妖術(shù)。
盡管與第三方模塊開(kāi)發(fā)相關(guān)的某些困難,但Nginx用戶社區(qū)最近看到了許多有用的第三方模塊。例如,有一個(gè)用于nginx的嵌入式Lua解釋器模塊,用于負(fù)載平衡的其他模塊,全面的WebDAV支持,高級(jí)緩存控制以及本章的作者鼓勵(lì)并將來(lái)會(huì)支持的其他有趣的第三方工作。
教訓(xùn)
當(dāng)Igor Sysoev開(kāi)始編寫(xiě)nginx時(shí),支持Internet的大多數(shù)軟件已經(jīng)存在,并且此類軟件的體系結(jié)構(gòu)通常遵循傳統(tǒng)服務(wù)器和網(wǎng)絡(luò)硬件,操作系統(tǒng)以及舊的Internet體系結(jié)構(gòu)的定義。但是,這并沒(méi)有阻止Igor認(rèn)為他可能能夠改進(jìn)Web服務(wù)器領(lǐng)域的功能。因此,盡管第一課似乎很明顯,但事實(shí)是:總有改進(jìn)的余地。
考慮到更好的Web軟件的想法,Igor花了很多時(shí)間來(lái)開(kāi)發(fā)初始代碼結(jié)構(gòu),并研究了針對(duì)各種操作系統(tǒng)優(yōu)化代碼的不同方法。十年后,考慮到對(duì)版本1的積極開(kāi)發(fā),他正在開(kāi)發(fā)nginx版本2.0的原型。很顯然,新架構(gòu)的初始原型和初始代碼結(jié)構(gòu)對(duì)于未來(lái)的發(fā)展至關(guān)重要。軟件產(chǎn)品。
值得一提的另一點(diǎn)是,應(yīng)重點(diǎn)發(fā)展。Windows版本的nginx可能是一個(gè)很好的例子,它說(shuō)明了如何避免將開(kāi)發(fā)工作浪費(fèi)在既不是開(kāi)發(fā)人員的核心能力也不是目標(biāo)應(yīng)用程序的東西上是值得的。它同樣適用于在嘗試使用更多功能增強(qiáng)nginx以便與現(xiàn)有舊式設(shè)置向后兼容的過(guò)程中出現(xiàn)的重寫(xiě)引擎。
最后但并非最不重要的一點(diǎn)是,值得一提的是,盡管Nginx開(kāi)發(fā)人員社區(qū)不是很大,但Nginx的第三方模塊和擴(kuò)展一直是其受歡迎程度的重要組成部分。Nginx用戶社區(qū)及其原始開(kāi)發(fā)人員對(duì)Evan Miller,Piotr Sikora,Valery Kholodkov,Zhang Yichun(agentzh)和其他才華橫溢的軟件工程師所做的工作表示贊賞。
(本文由聞數(shù)起舞翻譯自Andrew Alexeev的文章《Nginx》,轉(zhuǎn)載請(qǐng)注明出處,原文鏈接:
https://www.aosabook.org/en/nginx.html)






