Netty權威指南:I/O 多路複用技術

無敵天驕發表於2021-04-05

在I/O程式設計過程中,當需要同時處理多個客戶端接入請求時,可以利用 多執行緒或者 I/O多路複用技術進行處理。 I/O多路複用技術透過把多個I/O的阻塞複用到同一個select的阻塞上,從而使得系統在單執行緒的情況下可以同時處理多個客戶端請求。 與傳統的多執行緒/多程式模型比,I/O多路複用的最大優勢是 系統開銷小,系統不需要建立新的額外程式或者執行緒,也不需要維護這些程式和執行緒的執行,降低了系統的維護工作量,節省了系統資源,I/O 多路複用的主要應用場景如下。

  • 伺服器需要同時處理多個處於監聽狀態或者多個連線狀態的套接字;
  • 伺服器需要同時處理多種網路協議的套接字。

目前支援I/O多路複用的系統呼叫有 selectpselectpollepoll,在Linux網路程式設計過程中,很長一段時間都使用 select做輪詢和網路事件通知,然而 select的一些固有缺陷導致了它的應用受到了很大的限制,最終Linux不得不在新的核心版本中尋找 select的替代方案,最終選擇了 epollepoll 與 select 的原理比較類似,為了克服 select的缺點, epoll 作了很多重大改進,現總結如下。

1.支援一一個程式開啟的socket描述符( FD)不受限制(僅受限於作業系統的最大檔案控制程式碼數)。

select最大的缺陷就是單個程式所開啟的FD是有一定限制的,它由 FD_ SETSIZE設定,預設值是1024。 對於那些需要支援上萬個TCP連線的大型伺服器來說顯然太少了。可以選擇修改這個宏然後重新編譯核心,不過這會帶來網路效率的下降。我們也可以透過選擇多程式的方案(傳統的Apache方案)解決這個問題,不過雖然在Linux上建立程式的代價比較小,但仍舊是不可忽視的。另外,程式間的資料交換非常麻煩,對於Java 來說,由於沒有共享記憶體,需要透過 Socket通訊或者其他方式進行資料同步,這帶來了額外的效能損耗,增加了程式複雜度,所以也不是一種完美的解決方案。值得慶幸的是, epoll 並沒有這個限制,它所支援的 FD上限是作業系統的最大檔案控制程式碼數,這個數字遠遠大於 1024。例如,在1GB記憶體的機器,上大約是10萬個控制程式碼左右,具體的值可以透過 cat./proc/sys/fs/file-max察看,通常情況下這個值跟系統的記憶體關係比較大。

2.I/O效率不會隨著FD數目的增加而線性下降。

傳統 select/poll的另一個致命弱點,就是當你擁有一個很大的 socket集合時,由於網路延時或者鏈路空閒,任一時刻只有少部分的 socket是“活躍”的,但是 select/poll 每次呼叫都會線性掃描全部的集合,導致 效率呈現線性下降epoll不存在這個問題,它只會對“活躍”的 socket進行操作一這是因為在核心實現中, epoll是根據每個fd上面的 callback函式實現的。那麼,只有“活躍”的 socket才會去主動呼叫 callback函式,其他idle 狀態的 socket則不會。在這點上, epoll 實現了一個偽AIO。針對 epoll 和 select效能對比的 benchmark測試表明:如果所有的 socket都處於活躍態一例如一一個高速LAN環境, epoll並不比 select/poll效率高太多;相反,如果過多使用 epoll_ctl,效率相比還有稍微地降低。但是一旦使用 idleconnections模擬WAN環境,epoll的效率就遠在 select/poll之上了。

3.使用mmap加速核心與使用者空間的訊息傳遞。

無論是 selectpoll還是 epoll都需要核心把FD訊息通知給使用者空間,如何避免不必要的記憶體複製就顯得非常重要, epoll是透過核心和使用者空間 mmap同一塊記憶體來實現的。

4.epoll 的API更加簡單。

包括建立一個 epoll描述符新增監聽事件阻塞等待所監聽的事件發生關閉epoll描述符等。

值得說明的是,用來克服 select/poll缺點的方法不只有epoll, epoll 只是一種Linux的實現方案。在 freeBSD下有 kqueue,而 dev/poll是最古老的Solaris的方案,使用難度依次遞增。kqueue 是freebsd的寵兒,它實際上是一個功能相當豐富的kernel事件佇列,它不僅僅是 select/poll的升級,而且可以處理signal、目錄結構變化、程式等多種事件。kqueue是邊緣觸發的。 /dev/poll 是Solaris的產物,是這一系列高效能API中最早出現的。Kernel提供了一個特殊的裝置檔案 /dev/poll,應用程式開啟這個檔案得到操作 fd_ set 的控制程式碼,透過寫入 pollfd來修改它,一個特殊的 ioctl呼叫用來替換select。不過由於出現的年代比較早,所以 /dev/poll的介面實現比較原始。

從BIO到NIO是Java通訊類庫邁出的一小步,但卻對Java在高效能通訊領域的發展起到了關鍵性的推動作用。
隨著基於NIO的各類NIO框架的發展,以及基於NIO的Web伺服器的發展,Java在很多領域取代了C和C++,成為企業服務端應用開發的首選語言。

喜歡這篇文章的朋友們可以關注個人簡介中的公眾號

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69964492/viewspace-2766572/,如需轉載,請註明出處,否則將追究法律責任。

相關文章