1. 程式人生 > 其它 >web服務之NginX介紹

web服務之NginX介紹

I/O 模型相關概念

同步/非同步:關注的是訊息通訊機制,即呼叫者在等待一件事情的處理結果時,被呼叫者是否提供完成狀態的通知。

同步:synchronous,被呼叫者並不提供事件的處理結果相關的通知訊息,需要呼叫者主動詢問事
情是否處理完成
非同步:asynchronous,被呼叫者通過狀態、通知或回撥機制主動通知呼叫者被呼叫者的執行狀態

阻塞/非阻塞:關注呼叫者在等待結果返回之前所處的狀態

阻塞:blocking,指IO操作需要徹底完成後才返回到使用者空間,呼叫結果返回之前,呼叫者被掛起,幹不了別的事情。
非阻塞:nonblocking,指IO操作被呼叫後立即返回給使用者一個狀態值,而無需等到IO操作徹底完成,在最終的呼叫結果返回之前,呼叫者不會被掛起,可以去做別的事情。

網路 I/O 模型

阻塞型、非阻塞型、複用型、訊號驅動型、非同步

阻塞IO模型是最簡單的I/O模型,使用者執行緒在核心進行IO操作時被阻塞
使用者執行緒通過系統呼叫read發起I/O讀操作,由使用者空間轉到核心空間。核心等到資料包到達後,然後將
接收的資料拷貝到使用者空間,完成read操作
使用者需要等待read將資料讀取到buffer後,才繼續處理接收的資料。整個I/O請求的過程中,使用者執行緒是
被阻塞的,這導致使用者在發起IO請求時,不能做任何事情,對CPU的資源利用率不夠
優點:程式簡單,在阻塞等待資料期間程序/執行緒掛起,基本不會佔用 CPU 資源
缺點:每個連線需要獨立的程序/執行緒單獨處理,當併發請求量大時為了維護程式,記憶體、執行緒切換開銷
較大,apache 的preforck使用的是這種模式。

同步阻塞:程式向核心傳送I/O請求後一直等待核心響應,如果核心處理請求的IO操作不能立即返回,則程序將
一直等待並不再接受新的請求,並由程序輪訓檢視I/O是否完成,完成後程序將I/O結果返回給Client,在IO
沒有返回期間程序不能接受其他客戶的請求,而且是有程序自己去檢視I/O是否完成,這種方式簡單,但是比
較慢,用的比較少。

使用者執行緒發起IO請求時立即返回。但並未讀取到任何資料,使用者執行緒需要不斷地發起IO請求,直到資料
到達後,才真正讀取到資料,繼續執行。即 “輪詢”機制存在兩個問題:如果有大量檔案描述符都要等,
那麼就得一個一個的read。這會帶來大量的Context Switch(read是系統呼叫,每呼叫一次就得在使用者
態和核心態切換一次)。輪詢的時間不好把握。這裡是要猜多久之後資料才能到。等待時間設的太長,
程式響應延遲就過大;設的太短,就會造成過於頻繁的重試,乾耗CPU而已,是比較浪費CPU的方式,一
般很少直接使用這種模型,而是在其他IO模型中使用非阻塞IO這一特性。

非阻塞:程式向核心傳送請I/O求後一直等待核心響應,如果核心處理請求的IO操作不能立即返回IO結果,進
程將不再等待,而且繼續處理其他請求,但是仍然需要程序隔一段時間就要檢視核心I/O是否完成。

在設定連線為非阻塞時,當應用程序系統呼叫recvfrom 沒有資料返回時,核心會立即
返回一個EWOULDBLOCK 錯誤,而不會一直阻塞到資料準備好。如上圖在第四次呼叫時有一個數據報準備
好了,所以這時資料會被複制到應用程序緩衝區,於是recvfrom 成功返回資料
當一個應用程序這樣迴圈呼叫recvfrom 時,稱之為輪詢polling 。這麼做往往會耗費大量CPU時間,
實際使用很少

多路複用 I/O 型(I/O multiplexing)

I/O multiplexing 主要包括:select,poll,epoll三種系統呼叫,select/poll/epoll的好處就在於單個
process就可以同時處理多個網路連線的IO。
它的基本原理就是select/poll/epoll這個function會不斷的輪詢所負責的所有socket,當某個socket有數
據到達了,就通知使用者程序。
當用戶程序呼叫了select,那麼整個程序會被block,而同時,kernel會“監視”所有select負責的socket,
當任何一個socket中的資料準備好了,select就會返回。這個時候使用者程序再呼叫read操作,將資料從
kernel拷貝到使用者程序。
Apache prefork是此模式的select,work是poll模式。

IO多路複用(IO Multiplexing) :是一種機制,程式註冊一組socket檔案描述符給作業系統,表示“我要
監視這些fd是否有IO事件發生,有了就告訴程式處理”
IO多路複用一般和NIO一起使用的。NIO和IO多路複用是相對獨立的。NIO僅僅是指IO API總是能立刻返回,
不會被Blocking;而IO多路複用僅僅是作業系統提供的一種便利的通知機制。作業系統並不會強制這倆必須得
一起用,可以只用IO多路複用 + BIO,這時還是當前執行緒被卡住。IO多路複用和NIO是要配合一起使用才有
實際意義
IO多路複用是指核心一旦發現程序指定的一個或者多個IO條件準備讀取,就通知該程序
多個連線共用一個等待機制,本模型會阻塞程序,但是程序是阻塞在select或者poll這兩個系統呼叫上,而
不是阻塞在真正的IO操作上
使用者首先將需要進行IO操作新增到select中,同時等待select系統呼叫返回。當資料到達時,IO被啟用,
select函式返回。使用者執行緒正式發起read請求,讀取資料並繼續執行
從流程上來看,使用select函式進行IO請求和同步阻塞模型沒有太大的區別,甚至還多了新增監視IO,以及
呼叫select函式的額外操作,效率更差。並且阻塞了兩次,但是第一次阻塞在select上時,select可以監
控多個IO上是否已有IO操作準備就緒,即可達到在同一個執行緒內同時處理多個IO請求的目的。而不像阻塞IO
那種,一次只能監控一個IO
雖然上述方式允許單執行緒內處理多個IO請求,但是每個IO請求的過程還是阻塞的(在select函式上阻塞),
平均時間甚至比同步阻塞IO模型還要長。如果使用者執行緒只是註冊自己需要的IO請求,然後去做自己的事情,等
到資料到來時再進行處理,則可以提高CPU的利用率
IO多路複用是最常使用的IO模型,但是其非同步程度還不夠“徹底”,因它使用了會阻塞執行緒的select系統調
用。因此IO多路複用只能稱為非同步阻塞IO模型,而非真正的非同步IO

優缺點
優點:可以基於一個阻塞物件,同時在多個描述符上等待就緒,而不 是使用多個執行緒(每個檔案描述符一個執行緒),這樣可以大大節省 系統資源

缺點:當連線數較少時效率相比多執行緒+阻塞 I/O 模型效率較低,可能延遲更大,因為單個連線處理需要 2 次系統呼叫,佔用時間會有增加

IO多路複用適用如下場合:

當客戶端處理多個描述符時(一般是互動式輸入和網路套介面),必須使用I/O複用
當一個客戶端同時處理多個套接字時,此情況可能的但很少出現
當一個伺服器既要處理監聽套接字,又要處理已連線套接字,一般也要用到I/O複用
當一個伺服器即要處理TCP,又要處理UDP,一般要使用I/O複用
當一個伺服器要處理多個服務或多個協議,一般要使用I/O複用

I/O常見實現

Nginx支援在多種不同的作業系統實現不同的事件驅動模型,但是其在不同的作業系統甚至是不同的系
統版本上面的實現方式不盡相同,主要有以下實現方式:

1、select:
select庫是在linux和windows平臺都基本支援的 事件驅動模型庫,並且在介面的定義也基本相同,只是部
分引數的含義略有差異,最大併發限制1024,是最早期的事件驅動模型。
2、poll:
在Linux 的基本驅動模型,windows不支援此驅動模型,是select的升級版,取消了最大的併發限制,在編
譯nginx的時候可以使用--with-poll_module和--without-poll_module這兩個指定是否編譯select
庫。
3、epoll:
epoll是庫是Nginx伺服器支援的最高效能的事件驅動庫之一,是公認的非常優秀的事件驅動模型,它和
select和poll有很大的區別,epoll是poll的升級版,但是與poll有很大的區別.
epoll的處理方式是建立一個待處理的事件列表,然後把這個列表發給核心,返回的時候在去輪訓檢查這個
表,以判斷事件是否發生,epoll支援一個程序開啟的最大事件描述符的上限是系統可以開啟的檔案的最大
數,同時epoll庫的I/O效率不隨描述符數目增加而線性下降,因為它只會對核心上報的“活躍”的描述符進行
操作。
4、kqueue:
用於支援BSD系列平臺的高校事件驅動模型,主要用在FreeBSD 4.1及以上版本、OpenBSD 2.0級以上版
本,NetBSD級以上版本及Mac OS X 平臺上,該模型也是poll庫的變種,因此和epoll沒有本質上的區別,
都是通過避免輪訓操作提供效率。
5、rtsig:
不是一個常用事件驅動,最大佇列1024,不是很常用
6、/dev/poll:
用於支援unix衍生平臺的高效事件驅動模型,主要在Solaris 平臺、HP/UX,該模型是sun公司在開發
Solaris系列平臺的時候提出的用於完成事件驅動機制的方案,它使用了虛擬的/dev/poll裝置,開發人員將
要見識的檔案描述符加入這個裝置,然後通過ioctl()呼叫來獲取事件通知,因此執行在以上系列平臺的時候
請使用/dev/poll事件驅動機制。
7、eventport:
該方案也是sun公司在開發Solaris的時候提出的事件驅動庫,只是Solaris 10以上的版本,該驅動庫看防
止核心崩潰等情況的發生。
8、Iocp:
Windows系統上的實現方式,對應第5種(非同步I/O)模型。
xxx select poll epoll
操作方式 遍歷 遍歷 回撥
底層實現 陣列 連結串列 雜湊表
IO效率 每次呼叫都進行線性遍歷,時間複雜度為O(n) 同左 事件通知方式,每當fd就緒,系統註冊的回撥函式就會被呼叫,將就緒的fd放到rdist裡,時間複雜度O(1)
最大連線數 1024(x86),2048(x64) 無上限 無上限
fd拷貝 每次呼叫select都需要把fd集合從使用者拷貝到核心態 每次呼叫poll,都需要把fd集合從使用者態拷貝到核心態 呼叫epoll_ctl時拷貝進核心並儲存,之後每次epoll_wait不拷貝
Select:
POSIX所規定,目前幾乎在所有的平臺上支援,其良好跨平臺支援也是它的一個優點,本質上是通過設定或者
檢查存放fd標誌位的資料結構來進行下一步處理
缺點
單個程序能夠監視的檔案描述符的數量存在最大限制,在Linux上一般為1024,可以通過修改巨集定義
FD_SETSIZE,再重新編譯核心實現,但是這樣也會造成效率的降低
單個程序可監視的fd數量被限制,預設是1024,修改此值需要重新編譯核心
對socket是線性掃描,即採用輪詢的方法,效率較低
select 採取了記憶體拷貝方法來實現核心將 FD 訊息通知給使用者空間,這樣一個用來存放大量fd的資料結
構,這樣會使得使用者空間和核心空間在傳遞該結構時複製開銷大

poll:
本質上和select沒有區別,它將使用者傳入的陣列拷貝到核心空間,然後查詢每個fd對應的裝置狀態
其沒有最大連線數的限制,原因是它是基於連結串列來儲存的
大量的fd的陣列被整體複製於使用者態和核心地址空間之間,而不管這樣的複製是不是有意義
poll特點是“水平觸發”,如果報告了fd後,沒有被處理,那麼下次poll時會再次報告該fd
select是邊緣觸發即只通知一次

epoll:
在Linux 2.6核心中提出的select和poll的增強版本
支援水平觸發LT和邊緣觸發ET,最大的特點在於邊緣觸發,它只告訴程序哪些fd剛剛變為就需態,並且只會通
知一次
使用“事件”的就緒通知方式,通過epoll_ctl註冊fd,一旦該fd就緒,核心就會採用類似callback的回撥
機制來啟用該fd,epoll_wait便可以收到通知
優點:
沒有最大併發連線的限制:能開啟的FD的上限遠大於1024(1G的記憶體能監聽約10萬個埠),具體查
看/proc/sys/fs/file-max,此值和系統記憶體大小相關
效率提升:非輪詢的方式,不會隨著FD數目的增加而效率下降;只有活躍可用的FD才會呼叫callback函式,
即epoll最大的優點就在於它只管理“活躍”的連線,而跟連線總數無關
記憶體拷貝,利用mmap(Memory Mapping)加速與核心空間的訊息傳遞;即epoll使用mmap減少複製開銷

總結:

1、epoll只是一組API,比起select這種掃描全部的檔案描述符,epoll只讀取就緒的檔案描述符,再加入基於事件的就緒通知機制,所以效能比較好
2、基於epoll的事件多路複用減少了程序間切換的次數,使得作業系統少做了相對於使用者任務來說的無用功。
3、epoll比select等多路複用方式來說,減少了遍歷迴圈及記憶體拷貝的工作量,因為活躍連線只佔總併發連線的很小一部分。

最大併發連線數和記憶體有直接關係

範例: select 和epoll 幫助

[root@centos8 ~]# whatis epoll
epoll (7) - I/O event notification facility
[root@centos8 ~]# whatis select
select (2) - synchronous I/O multiplexing
select (3) - synchronous I/O multiplexing
select (3p) - synchronous I/O multiplexing
[root@centos8 ~]# whatis poll
poll (2) - wait for some event on a file descriptor
poll (3p) - input/output multiplexing
[root@centos8 ~]# man 2 select
SELECT(2) Linux Programmer's
Manual SELECT(2)
NAME
select, pselect, FD_CLR, FD_ISSET, FD_SET, FD_ZERO - synchronous I/O
multiplexing
[root@centos8 ~]# man 2 poll
POLL(2) Linux Programmer's
Manual POLL(2)
NAME
poll, ppoll - wait for some event on a file descriptor

零拷貝介紹

零拷貝就是上述問題的一個解決方案,通過儘量避免拷貝操作來緩解 CPU 的壓力。零拷貝並沒有真正做到“0”拷貝,它更多是一種思想,很多的零拷貝技術都是基於這個思想去做的優化

零拷頁相關技術MMAP ( Memory Mapping )

mmap()系統呼叫使得程序之間通過對映同一個普通檔案實現共享記憶體。普通檔案被對映到程序地址空
間後,程序可以向訪問普通記憶體一樣對檔案進行訪問。
mmap是一種記憶體對映檔案的方法,即將一個檔案或者其它物件對映到程序的地址空間,實現檔案磁碟
地址和程序虛擬地址空間中一段虛擬地址的一一對映關係。
實現這樣的對映關係後,程序就可以採用指標的方式讀寫操作這一段記憶體,而系統會自動回寫髒頁面到
對應的檔案磁碟上,即完成了對檔案的操作而不必再呼叫read,write等系統呼叫函式。相反,核心空間
對這段區域的修改也直接反映使用者空間,從而可以實現不同程序間的檔案共享。
記憶體對映減少資料在使用者空間和核心空間之間的拷貝操作,適合大量資料傳輸

SENDFILE

DMA 輔助的 SENDFILE

Nginx 功能介紹

靜態的web資源伺服器html,圖片,js,css,txt等靜態資源
http/https協議的反向代理
結合FastCGI/uWSGI/SCGI等協議反向代理動態資源請求
tcp/udp協議的請求轉發(反向代理)
imap4/pop3協議的反向代理

基礎特性

模組化設計,較好的擴充套件性
高可靠性
支援熱部署:不停機更新配置檔案,升級版本,更換日誌檔案
低記憶體消耗:10000個keep-alive連線模式下的非活動連線,僅需2.5M記憶體
event-driven,aio,mmap,sendfile

Web 服務相關的功能

虛擬主機(server)
支援 keep-alive 和管道連線(利用一個連線做多次請求)
訪問日誌(支援基於日誌緩衝提高其效能)
url rewirte
路徑別名
基於IP及使用者的訪問控制
支援速率限制及併發數限制
重新配置和線上升級而無須中斷客戶的工作程序

Nginx 程序結構

web請求處理機制
多程序方式:伺服器每接收到一個客戶端請求就有伺服器的主程序生成一個子程序響應客戶端,直
到使用者關閉連線,這樣的優勢是處理速度快,子程序之間相互獨立,但是如果訪問過大會導致服務
器資源耗盡而無法提供請求。
多執行緒方式:與多程序方式類似,但是每收到一個客戶端請求會有服務程序派生出一個執行緒來個客
戶方進行互動,一個執行緒的開銷遠遠小於一個程序,因此多執行緒方式在很大程度減輕了web伺服器
對系統資源的要求,但是多執行緒也有自己的缺點,即當多個執行緒位於同一個程序內工作的時候,可
以相互訪問同樣的記憶體地址空間,所以他們相互影響,一旦主程序掛掉則所有子執行緒都不能工作
了,IIS伺服器使用了多執行緒的方式,需要間隔一段時間就重啟一次才能穩定。
Nginx是多程序組織模型,而且是一個由Master主程序和Worker工作程序組成。

主程序(master process)的功能:

對外介面:接收外部的操作(訊號)
對內轉發:根據外部的操作的不同,通過訊號管理 Worker
監控:監控 worker 程序的執行狀態,worker 程序異常終止後,自動重啟 worker 程序
讀取Nginx 配置檔案並驗證其有效性和正確性
建立、繫結和關閉socket連線
按照配置生成、管理和結束工作程序
接受外界指令,比如重啟、升級及退出伺服器等指令
不中斷服務,實現平滑升級,重啟服務並應用新的配置
開啟日誌檔案,獲取檔案描述符
不中斷服務,實現平滑升級,升級失敗進行回滾處理
編譯和處理perl指令碼

工作程序(worker process)的功能:

所有 Worker 程序都是平等的
實際處理:網路請求,由 Worker 程序處理
Worker程序數量:一般設定為核心數,充分利用CPU資源,同時避免程序數量過多,導致程序競爭CPU資源,
增加上下文切換的損耗
接受處理客戶的請求
將請求依次送入各個功能模組進行處理
I/O呼叫,獲取響應資料
與後端伺服器通訊,接收後端伺服器的處理結果
快取資料,訪問快取索引,查詢和呼叫快取資料
傳送請求結果,響應客戶的請求
接收主程式指令,比如重啟、升級和退出等

Nginx 程序間通訊

工作程序是由主程序生成的,主程序使用fork()函式,在Nginx伺服器啟動過程中主程序根據配置檔案決
定啟動工作程序的數量,然後建立一張全域性的工作表用於存放當前未退出的所有的工作程序,主程序生
成工作程序後會將新生成的工作程序加入到工作程序表中,並建立一個單向的管道並將其傳遞給工作進
程,該管道與普通的管道不同,它是由主程序指向工作程序的單向通道,包含了主程序向工作程序發出
的指令、工作程序ID、工作程序在工作程序表中的索引和必要的檔案描述符等資訊。
主程序與外界通過訊號機制進行通訊,當接收到需要處理的訊號時,它通過管道向相關的工作程序傳送
正確的指令,每個工作程序都有能力捕獲管道中的可讀事件,當管道中有可讀事件的時候,工作程序就
會從管道中讀取並解析指令,然後採取相應的執行動作,這樣就完成了主程序與工作程序的互動。

worker程序之間的通訊原理基本上和主程序與worker程序之間的通訊是一樣的,只要worker程序之間能夠
取得彼此的資訊,建立管道即可通訊,但是由於worker程序之間是完全隔離的,因此一個程序想要知道另外一
個程序的狀態資訊,就只能通過主程序來實現。
為了實現worker程序之間的互動,master程序在生成worker程序之後,在worker程序表中進行遍歷,將該
新程序的PID以及針對該程序建立的管道控制代碼傳遞給worker程序中的其他程序,為worker程序之間的通訊做
準備,當worker程序1向worker程序2傳送指令的時候,首先在master程序給它的其他worker程序工作資訊
中找到2的程序PID,然後將正確的指令寫入指向程序2的管道,worker程序2捕獲到管道中的事件後,解析指
令並進行相關操作,這樣就完成了worker程序之間的通訊。
另worker程序可以通過共享記憶體來通訊的,比如upstream中的zone,或者limit_req、limit_conn中的
zone等。作業系統提供了共享記憶體機制

Nginx 啟動和 HTTP 連線建立

Nginx 啟動時,Master 程序,載入配置檔案
Master 程序,初始化監聽的 socket
Master 程序,fork 出多個 Worker 程序
Worker 程序,競爭新的連線,獲勝方通過三次握手,建立 Socket 連線,並處理請求

Nginx 模組介紹

nginx 有多種模組
核心模組:是 Nginx 伺服器正常執行必不可少的模組,提供錯誤日誌記錄 、配置檔案解析 、事件
驅動機制 、程序管理等核心功能
標準HTTP模組:提供 HTTP 協議解析相關的功能,比如: 埠配置 、 網頁編碼設定 、 HTTP響應
頭設定 等等
可選HTTP模組:主要用於擴充套件標準的 HTTP 功能,讓 Nginx 能處理一些特殊的服務,比如: Flash
多媒體傳輸 、解析 GeoIP 請求、 網路傳輸壓縮 、 安全協議 SSL 支援等
郵件服務模組:主要用於支援 Nginx 的 郵件服務 ,包括對 POP3 協議、 IMAP 協議和 SMTP協議
的支援
Stream服務模組: 實現反向代理功能,包括TCP協議代理
第三方模組:是為了擴充套件 Nginx 伺服器應用,完成開發者自定義功能,比如: Json 支援、 Lua 支
持等
nginx高度模組化,但其模組早期不支援DSO機制;1.9.11 版本支援動態裝載和解除安裝

模組分類:

核心模組:core module
標準模組:
HTTP 模組: ngx_http_*
HTTP Core modules #預設功能
HTTP Optional modules #需編譯時指定
Mail 模組: ngx_mail_*
Stream 模組 ngx_stream_*
第三方模組