Netty-簡(jiǎn)介
Netty是一個(gè)NIO client-server框架婚被,可以快速和簡(jiǎn)單的開發(fā)網(wǎng)絡(luò)應(yīng)用程序稳析,比如協(xié)議服務(wù)器服務(wù)器和客戶端洗做。Netty向你提供了一種新的方式開發(fā)你的網(wǎng)絡(luò)應(yīng)用程序,使得它簡(jiǎn)單和可擴(kuò)展彰居。它通過這樣的方式實(shí)現(xiàn):抽象出所涉及的復(fù)雜性和通過提供一種簡(jiǎn)單易用的API诚纸,這個(gè)將業(yè)務(wù)邏輯從網(wǎng)絡(luò)處理代碼中解耦出來。因?yàn)樗菫镹IO構(gòu)建,所有的Netty API都是異步的.
不選擇Java原生NIO編程的原因
為什么不建議開發(fā)者直接使用 JDK 的 NIO 類庫(kù)進(jìn)行開發(fā), 具體原因如下陈惰。
- NIO的類庫(kù)和API繁雜,使用麻煩,你需要熟練掌握Selector畦徘、 ServerSocketChannel、SocketChannel抬闯、ByteBuffer等井辆。
- 需要具備其他的額外技能做鋪墊,例如熟悉Java多線程編程。這是因?yàn)?NIO編程涉及到Reactor模式,你必須對(duì)多線程和網(wǎng)路編程非常熟悉,才能 編寫出高質(zhì)量的NIO程序溶握。
- 可靠性靠能力補(bǔ)齊,工作量和難度都非常大杯缺。例如客戶端面臨斷連重連、網(wǎng) 絡(luò)閃斷睡榆、半包讀寫夺谁、失敗緩存、網(wǎng)絡(luò)擁塞和異常碼流的處理等問題,NIO 編程的特點(diǎn)是功能開發(fā)相對(duì)容易,但是可靠性能力補(bǔ)齊的工作量和難度都 非常大肉微。
- JDK NIO的BUG,例如臭名昭著的epoll bug,它會(huì)導(dǎo)致Selector空輪詢, 最終導(dǎo)致CPU 100%。官方聲稱在JDK1.6版本的update18修復(fù)了該問題,但 是直到JDK1.7版本該問題仍舊存在,只不過該BUG發(fā)生概率降低了一些而 已,它并沒有被根本解決蜡塌。該BUG以及與該BUG相關(guān)的問題單可以參見以下 鏈接內(nèi)容碉纳。
選擇Netty的理由
Netty 是業(yè)界最流行的 NIO 框架之一,它的健壯性、功能馏艾、性能劳曹、可定制性 和可擴(kuò)展性在同類框架中都是首屈一指的,它已經(jīng)得到成百上千的商用項(xiàng)目驗(yàn)證, 例如 Hadoop 的 RPC 框架 avro 使用 Netty 作為底層通信框架;很多其他業(yè)界主流 的 RPC 框架,也使用 Netty 來構(gòu)建高性能的異步通信能力奴愉。
通過對(duì) Netty 的分析,我們將它的優(yōu)點(diǎn)總結(jié)如下 :
- API使用簡(jiǎn)單,開發(fā)門檻低;
- 功能強(qiáng)大,預(yù)置了多種編解碼功能,支持多種主流協(xié)議;
- 定制能力強(qiáng),可以通過ChannelHandler對(duì)通信框架進(jìn)行靈活地?cái)U(kuò)展;
- 性能高,通過與其他業(yè)界主流的NIO框架對(duì)比,Netty的綜合性能最優(yōu);
- 成熟、穩(wěn)定,Netty修復(fù)了已經(jīng)發(fā)現(xiàn)的所有JDK NIO BUG,業(yè)務(wù)開發(fā)人員不需要再為NIO的BUG而煩惱;
- 社區(qū)活躍,版本迭代周期短,發(fā)現(xiàn)的BUG可以被及時(shí)修復(fù),同時(shí),更多的新功能會(huì)加入;
- 經(jīng)歷了大規(guī)模的商業(yè)應(yīng)用考驗(yàn),質(zhì)量得到驗(yàn)證铁孵。在互聯(lián)網(wǎng)锭硼、大數(shù)據(jù)、網(wǎng)絡(luò)游戲蜕劝、企業(yè)應(yīng)用檀头、電信軟件等眾多行業(yè)得到成功商用,證明了它已經(jīng)完全能夠滿足不同行業(yè)的商業(yè)應(yīng)用了。
正是因?yàn)檫@些優(yōu)點(diǎn),Netty 逐漸成為 Java NIO 編程的首選框架岖沛。
異步設(shè)計(jì)
異步設(shè)計(jì)并不是什么新鮮玩意暑始,異步的思想已經(jīng)很廣泛。現(xiàn)今I/O處理往往會(huì)成為系統(tǒng)的瓶頸所在婴削,異步處理顯得尤為重要廊镜。但是不同的異步模式之間是有很多區(qū)別的,我們需要弄清楚這些模式背后的規(guī)則唉俗。
異步是指在應(yīng)用處理當(dāng)前任務(wù)的同時(shí)嗤朴,可以新建一個(gè)任務(wù)處理一些其他的事情,然后在事情處理完成時(shí)再獲取通知虫溜,而不是等待雹姊。這種方式使資源利用更加有效。
Callback 回調(diào)模式
Example
public interface Fetcher {
void fetchData(FetchCallback callback);
}
public interface FetchCallback {
void onData(Data data);
void onError(Throwable cause);
}
public class Worker {
public void doWork() {
Fetcher fetcher = ...
fetcher.fetchData(new FetchCallback() {
@Override
public void onData(Data data) { #1
System.out.println("Data received: " + data);
}
@Override
public void onError(Throwable cause) { #2
System.err.println("An error accour: " + cause.getMessage());
}
});
... }
}
- 回調(diào)接口
FetchCallback
-
Fetcher.fetchData(FetchCallback)
接收一個(gè)回調(diào)對(duì)象吼渡,這樣我們可以將執(zhí)行邏輯從回調(diào)者所在線程轉(zhuǎn)移到其他線程容为。
Future
java.util.concurrent.Future
對(duì)象在任務(wù)正常時(shí)可以持有執(zhí)行結(jié)果,在任務(wù)異常時(shí)可以持有執(zhí)行的異常寺酪。
Example
ExecutorService executor = Executors.newCachedThreadPool();
Runnable task1 = new Runnable() {
@Override
public void run() {
doSomeHeavyWork();
}
...
}
Callable<Interger> task2 = new Callable() {
@Override
public Integer call() {
return doSomeHeavyWorkWithResul();
}
...
}
Future<?> future1 = executor.submit(task1);
Future<Integer> future2 = executor.submit(task2);
while (!future1.isDone() || !future2.isDone()) {
...
// do something else
...
}
兩種方式各有利弊:Callback的方式好處在于坎背,當(dāng)任務(wù)完成后會(huì)自動(dòng)回調(diào)定義的回調(diào)接口,F(xiàn)uture方式需要額外的檢測(cè)寄雀;但是這樣的編碼風(fēng)格可讀性比較差得滤。