Netty之路(一)Linux蝇恶、Java、Netty的I/O模型

一惶桐、Linux 網(wǎng)絡(luò)I/O模型

Linux的內(nèi)核秉承一切皆文件的理念撮弧,普通文件、目錄姚糊、字符設(shè)備贿衍、塊設(shè)備和網(wǎng)絡(luò)設(shè)備(套接字)等在Unix/Linux都被當(dāng)做文件來對待。雖然他們的類型不同救恨,但是linux系統(tǒng)為它們提供了一套統(tǒng)一的操作接口贸辈。對一個文件的讀寫操作會調(diào)用內(nèi)核提供的系統(tǒng)命令,返回一個文件描述符(簡稱:fd)肠槽,而對于一個socket的讀寫也有響應(yīng)的描述符擎淤,簡稱socketfd奢啥,描述符就是一個數(shù)字,它指向內(nèi)核中的一個結(jié)構(gòu)體(文件路徑嘴拢,數(shù)據(jù)區(qū)等一些屬性)桩盲。
根據(jù)UNIX網(wǎng)絡(luò)編程對I/O模型的分類,UNIX提供了5種I/O模型炊汤,分別如下:

1. 阻塞I/O模型(Blocking IO):

最常用的I/O模型就是阻塞I/O模型正驻,默認(rèn)情況下,所有的文件操作都是阻塞的抢腐。應(yīng)用進程向內(nèi)核發(fā)起 I/O 請求姑曙,發(fā)起調(diào)用recvfrom的線程一直等待內(nèi)核返回結(jié)果。一次完整的 I/O 請求稱為BIO(Blocking IO迈倍,阻塞 I/O)伤靠,所以 BIO 在實現(xiàn)異步操作時,只能使用多線程模型啼染,一個請求對應(yīng)一個線程宴合。但是,線程的資源是有限且寶貴的迹鹅,創(chuàng)建過多的線程會增加線程切換的開銷卦洽。


image.png

2、非阻塞I/O模型(non-blocking IO):

recvfrom從應(yīng)用層到內(nèi)核斜棚,如果該緩沖區(qū)沒有數(shù)據(jù)的話阀蒂,直接返回一個EWOULDBLOCK錯誤,一般都對非阻塞I/O模型進行輪詢的時候就是檢查這個狀態(tài)弟蚀,看內(nèi)核是否有數(shù)據(jù)到來蚤霞。NIO 相比 BIO 雖然大幅提升了性能,但是輪詢過程中大量的系統(tǒng)調(diào)用導(dǎo)致上下文切換開銷很大义钉。所以昧绣,單獨使用非阻塞 I/O 時效率并不高,而且隨著并發(fā)量的提升捶闸,非阻塞 I/O 會存在嚴(yán)重的性能浪費夜畴。


image.png

3、多路復(fù)用I/O模型

多路復(fù)用實現(xiàn)了一個線程處理多個 fd的操作删壮。多路指的是多個數(shù)據(jù)通道斩启,復(fù)用指的是使用一個或多個固定線程來處理每一個 Socket。select/poll是順序掃描fd是否就緒醉锅,而且支持的fd數(shù)量有限兔簇。linux還提供了epoll的實現(xiàn)方式,基于事件驅(qū)動方式代替順序掃描,因此性能更高垄琐。當(dāng)有fd就緒時边酒,立即回調(diào)函數(shù)rollback。
select狸窘、poll墩朦、epoll 都是 I/O 多路復(fù)用的具體實現(xiàn),線程一次 select 調(diào)用可以獲取內(nèi)核態(tài)中多個數(shù)據(jù)通道的數(shù)據(jù)狀態(tài)翻擒。多路復(fù)用解決了同步阻塞 I/O 和同步非阻塞 I/O 的問題氓涣,是一種非常高效的 I/O 模型。


image.png

3.1陋气、epoll的特點

  • 支持一個進程打開的scoket描述符(fd)不受限制(僅受限于操作系統(tǒng)的最大文件句柄數(shù))
  • I/O效率不會隨著fd數(shù)目的增加而線性下降
  • 使用mmap加速內(nèi)核與用戶空間的消息傳遞
  • epoll的API更加簡單

4劳吠、信號驅(qū)動I/O模型

信號驅(qū)動 I/O 并不常用,它是一種半異步的 I/O 模型巩趁。在使用信號驅(qū)動 I/O 時痒玩,通過系統(tǒng)調(diào)用sigaction執(zhí)行一個信號處理函數(shù)。當(dāng)數(shù)據(jù)準(zhǔn)備就緒后议慰,內(nèi)核通過發(fā)送一個 SIGIO 信號通知應(yīng)用進程蠢古,應(yīng)用進程就可以開始讀取數(shù)據(jù)了。


image.png

5别凹、異步I/O模型

異步 I/O 最重要的一點是從內(nèi)核緩沖區(qū)拷貝數(shù)據(jù)到用戶態(tài)緩沖區(qū)的過程也是由系統(tǒng)異步完成草讶,應(yīng)用進程只需要在指定的數(shù)組中引用數(shù)據(jù)即可。異步 I/O 與信號驅(qū)動 I/O 這種半異步模式的主要區(qū)別:信號驅(qū)動 I/O 由內(nèi)核通知何時可以開始一個 I/O 操作炉菲,而異步 I/O 由內(nèi)核通知 I/O 操作何時已經(jīng)完成堕战。


image.png

二、JAVA的I/O模型

在JDK1.4時颁督,新增了java.nio包,提供了很多進行異步I/O開發(fā)的API和類庫浇雹,主要的類和接口如下:

  • 進行異步I/O操作的緩沖區(qū)ByteBuffer等
  • 進行異步I/O操作的管道Pipe
  • 進行各種I/O操作(異步或同步)的Channel沉御,包括ServerSocketChannel和SocketChannel
  • 多種字符集的編碼能力和解碼能力
  • 實現(xiàn)非阻塞I/O操作的多路復(fù)用器Selector
  • 基于流行的Perl實現(xiàn)的正則表達式類庫
  • 文件通道FileChannel
    雖然提供的NIO類庫極大的促進了JAVA的異步非阻塞變成的發(fā)展和應(yīng)用,但依然存在對文件系統(tǒng)的處理能力不足昭灵,主要有:
  • 沒有統(tǒng)一的文件屬性(例如讀寫權(quán)限)
  • API能力比較弱吠裆,例如目錄的級聯(lián)創(chuàng)建和遞歸遍歷,往往需要自己實現(xiàn)
  • 底層存儲系統(tǒng)的一些高級API無法使用
  • 所有文件操作都是同步阻塞調(diào)用烂完,不支持異步文件讀寫操作
    在JDK1.7中试疙,對NIO類庫進行了升級,被稱為NIO2.0它主要提供了三個方面的改進:
  • 提供能夠批量獲取文件屬性的API抠蚣,這些API具有平臺無關(guān)性祝旷,不與特性的文件系統(tǒng)相耦合。另外它還提供了標(biāo)準(zhǔn)文件系統(tǒng)的SPI,供各個服務(wù)提供商擴展實現(xiàn)
  • 提供AIO功能怀跛,支持基于文件的異步I/O操作和針對網(wǎng)絡(luò)套接字的異步操作
  • 完成JSR-51定義的通道功能距贷,包括對配置和多播數(shù)據(jù)報的支持等

三、Netty的I/O模型

Netty 的 I/O 模型是基于非阻塞 I/O 實現(xiàn)的吻谋,底層依賴的是 JDK NIO 框架的多路復(fù)用器 Selector忠蝗。一個多路復(fù)用器 Selector 可以同時輪詢多個 Channel,采用 epoll 模式后漓拾,只需要一個線程負(fù)責(zé) Selector 的輪詢阁最,就可以接入成千上萬的客戶端。

在 I/O 多路復(fù)用的場景下骇两,當(dāng)有數(shù)據(jù)處于就緒狀態(tài)后速种,需要一個事件分發(fā)器(Event Dispather),它負(fù)責(zé)將讀寫事件分發(fā)給對應(yīng)的讀寫事件處理器(Event Handler)脯颜。事件分發(fā)器有兩種設(shè)計模式:Reactor 和 Proactor哟旗,Reactor 采用同步 I/O, Proactor 采用異步 I/O栋操。

Reactor 實現(xiàn)相對簡單闸餐,適合處理耗時短的場景,對于耗時長的 I/O 操作容易造成阻塞矾芙。Proactor 性能更高舍沙,但是實現(xiàn)邏輯非常復(fù)雜,目前主流的事件驅(qū)動模型還是依賴 select 或 epoll 來實現(xiàn)剔宪。


image.png

(摘自 Lea D. Scalable IO in Java )
上圖所描述的便是 Netty 所采用的主從 Reactor 多線程模型拂铡,所有的 I/O 事件都注冊到一個 I/O 多路復(fù)用器上,當(dāng)有 I/O 事件準(zhǔn)備就緒后葱绒,I/O 多路復(fù)用器會將該 I/O 事件通過事件分發(fā)器分發(fā)到對應(yīng)的事件處理器中感帅。該線程模型避免了同步問題以及多線程切換帶來的資源開銷,真正做到高性能地淀、低延遲失球。

完美彌補 Java NIO 的缺陷

在 JDK 1.4 投入使用之前,只有 BIO 一種模式帮毁。開發(fā)過程相對簡單实苞。新來一個連接就會創(chuàng)建一個新的線程處理。隨著請求并發(fā)度的提升烈疚,BIO 很快遇到了性能瓶頸黔牵。JDK 1.4 以后開始引入了 NIO 技術(shù),支持 select 和 poll爷肝;JDK 1.5 支持了 epoll猾浦;JDK 1.7 發(fā)布了 NIO2陆错,支持 AIO 模型。Java 在網(wǎng)絡(luò)領(lǐng)域取得了長足的進步跃巡。

Netty 相比 JDK NIO 突出的優(yōu)勢:

  • 易用性危号。 我們使用 JDK NIO 編程需要了解很多復(fù)雜的概念,比如 Channels素邪、Selectors外莲、Sockets、Buffers 等兔朦,編碼復(fù)雜程度非常高偷线。相反,Netty 在 NIO 基礎(chǔ)上進行了更高層次的封裝沽甥,屏蔽了 NIO 的復(fù)雜性声邦;Netty 封裝了更加人性化的 API,統(tǒng)一的 API(阻塞/非阻塞) 大大降低了開發(fā)者的上手難度摆舟;與此同時亥曹,Netty 提供了很多開箱即用的工具,例如常用的行解碼器恨诱、長度域解碼器等媳瞪,而這些在 JDK NIO 中都需要自己實現(xiàn)。

  • 穩(wěn)定性照宝。 Netty 更加可靠穩(wěn)定蛇受,修復(fù)和完善了 JDK NIO 較多已知問題,例如臭名昭著的 select 空轉(zhuǎn)導(dǎo)致 CPU 消耗 100%厕鹃,TCP 斷線重連兢仰,keep-alive 檢測等問題。

  • 可擴展性剂碴。 Netty 的可擴展性在很多地方都有體現(xiàn)把将,這里主要列舉其中的兩點:一個是可定制化的線程模型,用戶可以通過啟動的配置參數(shù)選擇 Reactor 線程模型忆矛;另一個是可擴展的事件驅(qū)動模型察蹲,將框架層和業(yè)務(wù)層的關(guān)注點分離。大部分情況下洪碳,開發(fā)者只需要關(guān)注 ChannelHandler 的業(yè)務(wù)邏輯實現(xiàn)递览。

更低的資源消耗

作為網(wǎng)絡(luò)通信框架叼屠,需要處理海量的網(wǎng)絡(luò)數(shù)據(jù)瞳腌,那么必然面臨有大量的網(wǎng)絡(luò)對象需要創(chuàng)建和銷毀的問題,對于 JVM GC 并不友好镜雨。為了降低 JVM 垃圾回收的壓力嫂侍,Netty 主要采用了兩種優(yōu)化手段:

  • 對象池復(fù)用技術(shù)。 Netty 通過復(fù)用對象,避免頻繁創(chuàng)建和銷毀帶來的開銷挑宠。

  • 零拷貝技術(shù)菲盾。 除了操作系統(tǒng)級別的零拷貝技術(shù)外,Netty 提供了更多面向用戶態(tài)的零拷貝技術(shù)各淀,例如 Netty 在 I/O 讀寫時直接使用 DirectBuffer懒鉴,從而避免了數(shù)據(jù)在堆內(nèi)存和堆外內(nèi)存之間的拷貝。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末碎浇,一起剝皮案震驚了整個濱河市临谱,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌奴璃,老刑警劉巖悉默,帶你破解...
    沈念sama閱讀 211,042評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異苟穆,居然都是意外死亡抄课,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,996評論 2 384
  • 文/潘曉璐 我一進店門雳旅,熙熙樓的掌柜王于貴愁眉苦臉地迎上來跟磨,“玉大人,你說我怎么就攤上這事岭辣≈ㄉ梗” “怎么了?”我有些...
    開封第一講書人閱讀 156,674評論 0 345
  • 文/不壞的土叔 我叫張陵沦童,是天一觀的道長仑濒。 經(jīng)常有香客問我,道長偷遗,這世上最難降的妖魔是什么墩瞳? 我笑而不...
    開封第一講書人閱讀 56,340評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮氏豌,結(jié)果婚禮上喉酌,老公的妹妹穿的比我還像新娘。我一直安慰自己泵喘,他們只是感情好泪电,可當(dāng)我...
    茶點故事閱讀 65,404評論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著纪铺,像睡著了一般相速。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上鲜锚,一...
    開封第一講書人閱讀 49,749評論 1 289
  • 那天突诬,我揣著相機與錄音苫拍,去河邊找鬼。 笑死旺隙,一個胖子當(dāng)著我的面吹牛绒极,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播蔬捷,決...
    沈念sama閱讀 38,902評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼垄提,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了周拐?” 一聲冷哼從身側(cè)響起塔淤,我...
    開封第一講書人閱讀 37,662評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎速妖,沒想到半個月后高蜂,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,110評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡罕容,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,451評論 2 325
  • 正文 我和宋清朗相戀三年备恤,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片锦秒。...
    茶點故事閱讀 38,577評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡露泊,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出旅择,到底是詐尸還是另有隱情惭笑,我是刑警寧澤,帶...
    沈念sama閱讀 34,258評論 4 328
  • 正文 年R本政府宣布生真,位于F島的核電站沉噩,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏柱蟀。R本人自食惡果不足惜川蒙,卻給世界環(huán)境...
    茶點故事閱讀 39,848評論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望长已。 院中可真熱鬧畜眨,春花似錦、人聲如沸术瓮。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,726評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽胞四。三九已至恬汁,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間撬讽,已是汗流浹背蕊连。 一陣腳步聲響...
    開封第一講書人閱讀 31,952評論 1 264
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留游昼,地道東北人甘苍。 一個月前我還...
    沈念sama閱讀 46,271評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像烘豌,于是被迫代替她去往敵國和親载庭。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,452評論 2 348

推薦閱讀更多精彩內(nèi)容