天天看點

nginx架構(修改版)

英文:http://www.aosabook.org/en/nginx.html

3rdPartyModules http://wiki.nginx.org/3rdPartyModules

nginx(發音為“engine x”)是一個免費的開源Web伺服器,由俄羅斯軟體工程師Igor Sysoev編寫。其在2004年向公衆推出以來,nginx一直專注于高性能,高并發性和低記憶體占用。 Web伺服器功能之上的附加功能,如負載均衡,緩存,通路和帶寬控制的能力,以及有能力有效整合各種應用,這些都有助于使nginx成為現代網站架構一個不錯的選擇。目前,nginx在網際網路上是第二最流行的開源Web伺服器。

1. 為什麼高并發重要?

    這些天來,網際網路是如此的普遍,無處不在,這和我們十年前知道的完全不一樣的。它極大地演變,從簡單的HTML産生點選文字,基于NCSA然後是Apache Web伺服器,到一個由全球超過2億使用者使用的一直線上的通信媒體。永久連接配接的個人電腦,移動裝置和最近的平闆,網際網路景觀迅速的變化和整個經濟體已成為數字化。線上服務有明顯的偏向立即可用的實時資訊和娛樂。線上業務安全運作方面也有顯着的改變。是以,網站現在比以前要複雜得多,為了健壯性和可擴充行通常需要更多的工程努力。

    并發性一直是一個網站的架構師面臨的最大挑戰之一。Web服務創立以來,并發的水準一直在不斷增長。一個受歡迎的網站,服務幾十萬,甚至上百萬的同時線上使用者的情況并不少見。十年前,造成并發的主要原因是緩慢的ADSL或撥接上網的用戶端用使用者。如今,并發是由移動用戶端和新的應用程式架構的組合,這是都基于保持一個持久的連接配接,可以讓用戶端進行更新新聞,tweets,朋友feeds等。促進提高并發性的另一個重要因素是特性改變的現代浏覽器,打開4到6個同時連接配接到一個網站,以提高網頁加載速度。

  為了說明關于慢速的客戶問題,想象一個簡單的基于Apache的Web伺服器産生一個相對短的100 KB響應的web頁面中的文本或圖像。生成或檢索這個頁面隻需要幾分之一秒,但将它發送到帶寬為80 kbps(10 KB/秒)用戶端需要10秒。從本質上講,Web伺服器會相對迅速地擷取100 KB的内容,然後在釋放這個連接配接前, 将是繁忙的10秒鐘,慢慢将此内容發送到用戶端。現在,假設你有1000個同時連接配接的用戶端的請求類似的内容。如果每個用戶端隻配置設定1 MB的額外記憶體,這将導緻1000 MB(1 GB)的額外的記憶體,緻力于僅僅1000多家客戶提供服務100 KB的内容。在現實中,一個典型的基于Apache的Web伺服器每個連接配接配置設定通常超過1 MB的額外記憶體,令人遺憾的是幾十kbps的往往仍然是移動通信的有效速度。雖然發送内容到一個緩慢的用戶端的的情況,增加作業系統核心套接字緩沖區的大小在一定程度上可以改善性能,這不是解決問題的正常方式,并且可能具有不可預料的副作用。

       處理持久連接配接的并發性問題更是明顯,因為為避免建立新的HTTP連接配接的延遲,用戶端保持連接配接狀态,Web伺服器為每個連接配接的用戶端配置設定有一定量的記憶體。

    是以,為處理因為越來越多的觀衆而增加的工作量,是以,更進階别的并發性,并能繼續這樣做。一個網站應基于一些非常有效的積木。而方程的其他部分,如硬體(CPU,記憶體,磁盤),網絡容量,應用程式和存儲架構顯然是重要的,Web伺服器軟體處理和接受的用戶端連接配接。是以,Web伺服器應該能夠随着不斷增長的同時連接配接數和每秒請求數非線性擴充。

 Apache合适嗎?

        如今,Apache網頁伺服器軟體在很大程度上仍然統治着網際網路,起源于20世紀90年代初。最初,它的結構符合當時存在的作業系統和硬體,也符合當時網際網路狀态,一個網站通常是一個獨立的實體伺服器上運作的Apache的一個執行個體。到了21世紀初,很明顯獨立的Web伺服器模型不能簡單的複制,以滿足不斷增長的Web服務。雖然Apache為未來的發展提供了一個堅實的基礎,它的架構是為每一個新的連接配接生成一個自身的副本,這不适合的非線性可擴充性網站。最終Apache成為一個通用的Web伺服器,專注于有許多不同的功能,各種第三方擴充,并普遍适用于幾乎任何類型的Web應用程式開發。然而,任何事情都不是無代價和無缺點的,一個軟體一部分有那麼豐富和萬能工具組合性,因為每個連接配接都要增加CPU和記憶體使用,它的缺點就是弱擴充性。

        是以,當伺服器硬體,作業系統和網絡資源不再是網站增長的主要制約因素,世界各地的Web開發人員開始到處尋找一個更有效的方式運作Web伺服器。大約在10年前,著名的軟體工程師,Daniel Kegel宣布,“Web伺服器是時候同時處理10000客戶啦”,并預測也就是我們現在所說的網際網路雲服務。 Kegel的C10K明顯的刺激了一些嘗試者去解決Web伺服器問題,去優化在同一時間處理大量的客戶。nginx被證明是最成功的之一。

        為了解決C10K問題的10,000個并發連接配接,nginx從心地以不同體系結構編寫,這更适合于非線性可擴充性的并發連接配接數和每秒請求數。 nginx是基于事件的,是以它沒有延續apache的風格,不會為每個網頁請求産生新的程序或線程。最終的結果是,即使在負載增加時,記憶體和CPU使用率依然是可控的。一個典型的硬體伺服器上,nginx的現在可以提供數十萬的并發連接配接。

        當nginx的第一個版本釋出之時,它傾向于部署在Apache側旁,靜态内容,如HTML,CSS,JavaScript和圖像 由nginx處理以分擔apache為基礎的應用服務的并發性和低延遲。在其發展過程中,nginx的增加了內建的應用程式,通過使用uswgi的FastCGI,SCGI協定,像Memcached的分布式的記憶體對象緩存系統。其他有用的功能,也增加了如反向代理負載均衡和緩存。這些額外的功能把nginx塑造成一個有效的工具組合,來建立一個可擴充的網絡基礎架構。

        在2012年2月,Apache的2.4.x分支向公衆釋出。雖然這個最新版本的Apache已經加入新的多處理核心子產品和新的代理子產品旨在提高可擴充性和性能,斷定它的性能,并發和資源利用是否看齊,或好與純事件驅動的Web伺服器還太早。很樂于看到新版本Apache應用程式伺服器更好的處理伸縮性,不過,因為它可能會緩解後端的瓶頸問題,這在典型的nginx的加的Apache Web配置經常仍然沒有得到解決。

使用nginx有更多的優勢嗎?

    高性能,高效率的處理高并發是部署nginx的一直是關鍵的好處。然而,現在有更有趣的好處。

        在過去的幾年裡,網絡架構師們接受他們的應用程式從Web伺服器基礎設施的去耦和分離的想法。不過,以前以LAMP(Linux作業系統,Apache,MySQL和PHP,Python或Perl)的形式為基礎的網站,現在可能成為不僅僅基于LEMP('E'引擎X'的地位)但越來越多往往是一個例子以不同的方式推動Web伺服器到基礎設施邊緣和整合相同或改組後的一套應用程式和資料庫工具。

        Nginx是非常适合的,因為它提供了必要的關鍵功能,友善分擔的并發性,低延遲的處理,SSL(安全套接字層),靜态的内容,壓縮和緩存,連接配接和請求限制,甚至HTTP的流媒體的應用層,以一種更有效的邊緣Web伺服器層。它也允許直接內建memcached/Redis的或其他的“NoSQL”的解決方案,當服務大量并發使用者時以提高性能。

        随着近年來目前開發工具包和程式設計語言風格廣泛使用的,越來越多的企業正在改變他們的應用開發和部署的習慣。 nginx的已成為這些政策變革的最重要組成部分之一,它已經幫助許多公司開始開發Web服務,并在他們的預算中。

        在2002年的nginx的的第一行代碼寫成。 2004年在BSD許可證下向公衆釋出。 從那時nginx的使用者的數量一直增長,貢獻的想法,并送出bug報告,建議和意見,對社群有極大的幫助和益處。

        nginx的代碼庫是原創的,是完全從頭開始用C程式設計語言編寫的。 nginx的已經被移植到許多體系結構和作業系統,包括Linux,FreeBSD,Solaris,Mac OS X中,AIX和Microsoft Windows。 nginx的有其自己的庫,其标準子產品不會使用遠遠超出系統C庫的東西,除了zlib的,PCRE和OpenSSL,如果沒有必要,可以選擇排除,因為的建構中潛在的許可沖突,。

     說下Windows版本nginx。雖然nginx的工作在Windows環境中,Windows版本nginx的更像是概念的證明,而不是一個全功能的移植。 nginx和Windows核心架構,在這個時候,互動不是很好,有一定的限制。 nginx的版本的Windows的已知問題包括低得多的并發連接配接數,性能下降,沒有緩存,沒有帶寬政策。 nginx的Windows的未來版本将和主流版本功能更為貼近。

2. nginx的體系結構概述。

傳統的程序或線程模型處理并發連接配接是用一個單獨的程序或線程處理每個連接配接使,并阻塞在網絡或者輸入/輸出操作。取決于應用,記憶體和CPU的使用可能是非常低效的。産生一個單獨的程序或線程都需要一個新的運作環境準備,包括堆和棧記憶體配置設定,并建立一個新的執行上下文。建立這些項目也花費額外的CPU時間,這最終會導緻很差的性能,由于線程過多的上下文切換的颠簸。所有這些并發症的在較舊的Web伺服器架構都有表現,比如Apache。這個在一個提供豐富特性的通用應用程式和優化服務資源的一個權衡。

        從一開始,nginx就傾向于成為一個專門的工具來實作更高的性能,經濟的使用伺服器資源,同時允許一個網站的動态增長,是以它采取了不同的模式。它實際上是基于在各種作業系統的先進的事件的機制不斷發展的啟發。結果成就一個子產品化的,事件驅動的,異步,單線程的,非阻斷架構,成為nginx代碼的基礎。

        nginx大量使用複用和事件通知,以及單獨的程序緻力于特定任務。連接配接的處理在有限數目稱為worker的單線程程序的一個高效率的運作循環中。在每個worker 中nginx可以處理每秒成千上萬的并發連接配接請求。

代碼結構

    nginx的worker代碼包括核心和功能子產品。 nginx的核心是負責維持嚴格的運作循環和在每個階段的請求進行中執行适當子產品的部分代碼。子產品構成大部分示範和應用層的功能。子產品讀取和寫入到網絡和存儲,内容轉換,出站過濾,應用伺服器端包含行動,及當代理伺服器激活時,并向上遊傳送請求。

    nginx的子產品化結構,通常允許開發者來擴充Web伺服器功能集合,而無需修改nginx的核心。 nginx的子產品稍微不同的化身,即核心子產品,事件子產品,階段處理程式,協定,變量處理程式,過濾器,上遊和負載平衡器。目前,nginx的不支援動态加載子產品,在建構階段子產品和核心一起編譯。然而,計劃在将來主版本支援可加載子產品和ABI。不同的子產品的角色的更詳細資訊,可以參看第14.4節。

        在處理與接受,處理和管理網絡連接配接和内容檢索的各種響應,nginx的使用事件通知機制和Linux的性能大量的增強磁盤I / O,Solaris和BSD為基礎的作業系統,喜歡的kqueue,epoll,event ports事件端口。我們的目标是給作業系統提供盡可能多的提示,關于入站和出站流量及時的異步回報,磁盤操作,讀取或寫入socket,逾時等。複用和進階I / O操作在nginx的運作的基于Unix的作業系統上已經使用各種方法做了最大程度的優化。

nginx的高度概述架構如圖14.1示意。

nginx架構(修改版)

  Figure 14.1: Diagram of nginx's architecture

Worker模型

        正如前面所提到的,,nginx并不為每個連接配接産生一個程序或線程。相反,工作程序從一個共享的“listen”socket接受新的請求,每個worker内運作循環高效執行。每個worker處理數以千計的連接配接。在nginx中有沒有專門仲裁或分發連接配接到worker,這項工作是由作業系統核心機制完成。在啟動時,一組初始的監聽套接字被建立。worker不斷接受,讀取和寫入到socket,當處理HTTP請求和響應時

        nginx的worker代碼的運作循環是最複雜的部分。它包括全部的内部調用,并在很大程度上依賴于異步處理任務的想法。異步操作通過子產品化,事件通知,廣泛使用回調函數和微調定時器實作。總體而言,關鍵的原則是盡可能的非阻塞。 唯一可以讓nginx阻塞的情形是,沒有足夠的磁盤存儲供worker操作。

        由于nginx的并不會為每個連接配接産生的程序或線程,記憶體使用在絕大多數情況下是非常保守的,效率非常高。 nginx的節省CPU周期,因為沒有持續的程序或線程的建立消毀模式。nginx要做的是檢查網絡和存儲的狀态,初始化新的連接配接,将它們添加到運作循環,處理直到完成,此時連接配接被釋放,從運作循環中移除。謹慎使用系統調用和準确實作支援接口,如poll和slab記憶體配置設定器相結合,nginx的通常達到中度至低CPU占用率,即使在極端惡劣的工作負載。

        由于nginx的産生數個worker程序處理連接配接,在多核上擴充性很好。一般情況下,每核一個單獨的worker可以充分利用多核架構,并防止線程的颠簸和鎖定。隔離的單線程worker程序沒有資源匮乏和資源控制機制。該模型還允許在實體儲存設備的可擴充性,有利于更好的磁盤使用率,避免了磁盤I / O阻塞。是以,一些資源在幾個worker之間共享可以更有效使用

        一些磁盤和CPU的負載模式,nginx的worker數目應應相應的進行調整。這裡有些所謂的基本規則,系統管理者應該根據負載量嘗試幾種配置。以下的是一般建議内容:如果負載模式是CPU密集的情況下,處理大量的TCP / IP,做SSL,壓縮,nginx的worker的數量和CPU核的數量相比對,如果負載主要是磁盤I / O範疇的情況下,從儲存提供不同的内容,或繁忙的代理。worker的數量可以是一個半到兩個核的數量。與之相反的是,一些工程師選擇worker的數量是基于獨立存儲單元的數量,但這種方法的效率取決于磁盤存儲的類型和配置。

        在将來的版本中,nginx的開發一個主要問題是解決如何避免磁盤I / O阻塞。目前,如果沒有足夠的存儲性能,服務一個特定的worker産生的操作,worker可能仍然阻塞在磁盤讀/寫磁盤操作。存在的一些機制和配置檔案指令,以減輕這樣的磁盤I / O阻塞情況。最值得注意的是,組合選項如sendfile和AIO選項,通常會為磁盤性能産生大量的上部空間。 nginx的部署計劃應該基于資料集,nginx的可用記憶體量,以及底層的存儲架構。

        與現有的worker模式相關另一個問題是有限的嵌入式腳本支援。 nginx釋出的标準版本,隻支援Perl腳本嵌入。有一個簡單的解釋:關鍵的問題是嵌入的腳本可能阻塞在任意操作或意外退出。這兩種類型的行為,将立即導緻worker挂起,進而影響成千上萬的連接配接。更多的工作計劃将會實施, 将使nginx的嵌入式腳本更簡單,更可靠,适用于更廣泛的應用。

Nginx程序的作用

        nginx在記憶體中運作多個程序。有一個主程序和多個worker程序。此外,還有一些特殊用途的程序,特别是高速緩存器加載和高速緩存管理器。在nginx的1.x版本中所有的程序都是單線程。所有程序主要使用的共享記憶體的程序間通信機制。主程序以root使用者運作。緩存加載器,緩存管理和worker作為一個非特權使用者運作。

    主程序負責執行以下任務:

  • 讀取并驗證配置
  • 建立,綁定和關閉套接字
  • 啟動,終止和維護配置的工作程序數
  • 不中斷服務的情況下重新配置
  • 控制不停止服務的二進制更新(如有必要,啟動新的二進制程式和復原)
  • 重新打開日志檔案
  • 編譯嵌入式的Perl腳本

        worker程序接受,處置和處理來自用戶端的連接配接,提供反向代理和過濾功能,做nginx能力範圍之内的所有事情。關于監測nginx的執行個體的動态,系統管理者應該留意worker,因為他們是反映了Web伺服器的實際的日常操作的程序。

        緩存加載器程序負責檢查磁盤上的緩存項和使用高速緩存中繼資料填充Nginx的在記憶體資料庫。從本質上講,緩存加載器把幫助nginx和檔案協同工作,一個已經專門配置設定存儲在磁盤上的目錄結構。它周遊目錄,檢查緩存内容,中繼資料,更新共享記憶體中的相關條目,當一切都幹淨并準備投入使用時,然後退出,。

        高速緩存管理器主要是負責緩存過期和失效。在正常nginx的操作過程中它駐留在記憶體中,在失敗的情況下,它被主程序重新啟動。

Nginx的緩存的簡要概述

        Nginx的緩存在以分層資料存儲的形式在一個檔案系統中實作的。緩存鍵是可配置的,不同請求為目的參數可以用來控制那些參數進入高速緩存中。高速緩存鍵和緩存中繼資料存儲在共享記憶體段,進而緩存加載器,緩存管理器和worker可以通路。目前沒有任何檔案緩存在記憶體中,隻有作業系統的虛拟檔案系統機制方面的優化。每個高速緩存的響應被放置在檔案系統上的不同檔案。通過nginx的配置指令控制的層次結構(層次和命名的詳細資訊)。當一個響應被寫入到高速緩存的目錄結構,路徑和檔案的檔案名是來自代理URL的MD5哈希。

        放置在高速緩存中的内容的過程,如下所示:當nginx從上遊伺服器讀取響應,内容首先被寫入到高速緩存的目錄結構以外的一個臨時檔案。當nginx的完成處理請求時,臨時檔案重命名,并被移動到緩存目錄中。如果臨時檔案目錄代理是在另一個檔案系統上,該檔案将被複制,是以建議臨時檔案和緩存目錄保持在同一個檔案系統。需要顯式地清除,從緩存目錄結構删除檔案的是比較安全。有nginx第三方擴充,這可以遠端控制緩存的内容,在主版本中有更多的工作計劃将內建這一功能。

3. Nginx的配置

        Nginx的配置系統靈感來自Igor Sysoev使用Apache的經驗。他的主要見解是:一個可擴充的Web伺服器配置系統是必不可少的。維護有很多的virtual servers,directories,locations和datasets的的大型複雜配置遇到了主要問題是可伸縮性。一個比較大的網絡設定,無論是在應用程式級别和系統工程師自己,如果做得不好,那将是個噩夢。

        是以,nginx配置的目的是要簡化日常運作,并為Web伺服器将來擴充的配置提供一個簡單的方法。

        Nginx的配置以純文字檔案儲存,且通常駐留在/usr/local/etc/nginx或/etc/nginx。主配置檔案通常被稱為nginx.conf。為了保持它的整潔,可以把部分的配置放在單獨的檔案中,它可以在主檔案中自動包含。然而,應該指出的是nginx的目前不支援Apache風格的分布式配置(例如,。htaccess檔案)。所有和nginx web server的相關配置應駐留在一組集中的配置檔案中。

        配置檔案由master程序最先讀取和驗證。一個編譯過的nginx的配置是隻讀的形式提供給worker程序,worker是主程序派生的。配置結構通常由虛拟記憶體管理機制自動共享。

    Nginx的配置main, http, server, upstream, location (mail)有幾種不同上下文的指令塊。上下文永遠不會重疊。例如,沒有把location block放在main block的指令塊裡的事情。此外,為避免不必要的歧義,沒有任何像“全球網絡伺服器”配置的東西。 nginx的配置,傾向于幹淨和邏輯,允許使用者能夠保持複雜的配置檔案,包括數以千計的指令。在一次私人談話中,Sysoev說,Apache全局伺服器配置中的“Locations,directories和其它塊特性我從來都不喜歡的,是以因為這個原因,它們的功能從來沒有在nginx中實作。”

        配置文法,格式和定義遵循一個所謂的C-風格的慣例。這種特殊的配置檔案的方法已經被用于各種開源和商業軟體應用。在設計上,C-風格的配置适用于嵌套的描述,邏輯和容易建立,閱讀和維護,和許多工程師都喜歡的。 nginx的C-風格的配置,也容易實作自動化。

        雖然一些nginx的指令類似Apache配置中的某些部分,設立一個nginx的執行個體是完全不同的經曆。例如,重寫由nginx的支援的規則,雖然這将需要管理者從适應傳統的Apache重寫配置到比對nginx的風格。重寫引擎的實作也不同。

        在一般情況下,nginx的設定也提供了支援幾個原來的機制,這就是非常有用的瘦Web伺服器配置的一部分。這是有道理的,簡單提一下的variables和try_files指令,讓nginx是有些獨特的。在nginx的Variables,以提供額外的,更強大的機制來控制運作時配置的Web伺服器。變量為快速評估進行了優化,并在内部預編譯成指數。評估的需求;即一個變量的值,通常隻計算一次,并緩存的生命周期的一個特定的請求。變量可以和不同的配置指令一起使用,為描述條件請求處理的行為提供額外的靈活性。

    try_files指令最初是為了一個更恰當的方式逐漸取代條件配置語句,它的目的是快速,高效地嘗試不同的URI到内容的映射/比對。總體而言,try_files的指令運作良好,并可以非常有效和有用的。建議讀者徹底檢查的try_files,接受它的适用。

4.  Nginx的内部

        正如之前提到的,nginx的代碼庫包含一個核心和大量的子產品。 nginx的核心是負責提供Web伺服器基礎服務,Web和郵件的反向代理功能,它允許使用相關的網絡協定,建立必要的運作時環境,并確定不同子產品之間的無縫互動。然而,大多數的協定和特定應用程式的功能是由nginx的子產品完成的,而不是核心。

        在内部,nginx的通過子產品管道或鍊的處理連接配接。換句話說,每一個操作都有一個子產品向對應,例如,壓縮,修改的内容,執行伺服器端的包含通過FastCGI或uwsgi協定和上遊應用程式伺服器通信,或memcached互動。

        有一對nginx的子產品位于核心和真正的“功能性”子產品之間。這些子產品是http和mail。這兩個子產品在核心和較低級别的元件提供了更進階别的抽象。在這些子產品中,處理一系列的事件對應相應的應用層協定,如HTTP,SMTP,IMAP已經實作。結合nginx的核心,這些上層子產品負責維持各功能子產品正确順序的調用。雖然目前HTTP協定是HTTP子產品的一部分的,由于需要支援其他協定,如SPDY,在未來有計劃把它分割成一個功能子產品,(見“SPDY協定的實驗速度更快的網絡“)。

        這些功能子產品可分為事件子產品,階段處理,輸出濾波器,變量處理,協定,上遊和負載平衡器。nginx大多數這些子產品的補充HTTP的功能,雖然事件子產品和協定也被用于郵件。事件子產品提供了一個特别依賴于作業系統的kqueue或epoll的事件通知機制,如。 nginx的使用的事件子產品依賴于作業系統的功能和建構配置。協定子產品允許nginx通過TLS / SSL,HTTPS,SMTP,POP3和IMAP溝通。

一個典型的HTTP請求處理周期看起來像下面這樣。

  1. 用戶端發送HTTP請求。
  2. nginx的核心階段根據所配置的location選擇合适比對請求的處理程式。
  3. 如果配置要求這樣做,負載平衡器為代理挑選一個上遊伺服器。
  4. 階段處理程式執行它的工作,并傳遞每個輸出緩沖器到所述第一濾波器。
  5. 第一濾波器的輸出傳遞到所述第二過濾器。
  6. 第二濾波器的輸出到第三個(等等)。
  7. 最終的響應被發送到用戶端。

nginx的子產品調用是非常定制的。它是通過使用指針指向可執行函數執行一系列回調。但是,這種方法的缺點是,它給願意寫自己的子產品的程式員一個很大包袱,因為他們必須準确定義子產品何時以及如何運作。 nginx的API和開發者文檔中不斷完善,更可用以減輕這個負擔。

一些一個子產品可以附加的例子:

  • 在配置檔案中讀取和處理之前
  • 對于每個配置指令的location和伺服器出現的地方
  •  主配置初始化完成後
  • 當伺服器(即主機/端口)的初始化後
  • 當伺服器配置合并進主要配置
  • 當location的配置初始化或和它的父伺服器配置合并後
  • 當主程序啟動或退出
  • 當一個新的worker程序啟動或退出
  • 在處理一個請求
  • 當過濾的響應報頭和身體
  • 當選擇,啟動和重新啟動請求到上遊伺服器
  • 當處理從上遊伺服器來的響應
  • 當完成一個與上遊伺服器互動

在worker的内部,導緻運作循環生成響應行動的順序看起來像下面這樣:

  1. 開始ngx_worker_process_cycle()。
  2.  處理與OS相關的特定事件機制(,如epoll的或kqueue的)。
  3.  接受事件和排程相關的行動。
  4. 處理/代理請求報頭和主體。
  5. 生成響應内容(标題,正文),并傳輸到用戶端。
  6. 完成請求
  7. 重新初始化定時器和事件。

運作循環本身(步驟5和6),確定産生一個增量的響應和流給用戶端。

一個更詳細的處理一個HTTP請求視圖可能看起來像這樣:

  1. 初始化請求處理。
  2. 處理報頭
  3. 處理封包主體
  4. 調用相關的處理程式
  5. 執行通過處理階段。

        這給我們帶來的階段。 當nginx的處理HTTP請求,通過一些處理階段。在每個階段中,有調用相應的處理程式。在一般情況下,階段程式處理請求,并産生相應的輸出。階段處理程式附加在配置檔案中定義的location。

        第一階段處理程式通常做四件事:擷取location配置,産生适當的響應,發送标題,發送的消息體。一個處理程式有一個參數:一個特定的結構來描述的要求。請求結構有很多有用的資訊,用戶端的請求,如請求方法,URI,和頭。

        當讀取HTTP請求頭,nginx的執行查找相關聯的虛拟伺服器配置。如果虛拟伺服器找到,該請求通過六個階段:

  1. 伺服器重寫階段
  2.  location 階段
  3. location重寫階段(可帶回到上一階段的要求)
  4. 通路控制階段
  5. try_files階段
  6. 登入階段

        nginx為了産生必要的響應于該請求的内容,将請求傳遞到一個合适的内容處理程式。根據的确切location配置,nginx的可以嘗試所謂的無條件處理程式,如PERL,proxy_pass,FLV,MP4,等,如果請求不符合任何對以上内容的處理程式,它挑選的下列處理程式在這個正确的順序:随機名額,指數,自動索引,gzip_static,靜态的。

        索引子產品的詳細資訊,可以在nginx的文檔找到,但它們是處理帶斜線請求的子產品。如果一個專門的子產品,如MP4或自動索引不合适, 内容被認為是隻是在磁盤上一個檔案或目錄(也就是靜态)被靜态内容處理程式處理。對于一個目錄,它會自動重寫的URI,這樣結尾的斜線是永遠存在的(然後發出一個HTTP重定向)。

        内容處理程式的内容,然後遞送給過濾器。過濾器附加在locations裡,且一個locations可以配置數個過濾器。過濾器做任務的是操作由一個處理程式生成的輸出。過濾器執行的順序是在編譯時确定。對于出過濾器是已經預定義,第三方的過濾器,它可以在建構階段配置。在現有的nginx的實作,過濾器隻能做出的變化,目前還沒有寫和附加過濾器去做輸入内容轉換的機制。輸入濾波将在nginx的未來版本中出現。

        過濾器按照特定的設計模式。過濾器被調用,開始工作,調用下一個過濾器,直到最後的過濾器鍊中的。在那之後,nginx的定型的反應。過濾器不必等待前面的過濾器來完成。在一個鍊中的下一個過濾器可以從它自己的工作盡快從以前的1的輸入是可用的(功能很像Unix的管道)。反過來,所産生的輸出響應可以在上遊伺服器接收到的全部響應之前傳遞給用戶端,。

有消息頭過濾器和消息體過濾器; nginx分别饋送消息頭和消息體的和過濾器相關聯的響應。

一個頭過濾器包括三個基本步驟:

  1. 決定是否在操作此響應。
  2. 操作此響應
  3. 調用下個過濾器.

體過濾器轉換生成的内容。體過濾器的例子包括:

  • 伺服器端包含
  • XSLT 過濾器
  • 圖像過濾器 (for instance, resizing images on the fly)
  • 字元集修改
  • gzip 壓縮
  • 分塊編碼

        過濾器鍊後,響應被傳遞到寫操作。伴随寫操作有一對其他特殊用途的過濾器,即複制過濾器和的推遲過濾器。複制過濾器是負責,用于填充相關響應内容的記憶體緩沖區, 這些内容可能存貯在代理的一個臨時目錄中。推遲過濾器用于子請求。

        子請求是請求/響應處理的一個非常重要的機制。子請求nginx的最強大的方面之一。通過子請求nginx可以從一個不同于用戶端最初請求的URL傳回結果。一些web架構調用這個内部重定向。然而,nginx的更進一步,不僅可以過濾執行多個子請求的輸出組合成一個單獨的響應,但是子請求也可以是嵌套和層次。一個子請求可以執行其自己的子子請求,一個子子請求啟動子子子請求。子請求映射到硬碟上的檔案,其他處理,或上遊伺服器。子請求最有用的是在原來的響應基礎上插入額外的内容。例如,SSI(伺服器端包含)子產品使用過濾器來解析傳回的文檔的内容,然後指定的URL的内容替換include指令。或者,它可以是使一個過濾器,将一個檔案的全部内容作為要檢索一個URL的一個例子,然後追加新的檔案到URL本身。

        上遊和負載平衡器也值得描述簡要。Upstreams被标記為内容處理,也就是一個反向代理(proxy_pass處理程式)。Upstreams子產品主要是把請求發送到上遊伺服器(或“後端”),并從上遊伺服器收到的響應。這裡沒有輸出過濾出。的上遊子產品具體要做是設定回調函數,當上遊伺服器已準備好要寫入和讀出被調用。存在回調實作以下功能:

  • 制作一個發送到上遊伺服器的緩沖區請求被(或它們的鍊)
  • 重新初始化和重置連接配接到上遊伺服器(which happens right before creating the request again)
  • 處理的的上遊響應的第一個位和儲存到從上遊伺服器接收有效載荷的指針。
  • 中止請求(這發生在用戶端提前終止)
  • 當nginx從上遊伺服器完成讀取時,完成請求。
  • 修剪的響應體 (e.g. removing a trailer)

        負載均衡子產品連接配接到的proxy_pass處理程式,當一個以上的上遊伺服器符合要求,提供選擇上遊伺服器能力。負載平衡器注冊使能的配置檔案中指令,提供了額外的上遊初始化函數(解析上遊在DNS名稱等),初始化的連接配接結構,決定路由請求到哪裡,并更新統計資訊。目前,nginx的負載平衡支援到上遊伺服器兩個标準的方式:循環和IP哈希。

       上遊和負載平衡處理機制,包括檢測上遊伺服器失敗算法和路由的新請求到其它,雖然很多額外的工作計劃以增強此功能。在一般情況下,負載均衡方面更多工作的計劃,并在nginx的下一版本中在不同的上遊伺服器配置設定負載以及健康檢查的機制将大大改善。

        也有一些其他有趣的子產品,提供了一個額外varibales集合在配置檔案中使用。雖然在nginx的variables在不同的子產品中建立和更新,有兩個子產品的是完全緻力于variables: geo和map。geo子產品友善根據用戶端的IP位址跟蹤用戶端。該子產品可以依賴于用戶端的IP位址建立任意變量。其他子產品,map,允許從其他變量建立變量,基本上能夠做到靈活的映射主機名和其他運作時變量。這種子產品可以被稱為變量的處理程式。

        記憶體配置設定機制實作在一個單一的nginx的worker裡,在一定程度上,受Apache啟發。在一個高層次上描述nginx的記憶體管理應該如下:對于每個連接配接,動态配置設定必要的記憶體緩沖區,連結,用于存儲和處理的請求和響應的頭和身體,然後釋放連接配接釋放後。非常重要是要注意nginx試圖盡可能地避免在存儲器中的複制資料和大部分的資料傳遞由指針的值傳遞,而不是調用memcpy。

        更深一點,一個影響由子產品所産生時,所檢索的内容放置在記憶體存儲器中,然後添加到緩沖區鍊中。後續處理工作也和這個緩沖區鍊相關。緩沖區鍊在nginx是相當複雜的,因為有幾個處理場景,取決子產品類型不同而有所不同。例如,實作消息體過濾器子產品時精确地管理緩沖區是相當棘手的。這樣的子產品隻能在同一時間運作在一個緩沖區(鍊環),它必須決定是否要改寫輸入緩沖器,用一個新配置設定的緩沖區更換緩沖區,或插入一個新的緩沖區之前或之後的緩沖區。為了使事情變得複雜,有時一個子產品會收到幾個緩沖區,是以,它有一個不完整的必須運作在緩沖區鍊。然而,此時的nginx隻提供了一個低級别的API操縱緩沖鍊,是以在做任何實際實作第三方子產品之前,開發人員應該對nginx的這部分神秘代碼相當熟悉。

        對上述方案的說明是總在連接配接整個生命周期都有記憶體配置設定,進而為長期連接配接保持一些額外的記憶體。在同一時間,在一個空閑的保持活動的連接配接,nginx花費的記憶體隻有550個位元組。一個可能的優化将是在nginx的未來版本的為長連接配接重用和共享記憶體緩沖區。

        管理記憶體配置設定的任務是通過nginx的池配置設定器。共享記憶體區域用于接受互斥,緩存中繼資料,SSL會話緩存,相關的資訊帶寬政策和管理(限制)。nginx實作了一個slab配置設定器實施管理共享記憶體配置設定。同時為了共享記憶體的同步安全使用,一些鎖定機制可用(互斥鎖和信号量)。為了組織複雜的資料結構,Nginx還提供了一個紅黑樹的實作。紅 - 黑樹是用來保持緩存中繼資料在共享記憶體中,追蹤用于一對其他任務的非正規表達式的location定義。

        不幸的是,上述所有從未一緻的和簡單的方式描述,使得開發nginx的第三方擴充的工作相當複雜。雖然存在一些很好的nginx的内部檔案 - 例如,埃文·米勒所寫的,這樣的檔案需要一個巨大的逆向工程努力,實作nginx的子產品對許多人來說仍然如魔術一般。

        盡管第三方子產品的開發有一定的困難,nginx的使用者社群最近看到了很多有用的第三方子產品。例如,有一個nginx的嵌入式的Lua語言解釋器子產品,其他子產品,負載均衡,全面支援WebDAV,先進的高速緩存控制和其他有趣的第三方本章作者的鼓勵未來被支援。

5. 經驗教訓

        當 Igor Sysoev開始寫nginx時,大部分軟體使網際網路已經存在,那樣的軟體的體系結構通常遵循的傳統的伺服器和網絡硬體,作業系統,和老的Internet體系結構的通常定義。然而,這并沒有阻擋Igor認為他可以在web伺服器上做些事情。是以,第一個的經驗似乎是顯而易見的,它是這樣的:總是有改進的餘地。

        有着使網絡軟體更好的想法,Igor花了很多時間開發初始代碼的結構和學習在各種作業系統優化代碼的不同方式。十年後,考慮到第1版多年的積極發展, 他正在開發nginx2.0版本原型。很顯然,對未來的軟體産品初始原型的新架構,最初的代碼結構,是非常重要的。

        還有一點值得一提的是,開發要有重點。 Windows版本的nginx在避免在既不是開發商的核心競争力或目标應用上分散開發努力,可能是一個很好的例子。它同樣适用重寫引擎過程中出現多次嘗試增加更多的nginx功能與現有的傳統設定的向後相容性。

        最後但并非最不重要的一點是,值得一提的是,盡管事實上nginx的開發人員社群不是非常大,nginx的第三方子產品和擴充一直是一個nginx受歡迎的非常重要的部分。Evan Miller, Piotr Sikora, Valery Kholodkov, Zhang Yichun (agentzh) 和其他優秀的軟體工程師所做的工作備受nginx的使用者社群和它的最初的開發人員贊賞。

6.參考

  Building nginx from Sources   http://nginx.org/en/docs/configure.html

linux/centos安裝nginx常見錯誤及解決辦法  http://www.myhack58.com/Article/sort099/sort0102/2014/42239.htm

http://www.2cto.com/os/201308/238933.html

http://tengine.taobao.org/

Linux redhat安裝Nginx http://minjiechenjava.iteye.com/blog/2040555

錯誤現象:

./configure: error: SSL modules require the OpenSSL library.   You can either do not enable the modules, or install the OpenSSL library   into the system, or build the OpenSSL library statically from the source   with nginx by using --with-openssl=<path> option.  

安裝openssl:

sudo apt-get install libcurl4-openssl-dev  

安裝步驟:

./configure  --prefix=/ROOT/server/nginx/tengine-1.5.2  --with-http_ssl_module

make 

make install

make clean

日志調試版說明 http://tengine.taobao.org/book/appendix_c.html#nginxlinux

./configure  --prefix=/ROOT/server/nginx/tengine-1.5.2-debug  --with-http_ssl_module  --with-debug

make 

make install

make clean