天天看點

NIO vs. BIO 我該如何選擇術語介紹性能測試NIO還是BIO如何選擇

本文介紹了nio和bio的工作原理,并通過一組性能測試,對nio和bio的性能進行對比,為如何選擇nio和bio提供理論和實踐依據。

bio -- blocking io 即阻塞式io。

nio -- non-blocking io, 即非阻塞式io或異步io。

性能 -- 所謂的性能是指伺服器響應用戶端的能力,對于伺服器我們通常用并發客戶連接配接數+系統響應時間來衡量伺服器性能,例如,我們說這個伺服器在10000個并發下響應時間是100ms,就是高性能,而另一個伺服器在10個并發下響應時間是500ms,性能一般。是以提升性能就是提升伺服器的并發處理能力,和縮短系統的響應時間。

用同一個java socket client 分别調用用bio和nio實作的socket server, 觀察其建立一個socket (tcp connection)所需要的時間,進而計算出server吞吐量tps。

之是以可以用connection建立時間來計算tps,而不考慮業務邏輯運作時間,是因為這裡的業務邏輯很簡單,隻是echo回從client傳過來的字元,所消耗時間可以忽略不計。

注意: 在現實場景中,業務邏輯會比較複雜,tps的計算必須綜合考慮io時間+業務邏輯執行時間+多線程并行運作情況 等因素的影響。

1、java socket client

2、io socket server

這個socket server模拟的是我們經常使用的thread-per-connection模式, tomcat,jboss等web container都是這種方式。

3、nio socket server

socket client <——> io socket server

establish connection time: 2183277 ns

establish connection time: 1523264 ns

establish connection time: 1430883 ns

平均耗費時間大概是1.5 ms,tps 大概是600

socket client <——> nio socket server

accept connection time: 138059 ns

accept connection time: 132927 ns

accept connection time: 132413 ns

平均耗費時間大概是0.15 ms,tps 大概是6000

從測試結果可以看出,nio的接受請求的速率大概是io的十倍。

在探讨在什麼場景下使用bio,什麼場景下使用nio之前,讓我們先看一下在兩種不同io模型下,實作的伺服器有什麼不同。

bio server

通常采用的是request-per-thread模式,用一個acceptor線程負責接收tcp連接配接請求,并建立鍊路(這是一個典型的網絡io,是非常耗時的操作),然後将請求dispatch給負責業務邏輯處理的線程池,業務邏輯線程從inputstream中讀取資料,進行業務處理,最後将處理結果寫入outputstream,自此,一個transaction完成。

acceptor線程是服務的入口,任何發生在其上面的堵塞操作,都将嚴重影響server性能,假設建立一個tcp連接配接需要4ms,無論你後面的業務處理有多快,因為acceptor的堵塞,這個server最多每秒鐘隻能接受250個請求。而nio則是另外一番風景,因為所有的io操作都是非堵塞的,毫無疑問,acceptor可以接受更大的并發量,并能最大限度的利用cpu和硬體資源處理這些請求。

bio通信模型圖

NIO vs. BIO 我該如何選擇術語介紹性能測試NIO還是BIO如何選擇

bio序列圖

NIO vs. BIO 我該如何選擇術語介紹性能測試NIO還是BIO如何選擇

nio server

如下圖所示,在nio server中,所有的io操作都是異步非堵塞的,acceptor的工作變的非常輕量,即将io操作分派給io線程池,在收到io操作完成的消息通知時,指派業務邏輯線程池去完成業務邏輯處理,因為所有的耗時工作都是異步的,使得acceptor可以以非常快的速度接收請求,10w每秒是完全有可能的。

10w/s可能是沒有考慮業務處理時間,考慮到業務時間,現實場景中,普通伺服器可能很難做到10w tps,為什麼這麼說呢?試想下,假設一個業務處理需要500ms,而業務線程池中隻有50個線程,假設其它耗時忽略不計,50個線程滿負載運作,在50個并發下,大家都很happy,所有的client都能在500ms後獲得響應. 在100個并發下,因為隻有50個線程,當50個請求被處理時,另50個請求隻能處在等待狀态直到有可用線程為止。也就是說,理想情況下50個請求會在500ms傳回,另50個可能會在1000ms傳回。以此類推,若是10000個并發,最慢的50個請求需要100s才能傳回。

以上做法是為線程池預設50個線程,這是相對保守的一種做法,其好處是不管有多少個并發請求,系統隻有這麼多資源(50個線程)提供服務,是一種時間換空間的做法,也許有的客戶會等很長時間,甚至逾時,但是伺服器的運作是平穩的。 還有一種比較激進的線程池模型是類似netty裡推薦的彈性線程池,就是沒有給線程池制定一個線程上線,而是根據需要,彈性的增減線程數量,這種做法的好處是,并發量加大時,系統會建立更多的線程以縮短響應時間,缺點是到達一個極限時,系統可能會因為資源耗盡(cpu 100%或者out of memory)而down機。

是以可以這樣說,nio極大的提升了伺服器接受并發請求的能力,而伺服器性能還是要取決于業務處理時間和業務線程池模型。

nio序列圖

NIO vs. BIO 我該如何選擇術語介紹性能測試NIO還是BIO如何選擇

什麼時候使用bio?

低負載、低并發的應用程式可以選擇同步阻塞bio以降低程式設計複雜度。

業務邏輯耗時過長,使得nio節省的時間顯得微不足道。

什麼時候使用nio?

對于高負載、高并發的網絡應用,需要使用nio的非阻塞模式進行開發。

業務邏輯簡單,處理時間短,例如網絡聊天室,網絡遊戲等