NGINX之一----IO五種模型和select與epoll工作原理(引入nginx)


用戶速度體驗的1-3-10原則

性能影響

有很多研究都表明,性能對用戶的行為有很大的影響:
79%的用戶表示不太可能再次打開一個緩慢的網站
47%的用戶期望網頁能在2秒鍾以內加載
40%的用戶表示如果加載時間超過三秒鍾,就會放棄這個網站
頁面加載時間延遲一秒可能導致轉換損失7%,頁面瀏覽量減少11%
8秒定律:用戶訪問一個網站時,如果等待網頁打開的時間超過8秒,會有超過30%的用戶放棄等待

影響用戶體驗的幾個因素

客戶端硬件配置
客戶端網絡速率
客戶端與服務端距離
服務端網絡速率
服務端硬件配置
服務端架構設計
服務端應用程序工作模式
服務端並發數量
服務端響應文件大小及數量
服務端I/O壓力

Httpd MPM

httpd MPM:
prefork:進程模型,兩級結構,主進程master負責生成子進程,每個子進程負責響應一個請求
worker:線程模型,三級結構,主進程master負責生成子進程,每個子進程負責生成多個線程,每個線程響應一個請求
event:線程模型,三級結構,主進程master負責生成子進程,每個子進程響應多個請求

top命令可以查看當前機器的開機時間時長,負載情況:load average:每1/5/15分鍾負載情況。

服務端處理網絡請求過程 

1、I/O在計算機中指Input/Output, IOPS (Input/Output Per Second)即每秒的輸入輸出量(或讀寫次數),是衡量磁盤性能的主要指標之一。IOPS是指單位時間內系統能處理的I/O請求數量,一般以每秒處理的I/O請求數量為單位,I/O請求通常為讀或寫數據操作請求。

2、一次完整的I/O是用戶空間的進程數據與內核空間的內核數據的報文的完整交換,但是由於內核空間與用戶空間是嚴格隔離的,所以其數據交換過程中不能由用戶空間的進程直接調用內核空間的內存數據,而是需要經歷一次從內核空間中的內存數據copy到用戶空間的進程內存當中,所以簡單說I/O就是把數據從內核空間中的內存數據復制到用戶空間中進程的內存當中。

而網絡通信就是網絡協議棧到用戶空間進程的IO就是網絡IO

3、磁盤I/O是進程向內核發起系統調用,請求磁盤上的某個資源比如是文件或者是圖片,然后內核通過相應的驅動程序將目標圖片加載到內核的內存空間,加載完成之后把數據從內核內存再復制給進程內存,如果是比較大的數據也需要等待時間。

 PIO:程序的輸入輸出模型。

服務端處理網絡請求過程 

  獲取請求數據,客戶端與服務器建立連接發出請求,服務器接受請求(1-3)
構建響應,當服務器接收完請求,並在用戶空間處理客戶端的請求,直到構建響應完成(4)
返回數據,服務器將已構建好的響應再通過內核空間的網絡 I/O 發還給客戶端(5-7)

I/O介紹

網絡IO:本質是socket文件讀取

磁盤IO:

每次IO,都要經由兩個階段:

第一步:將數據從文件先加載至內核內存空間(緩沖區),等待數據准備完成,時間較長
第二步:將數據從內核緩沖區復制到用戶空間的進程的內存中,時間較短

I/O模型

同步/異步:關注的是消息通信機制

同步:synchronous,調用者等待被調用者返回消息,才能繼續執行
異步:asynchronous,被調用者通過狀態、通知或回調機制主動通知調用者被調用者的運行狀態

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

阻塞:blocking,指IO操作需要徹底完成后才返回到用戶空間,調用結果返回之前,調用者被掛起
非阻塞:nonblocking,指IO操作被調用后立即返回給用戶一個狀態值,無需等到IO操作徹底完成,最終的調用結果返回之前,調用者不會被掛起

I/O模型:

阻塞型、非阻塞型、復用型、信號驅動型、異步

同步阻塞IO模型 

   阻塞原理:

    1、阻塞IO模型是最簡單的IO模型,用戶線程在內核進行IO操作時被阻塞。

    2、用戶線程通過系統調用read發起IO讀操作,由用戶空間轉到內核空間。內核等到數據包到達后,然后將接收的數據拷貝到用戶空間,完成read操作。

3、用戶需要等待read將數據讀取到buffer后,才繼續處理接收的數據。整個IO請求的過程中,用戶線程是被阻塞的,這導致用戶在發起IO請求時,不能做任何事情,對CPU的資源利用率不夠。

   優缺點:

優點:程序簡單,在阻塞等待數據期間進程/線程掛起,基本不會占用 CPU 資源。
缺點:每個連接需要獨立的進程/線程單獨處理,當並發請求量大時為了維護程序,內存、線程切換開銷較大,這種模型在實際生產中很少使用,apache 的preforck使用的是這種模式。

  同步阻塞:

     程序向內核發送IO請求后一直等待內核響應,如果內核處理請求的IO操作不能立即返回,則進程將一直等待並不再接受新的請求,並由進程輪訓查看IO是否完成,完成后進程將IO結果返回給Client,

     在IO沒有返回期間進程不能接受其他客戶的請求,而且是有進程自己去查看IO是否完成,這種方式簡單,但是比較慢,用的比較少。

 同步非阻塞IO模型

非阻塞原理:

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

同步非阻塞:

程序向內核發送請IO求后一直等待內核響應,如果內核處理請求的IO操作不能立即返回IO結果,進程將不再等待,而且繼續處理其他請求,但是仍然需要進程隔一段時間就要查看內核IO是否完成。

 

 IO多路復用模型

   IO多路復用原理:

  1、IO多路復用(IO Multiplexing) :是一種機制,程序注冊一組socket文件描述符給操作系統,表示“我要監視這些fd是否有IO事件發生,有了就告訴程序處理”。

  2、IO多路復用是要和NIO一起使用的。NIO和IO多路復用是相對獨立的。NIO僅僅是指IO API總是能立刻返回,不會被Blocking;而IO多路復用僅僅是操作系統提供的一種便利的通知機制。操作系統並不會強制這倆必須得一起用,可以只用IO多路復用 + BIO,這時還是當前線程被卡住。IO多路復用和NIO是要配合一起使用才有實際意義。

 3、IO多路復用是指內核一旦發現進程指定的一個或者多個IO條件准備讀取,就通知該進程。

 4、多個連接共用一個等待機制,本模型會阻塞進程,但是進程是阻塞在select或者poll這兩個系統調用上,而不是阻塞在真正的IO操作上。

 5、用戶首先將需要進行IO操作添加到select中,同時等待select系統調用返回。當數據到達時,IO被激活,select函數返回。用戶線程正式發起read請求,讀取數據並繼續執行。

注意:Apache prefork是此模式1 的select,work是poll模式。

  1、從流程上來看,使用select函數進行IO請求和同步阻塞模型沒有太大的區別,甚至還多了添加監視IO,以及調用select函數的額外操作,效率更差。並且阻塞了兩次,但是第一次阻塞在select上時,select可以監控多個IO上是否已有IO操作准備就緒,即可達到在同一個線程內同時處理多個IO請求的目的。而不像阻塞IO那種,一次只能監控一個IO。

  2、雖然上述方式允許單線程內處理多個IO請求,但是每個IO請求的過程還是阻塞的(在select函數上阻塞),平均時間甚至比同步阻塞IO模型還要長。如果用戶線程只是注冊自己需要的IO請求,然后去做自己的事情,等到數據到來時再進行處理,則可以提高CPU的利用率。

  3、IO多路復用是最常使用的IO模型,但是其異步程度還不夠“徹底”,因它使用了會阻塞線程的select系統調用。因此IO多路復用只能稱為異步阻塞IO模型,而非真正的異步IO

信號驅動IO模型 

 信號驅動IO模型原理:

   信號驅動IO:signal-driven I/O

1、用戶進程可以通過sigaction系統調用注冊一個信號處理程序,然后主程序可以繼續向下執行,當有IO操作准備就緒時,由內核通知觸發一個SIGIO信號處理程序執行,然后將用戶進程所需要的數據從內核空間拷貝到用戶空間。

2、此模型的優勢在於等待數據報到達期間進程不被阻塞。用戶主程序可以繼續執行,只要等待來自信號處理函數的通知。

3、對於 TCP 而言,信號驅動的 I/O 方式近乎無用,因為導致這種通知的條件為數眾多,每一個來進行判別會消耗很大資源,與前幾種方式相比優勢盡失。

優點:線程並沒有在等待數據時被阻塞,可以提高資源的利用率。
缺點:信號 I/O 在大量 IO 操作時可能會因為信號隊列溢出導致沒法通知。

異步阻塞:程序進程向內核發送IO調用后,不用等待內核響應,可以繼續接受其他請求,內核收到進程請求后進行的IO如果不能立即返回,就由內核等待結果,直到IO完成后內核再通知進程,apache event是此模式。

 異步IO(非阻塞)模型

原理:

   1、異步IO與信號驅動IO最主要的區別是信號驅動IO是由內核通知應用程序何時可以進行IO操作,而異步IO則是由內核告訴用戶線程IO操作何時完成。信號驅動IO當內核通知觸發信號處理程序時,信號處理程序還需要阻塞在從內核空間緩沖區拷貝數據到用戶空間緩沖區這個階段,而異步IO直接是在第二個階段完成后,內核直接通知用戶線程可以進行后續操作了。

2、由 POSIX 規范定義,應用程序告知內核啟動某個操作,並讓內核在整個操作(包括將數據從內核拷貝到應用程序的緩沖區)完成后通知應用程序。

優缺點:

優點:異步 I/O 能夠充分利用 DMA 特性,讓 I/O 操作與計算重疊。
缺點:要實現真正的異步 I/O,操作系統需要做大量的工作。目前 Windows 下通過 IOCP 實現了真正的異步 I/O,在 Linux 系統下,Linux 2.6才引入,目前 AIO 並不完善,因此在 Linux 下實現高並發網絡編程時以 IO 復用模型模式+多線程任務的架構基本可以滿足需求。

異步非阻塞:程序進程向內核發送IO調用后,不用等待內核響應,可以繼續接受其他請求,內核調用的IO如果不能立即返回,內核會繼續處理其他事物,直到IO完成后將結果通知給內核,內核在將IO完成的結果返回給進程,期間進程可以接受新的請求,內核也可以處理新的事物,因此相互不影響,可以實現較大的同時並實現較高的IO復用,因此異步非阻塞使用最多的一種通信方式。

 五種I/O模型對比

這五種 I/O 模型中,越往后,阻塞越少,理論上效率也是最優前四種屬於同步 I/O,因為其中真正的 I/O 操作(recvfrom)將阻塞進程/線程,只有異步 I/O 模型才與 POSIX 定義的異步 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庫的IO效率不隨描述符數目增加而線性下降,因為它只會對內核上報的“活躍”的描述符進行操作。
4、rtsig:
不是一個常用事件驅動,最大隊列1024,不是很常用
5、kqueue:
用於支持BSD系列平台的高校事件驅動模型,主要用在FreeBSD 4.1及以上版本、OpenBSD 2.0級以上版本,
NetBSD級以上版本及Mac OS X 平台上,該模型也是poll庫的變種,因此和epoll沒有本質上的區別,都是通
過避免輪訓操作提供效率。
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)模型。

常用模型匯總 

 常用模型對比

水平觸發--單次通知

邊緣觸發--多次通知

   對比:

Select:POSIX所規定,目前幾乎在所有的平台上支持,其良好跨平台支持也是它的一個優點,本質上是通過設置或者檢查存放fd標志位的數據結構來進行下一步處理。

缺點

1、單個進程能夠監視的文件描述符的數量存在最大限制,在Linux上一般為1024,可以通過修改宏定義FD_SETSIZE,再重新編譯內核實現,但是這樣也會造成效率的降低
2、單個進程可監視的fd數量被限制,默認是1024,修改此值需要重新編譯內核
3、對socket是線性掃描,即采用輪詢的方法,效率較低
4、select 采取了內存拷貝方法來實現內核將 FD 消息通知給用戶空間,這樣一個用來存放大量fd的數據結構,這樣會使得用戶空間和內核空間在傳遞該結構時復制開銷大

  poll:

1、本質上和select沒有區別,它將用戶傳入的數組拷貝到內核空間,然后查詢每個fd對應的設備狀態
2、其沒有最大連接數的限制,原因是它是基於鏈表來存儲的
3、大量的fd的數組被整體復制於用戶態和內核地址空間之間,而不管這樣的復制是不是有意義
4、poll特點是“水平觸發”,如果報告了fd后,沒有被處理,那么下次poll時會再次報告該fd
5、select是邊緣觸發即只通知一次

epoll:在Linux 2.6內核中提出的select和poll的增強版本

1、支持水平觸發LT和邊緣觸發ET,最大的特點在於邊緣觸發,它只告訴進程哪些fd剛剛變為就需態,並且只會通知一次
2、使用“事件”的就緒通知方式,通過epoll_ctl注冊fd,一旦該fd就緒,內核就會采用類似callback的回調機制來激活該fd,epoll_wait便可以收到通知

優點:

1、沒有最大並發連接的限制:能打開的FD的上限遠大於1024(1G的內存能監聽約10萬個端口),具體查看/proc/sys/fs/file-max,此值和系統內存大小相關
2、效率提升:非輪詢的方式,不會隨着FD數目的增加而效率下降;只有活躍可用的FD才會調用callback函數,即epoll最大的優點就在於它只管理“活躍”的連接,而跟連接總數無關
3、內存拷貝,利用mmap(Memory Mapping)加速與內核空間的消息傳遞;即epoll使用mmap減少復制開銷

MMAP介紹

mmap()系統調用使得進程之間通過映射同一個普通文件實現共享內存。普通文件被映射到進程地址空間后,進程可以向訪問普通內存一樣對文件進行訪問。

零拷貝

1、傳統Linux中 I/O 的問題

    2、傳統的 Linux 系統的標准 I/O 接口(read、write)是基於數據拷貝的,也就是數據都是 copy_to_user 或者 copy_from_user,這樣做的好處是,通過中間緩存的機制,減少磁盤 I/O 的操作,但是壞處也很明顯,大量數據的拷貝,用戶態和內核態的頻繁切換,會消耗大量的 CPU 資源,嚴重影響數據傳輸的性能,統計表明,在Linux協議棧中,數據包在內核態和用戶態之間的拷貝所用的時間甚至占到了數據包整個處理流程時間的57.1%。

什么是零拷貝?

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

原始數據拷貝操作 

MMAP:Memory Mapping 

SENDFILE

 DMA 輔助的 SENDFILE

 

 

 

 

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM