五種網路io模型

風靈使發表於2018-07-12

由於最近再看nginx,其採用了優於apacheselect網路io模型,所以稍微瞭解了下網路io的模型的基礎知識。

首先,介紹幾種常見的I/O模型及其區別,如下:

    blocking I/O

    nonblocking I/O

    I/O multiplexing (select and poll)

    signal driven I/O (SIGIO)

    asynchronous I/O (the POSIX aio_functions)

不管LinuxIO模型的阻塞同步分類是如何分類,幾種IO模型的具體實現是確定的。這裡借用《Unix 網路程式設計:卷一》的圖片說明。

1 阻塞式IO模型

clip_image001

這個模型也是最容易理解的

程式呼叫和我們基本的程式編寫是一致的:

fd = connect()

write(fd)

read(fd)

close(fd)

程式的read必須在write之後執行,當write阻塞住了,read就不能執行下去

2 非阻塞IO模型

clip_image002

從圖中可以看出來,這是一個輪詢的過程

每次使用者詢問核心是否有資料包準備好(檔案描述符緩衝區是否就緒),當資料包準備好的時候,就進行拷貝資料包的操作。當資料包沒有準備好的時候,也不阻塞程式,核心直接返回未準備就緒的訊號,等待使用者程式的下一次輪詢。

3 I/O複用模型

clip_image003

IO複用模型是多了一個select函式,select函式有一個引數是檔案描述符集合,意思就是對這些的檔案描述符進行迴圈監聽,當某個檔案描述符就緒的時候,就對這個檔案描述符進行處理。

這種IO模型是屬於阻塞的IO。但是由於它可以對多個檔案描述符進行阻塞監聽,所以它的效率比阻塞IO模型高效。

4 訊號驅動IO模型

clip_image004

訊號驅動IO模型是應用程式告訴核心:當你的資料包準備好的時候,給我傳送一個訊號哈,並且呼叫我的訊號處理函式來獲取資料包。這個模型是由訊號進行驅動。

5 非同步IO模型

clip_image005

非同步IO使用的不再是readwrite的系統介面了,應用工程式呼叫aio_XXXX系列的核心介面。

當應用程式呼叫aio_read的時候,核心一方面去取資料包內容返回,另外一方面將程式控制權還給應用程式,應用程式繼續處理其他事務。這樣應用程式就是一種非阻塞的狀態。

當核心的資料包就緒的時候,是由核心將資料包拷貝到應用程式中,返回給aio_read中定義好的函式處理程式。很少有linux系統支援,windowsIOCP則是此模型

完全非同步的I/O複用機制,因為縱觀上面其它四種模型,至少都會在由kernel copy data to appliction時阻塞。而該模型是當copy完成後才通知application,可見是純非同步的。好像只有windows的完成埠是這個模型,效率也很出色。

下面是以上五種模型的比較
這裡寫圖片描述

可以看出,越往後,阻塞越少,理論上效率也是最優。

=====================分割線==================================

5種模型的比較比較清晰了,剩下的就是把select,epoll,iocp,kqueue按號入座那就OK了。

selectiocp分別對應第3種與第5種模型,那麼epollkqueue呢?其實也於select屬於同一種模型,只是更高階一些,可以看作有了第4種模型的某些特性,如callback機制。

那麼,為什麼epoll,kqueueselect高階?

答案是,他們無輪詢。因為他們用callback取代了。想想看,當套接字比較多的時候,每次select()都要通過遍歷FD_SETSIZESocket來完成排程,不管哪個Socket是活躍的,都遍歷一遍。這會浪費很多CPU時間。如果能給套接字註冊某個回撥函式,當他們活躍時,自動完成相關操作,那就避免了輪詢,這正是epollkqueue做的。

windows or *nix (IOCP or kqueue/epoll)?

誠然,WindowsIOCP非常出色,目前很少有支援asynchronous I/O的系統,但是由於其系統本身的侷限性,大型伺服器還是在UNIX下。而且正如上面所述,kqueue/epollIOCP相比,就是多了一層從核心copy資料到應用層的阻塞,從而不能算作asynchronous I/O類。但是,這層小小的阻塞無足輕重,kqueueepoll已經做得很優秀了。

提供一致的介面,IO Design Patterns

實際上,不管是哪種模型,都可以抽象一層出來,提供一致的介面,廣為人知的有ACE,Libevent這些,他們都是跨平臺的,而且他們自動選擇最優的I/O複用機制,使用者只需呼叫介面即可。說到這裡又得說說2個設計模式,Reactor and Proactor。有一篇經典文章http://www.artima.com/articles/io_design_patterns.html值得閱讀,LibeventReactor模型,ACE提供Proactor模型。實際都是對各種I/O複用機制的封裝。

Java nio包是什麼I/O機制?

我曾天真的認為java nio封裝的是IOCP。。現在可以確定,目前的java本質是select()模型,可以檢查/jre/bin/nio.dll得知。至於java伺服器為什麼效率還不錯。。我也不得而知,可能是設計得比較好吧。。-_-。

=====================分割線==================================

總結一些重點:

  • 只有IOCPasynchronous I/O,其他機制或多或少都會有一點阻塞。
  • select低效是因為每次它都需要輪詢。但低效也是相對的,視情況而定,也可通過良好的設計改善
  • epoll, kqueueReacor模式,IOCPProactor模式。
  • java nio包是select模型。。

相關文章