您好,登錄后才能下訂單哦!
這篇文章將為大家詳細講解有關傳統的BIO編程中Netty開發環境如何搭建,小編覺得挺實用的,因此分享給大家做個參考,希望大家閱讀完這篇文章后可以有所收獲。
1.1 傳統的BIO編程
網絡編程的基本模型是 Client/Server 模型,也就是兩個進程之間進行相互通信,其中服務端提供位置信息(綁定的 IP 地址和監聽端口),客戶端通過連接操作向服務端監聽的地址發起連接請求,通過三次握手建立連接,如果連接建立成功,雙方就可以通過網絡套接字(Socket)進行通信。
在基于傳統同步阻塞模型開發中,ServerSocket 負責綁定 IP 地址,啟動監聽端口;Socket 負責發起連接操作。連接成功之后,雙方通過輸入和輸出流進行同步阻塞式通信。
1.1.1 BIO 通信模型圖
首先,我們通過圖 2-1 所示的通信模型圖來熟悉下 BIO 的服務端通信模型:
采用 BIO 通信模型的服務端,通常由一個獨立的 Acceptor 線程負責監聽客戶端的連接,它接收到客戶端連接請求之后為每個客戶端創建一個新的線程進行鏈路處理,處理完成之后,通過輸出流返回應答給客戶端,線程銷毀。這就是典型的一請求一應答通信模型。
圖1-1同步阻塞 1/0服務端通信模型(1客戶端1線程)
該模型最大的問題就是缺乏彈性伸縮能力,當客戶端并發訪問量增加后,服務端的線程個數和客戶端并發訪問數呈 1:1 的正比關系,由于線程是 Java 虛擬機非常寶貴的系統資源,當線程數膨脹之后,系統的性能將急劇下降,隨著并發訪問量的繼續增大,系統會發生線程堆棧溢出、創建新線程失敗等問題,并最終導致進程宕機或者僵死,不能對外提供服務。
1.2 偽異步I/O編程
為了解決同步阻塞 I/O 面臨的一個鏈路需要一個線程處理的問題,后來有人對它的線程模型進行了優化,后端通過一個線程池來處理多個客戶端的請求接入,形成客戶端個數 M:線程池最大線程數 N 的比例關系,其中 M 可以遠遠大于 N,通過線程池可以靈活的調配線程資源,設置線程的最大值,防止由于海量并發接入導致線程耗盡。
下面,我們結合連接模型圖和源碼,對偽異步 I/O 進行分析,看它是否能夠解決同步阻塞 I/O 面臨的問題。
1.2.1 偽異步 I/O 模型圖
采用線程池和任務隊列可以實現一種叫做偽異步的 I/O 通信框架,它的模型圖如圖 1-2 所示。
當有新的客戶端接入的時候,將客戶端的 Socket 封裝成一個 Task(該任務實現 java.lang.Runnable 接口)投遞到后端的線程池中進行處理,JDK 的線程池維護一個消息隊列和 N 個活躍線程對消息隊列中的任務進行處理。由于線程池可以設置消息隊列的大小和最大線程數,因此,它的資源占用是可控的,無論多少個客戶端并發訪問,都不會導致資源的耗盡和宕機。
圖 1-2 偽異步I/0服務端通信模型(M: N)
偽異步 I/O 實際上僅僅只是對之前 I/O 線程模型的一個簡單優化,它無法從根本上解決同步 I/O 導致的通信線程阻塞問題。下面我們就簡單分析下如果通信對方返回應答時間過長,會引起的級聯故障。
1. 服務端處理緩慢,返回應答消息耗費60s,平時只需要10ms。
2. 采用偽異步I/O的線程正在讀取故障服務節點的響應,由于讀取輸入流是阻塞的,因此,它將會被同步阻塞60s。
3. 假如所有的可用線程都被故障服務器阻塞,那后續所有的I/O消息都將在隊列中排隊。
4. 由于線程池采用阻塞隊列實現,當隊列積滿之后,后續入隊列的操作將被阻塞。
5. 由于前端只有一個Accptor線程接收客戶端接入,它被阻塞在線程池的同步阻塞隊列之后,新的客戶端請求消息將被拒絕,客戶端會發生大量的連接超時。
6. 由于幾乎所有的連接都超時,調用者會認為系統已經崩潰,無法接收新的請求消息。
1.3 NIO編程
在介紹 NIO 編程之前,我們首先需要澄清一個概念:NIO 到底是什么的簡稱?
有人稱之為 New I/O,因為它相對于之前的 I/O 類庫是新增的,所以被稱為 NewI/O,這是它的官方叫法。但是,由于之前老的 I/O 類庫是阻塞 I/O,New I/O 類庫的目標就是要讓 Java 支持非阻塞 I/O,所以,更多的人喜歡稱之為非阻塞 I/O(Non-block I/O),由于非阻塞 I/O 更能夠體現 NIO 的特點,所以本文使用的NIO 都指的是非阻塞 I/O。
與 Socket 類和 ServerSocket 類相對應,NIO 也提供了 SocketChannel 和ServerSocketChannel 兩種不同的套接字通道實現。這兩種新增的通道都支持阻塞和非阻塞兩種模式。阻塞模式使用非常簡單,但是性能和可靠性都不好,非阻塞模式則正好相反。開發人員一般可以根據自己的需要來選擇合適的模式,一般來說,低負載、低并發的應用程序可以選擇同步阻塞 I/O 以降低編程復雜度,但是對于高負載、高并發的網絡應用,需要使用 NIO 的非阻塞模式進行開發。
1.4 AIO編程
NIO2.0 引入了新的異步通道的概念,并提供了異步文件通道和異步套接字通道的實現。異步通道提供兩種方式獲取獲取操作結果:
通過java.util.concurrent.Future類來表示異步操作的結果;
在執行異步操作的時候傳入一個java.nio.channels;
CompletionHandler接口的實現類作為操作完成的回調。
NIO2.0 的異步套接字通道是真正的異步非阻塞 I/O,它對應 UNIX 網絡編程中的事件驅動 I/O(AIO),它不需要通過多路復用器(Selector)對注冊的通道進行輪詢操作即可實現異步讀寫,從而簡化了 NIO 的編程模型。
1.5 幾種I/O模型對比
不同的 I/O 模型由于線程模型、API 等差別很大,所以用法的差異也非常大。
由于之前的幾個小節已經集中對這幾種 I/O 的 API 和用法進行了說明,本小節會重點對這幾種 I/O 進行功能對比。如表 2-1 所示。
表 1-1 幾種 I/O 模型的功能和特性對比
1.6 業界主流的NIO框架介紹
隨著移動互聯網的發展和大數據時代的到來,大規模分布式服務框架、分布式流計算框架已經成為架構主流,分布式服務節點之間的通信形式往往是內部長連接,例如 FaceBook 的 Thrift 協議,為了提升節點間的通信吞吐量、提升通信性能,目前主流的內部通信框架均使用 NIO 框架,對于大公司、技術積累比較深的團隊可能會使用自研的 NIO 框架來滿足個性化或者行業特殊的需求,但是大多數架構師會選擇業界主流的 NIO 框架進行異步通信開發。
目前,業界主流的 NIO 框架主要有兩款:Mina 和 Netty,兩者都使用 ApacheLICENSE-2.0 進行開源。不同之處是 Mina 是 Apache 基金會的官方 NIO 框架,Netty 之前是 Jboss 的 NIO 框架,后來脫離 Jboss 獨立申請了 netty.io 域名,與 Jboss 脫離關系,并對版本進行了重構,導致 API 無法向上兼容。
Mina 和 Netty 還 有一段 歷 史 淵 源,Mina 最 初 版 本 的 架 構 師 是 TrustinLee,后來,由于種種原因,Trustin Lee 離開了 Mina 社區加入到了 Netty 團隊,重新設計并開發了 Netty。很多讀者會發現 Netty 中透著 Mina 的影子,兩個框架的架構理念也有很多相似之處,甚至一些代碼都非常相似,原因就在這里。
目前,Mina 和 Netty 的應用已經非常廣泛,很多開源框架都使用兩者做底層的 NIO 框架,例如 Hadoop 的通信組件 Avro 使用 Netty 做底層的通信框架,
Openfire 則使用 Mina 做底層通信框架,相比于 Mina,Netty 社區目前更活躍,版本應用范圍也更廣。
1.7 為什么選擇Netty
1.7.1 不選擇 Java 原生 NIO 編程的原因
現在我們總結一下為什么不建議開發者直接使用 JDK 的 NIO 類庫進行開發,具體原因如下。
1. NIO的類庫和API繁雜,使用麻煩,你需要熟練掌握Selector、ServerSocketChannel、SocketChannel、ByteBuffer等。
2. 需要具備其他的額外技能做鋪墊,例如熟悉Java多線程編程。這是因為NIO編程涉及到Reactor模式,你必須對多線程和網路編程非常熟悉,才能編寫出高質量的NIO程序。
3. 可靠性能力補齊,工作量和難度都非常大。例如客戶端面臨斷連重連、網絡閃斷、半包讀寫、失敗緩存、網絡擁塞和異常碼流的處理等問題,NIO編程的特點是功能開發相對容易,但是可靠性能力補齊的工作量和難度都非常大。
4. JDK NIO的BUG,例如臭名昭著的epoll bug,它會導致Selector空輪詢,最終導致CPU 100%。官方聲稱在JDK1.6版本的update18修復了該問題,但是直到JDK1.7版本該問題仍舊存在,只不過該BUG發生概率降低了一些而已,它并沒有被根本解決。該BUG以及與該BUG相關的問題單可以參見以下鏈接內容。
http://bugs.java.com/bugdatabase/view_bug.do?bug_id=6403933
http://bugs.java.com/bugdatabase/view_bug.do?bug_id=2147719
由于上述原因,在大多數場景下,不建議大家直接使用 JDK 的 NIO 類庫,除非你精通 NIO 編程或者有特殊的需求。在絕大多數的業務場景中,我們可以使用NIO 框架 Netty 來進行 NIO 編程,它既可以作為客戶端也可以作為服務端,同時
支持 UDP 和異步文件傳輸,功能非常強大。
1.7.2 選擇 Netty 的理由
Netty 是業界最流行的 NIO 框架之一,它的健壯性、功能、性能、可定制性和可擴展性在同類框架中都是首屈一指的,它已經得到成百上千的商用項目驗證,例如 Hadoop 的 RPC 框架 avro 使用 Netty 作為底層通信框架;很多其他業界主流的 RPC 框架,也使用 Netty 來構建高性能的異步通信能力。
通過對 Netty 的分析,我們將它的優點總結如下 :
API使用簡單,開發門檻低;
功能強大,預置了多種編解碼功能,支持多種主流協議;
定制能力強,可以通過ChannelHandler對通信框架進行靈活地擴展;
性能高,通過與其他業界主流的NIO框架對比,Netty的綜合性能最優;
成熟、穩定,Netty修復了已經發現的所有JDK NIO BUG,業務開發人員不需要再為NIO的BUG而煩惱;
社區活躍,版本迭代周期短,發現的BUG可以被及時修復,同時,更多的新功能會加入;
經歷了大規模的商業應用考驗,質量得到驗證。在互聯網、大數據、網絡游戲、企業應用、電信軟件等眾多行業得到成功商用,證明了它已經完全能夠滿足不同行業的商業應用了。
正是因為這些優點,Netty 逐漸成為 Java NIO 編程的首選框架。
Netty 的架構圖如下所示。
1.8 Netty開發環境搭建
首先假設你已經在本機安裝了 JDK1.7,配置了 JDK 的環境變量 path,同時下載并正確啟動了 IDE 工具 Eclipse。如果你是個 Java 初學者,從來沒有在本機搭建過 Java 開發環境,建議你先選擇一本 Java 基礎入門的書籍或者課程學習。
假如你習慣于使用其他 IDE 工具進行 Java 開發,例如 NetBeans IDE,也可以運行本節的入門例程。但是,你需要根據自己實際使用的 IDE 進行對應的配置修改和調整,本書統一使用 eclipse-jee-kepler-SR1-win32 作為 Java 開發工具。
1.8.1 下載 Netty 類庫
訪問 Netty 的官網 http://netty.io/,從【Downloads】標簽頁選擇下載4.1.5.Final 軟件包,包含了源碼、編譯類庫和 Java Doc,18.1M 左右,解壓之后的軟件包如下所示。
這時會發現里面包含了各個模塊的.jar 包和源碼,由于我們直接以二進制類庫的方式使用 Netty,所以只需要獲取 netty-all-4.1.5.Final.jar 即可。
1.8.2 開發工程搭建
將 netty-all-4.1.5.Final.jar 導入到 Java 工程的 lib 目錄下(lib 目錄需要自建),右鍵單擊 netty
-all-4.1.5.Final.jar,在彈出的菜單中,選擇將.jar包添加到 Build Path 中,即可完成 Netty 開發環境的搭建。
關于“傳統的BIO編程中Netty開發環境如何搭建”這篇文章就分享到這里了,希望以上內容可以對大家有一定的幫助,使各位可以學到更多知識,如果覺得文章不錯,請把它分享出去讓更多的人看到。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。