Netty簡(jiǎn)介
Netty是由JBoss開(kāi)發(fā),基于JAVA NIO的一個(gè)高性能通信框架。之前幾篇文章介紹了Java NIO的一些基本的概念和API。但在實(shí)際的網(wǎng)絡(luò)開(kāi)發(fā)中,其實(shí)很少使用Java NIO原生的API。主要有以下原因:
- 原生API使用單線程模型,不能很好利用多核優(yōu)勢(shì),如果自己去寫多線程結(jié)合起來(lái)比較麻煩;
- 原生API是直接使用的IO數(shù)據(jù),沒(méi)有做任何封裝處理,對(duì)數(shù)據(jù)的編解碼、TCP的粘包和拆包、客戶端斷連、網(wǎng)絡(luò)的可靠性和安全性方面沒(méi)有做處理;
在《Netty權(quán)威指南》這本書里提到一個(gè)真實(shí)的故事,兩個(gè)項(xiàng)目團(tuán)隊(duì)都要做基于NIO非阻塞特性構(gòu)建高性能、異步和高可靠性的底層通信框架,但一個(gè)團(tuán)隊(duì)選擇了基于Java NIO API從頭開(kāi)發(fā),另一個(gè)團(tuán)隊(duì)選擇了基于Netty開(kāi)發(fā)。最終,從頭開(kāi)發(fā)的團(tuán)隊(duì)遇到了各種各樣的問(wèn)題,導(dǎo)致項(xiàng)目延遲,而基于Netty開(kāi)發(fā)的團(tuán)隊(duì)則進(jìn)展順利。
其實(shí)網(wǎng)絡(luò)開(kāi)發(fā)是一個(gè)比較復(fù)雜的事情,因?yàn)榫W(wǎng)絡(luò)的不穩(wěn)定性,通常會(huì)遇到各種各樣的問(wèn)題,比如前面提到的客戶端突然斷連、TCP的拆包和沾包等等。
幸運(yùn)的是,網(wǎng)絡(luò)上已經(jīng)有了這么一個(gè)成熟的框架幫我們處理了這些事情,這個(gè)框架就是Netty。Netty主要應(yīng)用于以下領(lǐng)域:
- 高性能的RPC框架:常用于微服務(wù)之間的高性能遠(yuǎn)程調(diào)用(如Dubbo)
- 游戲行業(yè):Netty可以很輕松地定制和開(kāi)發(fā)一個(gè)私有協(xié)議棧,
- 即時(shí)通訊:Netty基于Java NIO,并且做了一些優(yōu)化,支持高性能的即時(shí)通訊
Netty可以做什么?
這里有一個(gè)Netty的功能特性的圖:
Netty Core提供了基本功能,包括文件零拷貝、基本的API、可擴(kuò)展的基于事件的模型(下文詳細(xì)介紹)。
Netty支持非常多的協(xié)議,比如HTTP、WebSocket等。當(dāng)然,Netty也可以自定義協(xié)議。常見(jiàn)協(xié)議的示例代碼可以參考netty源碼里面的example包。
Netty同時(shí)支持Java的BIO和NIO兩種方式。且很容易與Spring等主流框架進(jìn)行集成。
Reactor 線程模型
首先介紹處理事件的兩種方式:
- 輪詢方式:線程不斷輪詢?cè)L問(wèn)相關(guān)事件發(fā)生源有沒(méi)有發(fā)生事件,有發(fā)生事件就調(diào)用事件處理邏輯。Java 原生的NIO就是使用的輪詢方式。
- 事件驅(qū)動(dòng)方式,發(fā)生事件,主線程把事件放入事件隊(duì)列,在另外線程不斷循環(huán)消費(fèi)事件列表中的事件,調(diào)用事件對(duì)應(yīng)的處理邏輯處理事件。事件驅(qū)動(dòng)方式也被稱為消息通知方式,其實(shí)是設(shè)計(jì)模式中觀察者模式的思路。
Reactor是反應(yīng)堆的意思。Reactor線程模型是指通過(guò)一個(gè)或多個(gè)輸入,同時(shí)傳遞給服務(wù)處理器的服務(wù)請(qǐng)求的事件驅(qū)動(dòng)處理模式。
Reactor模式主要工作原理如下圖:
Reactor 有一個(gè)專門負(fù)責(zé)監(jiān)聽(tīng)和分發(fā)事件的線程,如圖中的Service Handler,所有請(qǐng)求進(jìn)來(lái)后,被它分發(fā)到具體的處理線程,如圖中的EventHandler去處理。
Reactor可能有多個(gè),而Netty正是使用了多Reactor的線程模型。
Netty是怎么工作的?
Netty里面有兩個(gè)Group,分別是Boss Group和Worker Group。其中,Boss Group用于處于連接,Worker Group用于處理實(shí)際的讀寫IO。
Boss Group里面的NioEventLoop會(huì)輪詢accept事件,遇到有新的連接,就生成NIOSocketChannel,并把這個(gè)Channel注冊(cè)到Worker Group的Selector上。
Worker Group輪詢r(jià)ead和write事件,在可讀或者可寫條件滿足時(shí),就進(jìn)行處理。
Worker Group和Boss Group都是通過(guò)里面的NioEventLoop來(lái)操作的。NioEventLoop中維護(hù)了一個(gè)線程和任務(wù)隊(duì)列,支持異步提交執(zhí)行任務(wù),線程啟動(dòng)時(shí)會(huì)調(diào)用NioEventLoop的run方法。
最后都會(huì)執(zhí)行一個(gè)runAllTasks方法,它用于處理任務(wù)隊(duì)列中的任務(wù)。任務(wù)隊(duì)列中的任務(wù)包括用戶調(diào)用 eventloop.execute或schedule執(zhí)行的任務(wù),或者其他線程提交到該eventloop的任務(wù)。
示例代碼
以下是使用Netty創(chuàng)建一個(gè)Server的示例代碼。Client也可以使用Netty來(lái)創(chuàng)建,也可以使用之前文章里面的NIO示例代碼。這里就不展示基于Netty的Client端的代碼,只展示Server端的代碼了。
文章來(lái)源:xy的技術(shù)圈作者:xy的技術(shù)圈






