簡單理解I/O模型


服務端I/O:

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

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

簡單理解I/O模型

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

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

  1. 將數據從文件先加載至內核內存空間(緩衝區),等待數據準備完成,時間較長
  2. 將數據從內核緩衝區複製到用戶空間的進程的內存中,時間較短

系統I/O模型:

  同步/異步:關注的是消息通信機制,即在等待一件事情的處理結果之前,被調用者是否提供通知機制。
同步:進程發出請求調用後,等待內核返回響應之後再進行下一個請求。如果內核不進行返回數據,則進程一直處於等待狀態。
異步:進程發出請求調用後,不等待內核返回響應,直接處理下一個請求。(Nginx是異步處理機制)

  阻塞/非阻塞:關注調用者在等待結果返回之前所處的狀態。
阻塞:I/O操作需要徹底完成之後才返回到用戶空間,操作返回之前,調用者處於被掛起狀態,無法執行其他操作。
非阻塞:I/O操作被調用後立即返回給用戶一個狀態值,無需等待完成,最終的調用結果返回之前,調用者不會被掛起,可以執行其他操作。

網絡I/O模型

同步阻塞型I/O模型(blocking IO)

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

  簡單理解就是:程序向內核發送I/O請求後一直處於等待內核響應的狀態,如果內核處理請求的I/O操作不能立即返回,則進程將一直處於等待狀態而不再接收新的請求,並由進程輪詢查看I/O是否完成,完成後進程將I/O結果返回給Client,在I/O沒有返回期間進程不能接收其他客戶的請求,而且是由進程自己去看I/O是否完成,這種方式簡單,但是比較慢,所以用的比較少。

簡單理解I/O模型

同步非阻塞型I/O模型(nonblocking IO)

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

  簡單理解就是:程序向內核發送I/O請求後一直等待內核響應,如果內核處理請求的I/O操作不能理解返回I/O結果,進程將不再等待,繼續處理其他請求,但是仍然需要進程每隔一段時間就要查看內核I/O是否完成。這是一種比較浪費CPU的一種方式:輪詢的時間不好把握,如果設置的等待時間過長,程序響應延遲就過大;設置的時間過短,就會造成過於頻繁的重試。

簡單理解I/O模型

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

  I/O多路複用型就是我們說的select,poll,epoll,有些地方也稱這種IO方式爲event driven IO。select/epoll的好處就在於單個process就可以同時處理多個網絡連接的IO。它的基本原理就是select,poll,epoll這個function會不斷的輪詢所負責的所有socket,當某個socket有數據到達了,就通知用戶進程。 當用戶進程調用了select,那麼整個進程會被block,而同時,kernel會“監視”所有select負責的socket,當任何一個socket中的數據準備好了,select就會返回。這個時候用戶進程再調用read操作,將數據從kernel拷貝到用戶進程。比如:Apache prefork是此模式的select,work是poll模式。

  簡單理解即:I/O多路複用機制可以同時監控多個描述符,當某個描述符就緒(讀或者寫就緒),則立即通知相應程序進行讀或者寫操作。但select、poll、epoll本質上都是同步I/O,因爲他們都需要在讀寫事件就緒後自己負責進行讀寫,也就是說這個讀寫過程是阻塞的。

簡單理解I/O模型

信號驅動式IO(signal-driven IO)

  信號驅動IO就是用戶進程可以通過sigaction系統調用註冊一個信號處理程序,然後主程序可以繼續向下執行,當有IO操作準備就緒時,由內核通知觸發一個SIGIO信號處理程序執行,然後將用戶進程所需要的數據從內核空間拷貝到用戶空間 此模型的優勢在於等待數據報到達期間進程不被阻塞。用戶主程序可以繼續執行,只要等待來自信號處理函數的通知。

  1. 優點:線程並沒有在等待數據時被阻塞,內核直接返回調用接收信號,不影響進程繼續處理其他請求因此可以提高資源的利用率

  2. 缺點:信號 I/O 在大量 IO 操作時可能會因爲信號隊列溢出導致沒法通知

  簡單理解就是:程序進程通過在內核上調用sigaction函數,向內核發送I/O調用後,不用等待內核響應,可以繼續接受其他請求,內核收到進程請求後進行的I/O如果不能立即返回,就由內核等待結果,直到I/O完成後內核再通知進程。apache event就是這個模式。

簡單理解I/O模型

異步(非阻塞)IO(asynchronous IO)

  相對於同步IO,異步IO不是順序執行。用戶進程進行aio_read系統調用之後,無論內核數據是否準備好,都會直接返回給用戶進程,然後用戶態進程可以去做別的事情。等到socket數據準備好了,內核直接複製數據給進程,然後從內核向進程發送通知。IO兩個階段,進程都是非阻塞的。 Linux提供了AIO庫函數實現異步,但是用的很少。目前有很多開源的異步IO庫,例如libevent、libev、libuv。

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

簡單理解I/O模型

nginx事件驅動模型實現方式

  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)模型。

常用模型彙總

簡單理解I/O模型

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章