<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          BIO、NIO、AIO,還傻傻分不清?

          共 4587字,需瀏覽 10分鐘

           ·

          2021-07-05 09:59


          點擊上方 藍字 關(guān)注我們!



          Java,Python,C/C++,Linux,PHP,Go,C#,QT,大數(shù)據(jù),算法,軟件教程,前端,簡歷,畢業(yè)設(shè)計等分類,資源在不斷更新中... 點擊領(lǐng)取

          每天 11 點更新文章,餓了點外賣,點擊 ??《無門檻外賣優(yōu)惠券,每天免費領(lǐng)!》

          來源:cnblogs.com/rickiyang/p/11074238.html


          前面我們簡單學(xué)習(xí)了NIO。我們知道java的I/O模型一共有四種,分別是:傳統(tǒng)的BIO,偽異步I/O,NIO和AIO。為了澄清概念和分清區(qū)別,我們還是先簡單的介紹一下他們的概念,然后再去比較優(yōu)劣。以及探討我們?yōu)槭裁词褂胣etty。

          1.概念澄清

          1.1 BIO

          BIO,即Blocking I/O。網(wǎng)絡(luò)編程的基本模型是Client/Server 模型,也就是兩個進程之間進行相互通信,其中服務(wù)端提供位置信息(綁定的Ip 地址和監(jiān)聽端口) ,客戶端通過連接操作向服務(wù)端監(jiān)聽的地址發(fā)起連接請求,通過三次握手建立連接,如果連接建在成功,雙方就可以通過網(wǎng)絡(luò)套接字( Socket ) 進行通信。在基于傳統(tǒng)同步阻塞模型開發(fā)中, ServerSocket 負責(zé)綁定IP 地址,啟動監(jiān)聽端口:Socket 負責(zé)發(fā)起連接操作。連接成功之后,雙方通過輸入和輸出流進行同步阻塞式通信 。

          BIO通信模型圖:

          解釋一下上圖:

          采用BIO通信模型的服務(wù)端,通常由一個獨立的Acceptor線程負責(zé)監(jiān)聽客戶端的連接,它接收到客戶端連接請求之后為每個客戶端創(chuàng)建一個新的線程進行鏈路處理,處理完成之后,通過輸出流返回應(yīng)答給客戶端, 統(tǒng)程銷毀。這就是典型的一請求一回答通信模型。

          對于這種IO模型我們知道:用戶線程發(fā)出IO請求之后,內(nèi)核會去查看數(shù)據(jù)是否就緒,如果沒有就緒就會等待數(shù)據(jù)就緒,而用戶線程就會處于阻塞狀態(tài),用戶線程交出CPU。當(dāng)數(shù)據(jù)就緒之后,內(nèi)核會將數(shù)據(jù)拷貝到用戶線程,并返回結(jié)果給用戶線程,用戶線程才解除block狀態(tài)。即在讀寫數(shù)據(jù)過程中會發(fā)生阻塞現(xiàn)象。

          1.2 偽異步IO

          為了解決同步阻塞 I/O 面臨的一個鏈路需要一個線程處理的問題,后來有人對它的線程模型進行了優(yōu)化一一后端通過一個線程池來處理多個客戶端的請求接入,形成客戶端個數(shù)M: 線程池最大線程數(shù)N 的比例關(guān)系,其中M 可以遠遠大于N。通過線程地可以靈活地調(diào)配線程資源,設(shè)置線程的最大值,防止由于海量并發(fā)接入導(dǎo)致線程耗盡。

          偽異步IO通信模型圖:

          采用線程池和任務(wù)隊列可以實現(xiàn)偽異步I/O通信框架。當(dāng)有新的客戶端接入時,將客戶端的Socket 封裝成一個Task (該任務(wù)實現(xiàn)java.lang. Runnable 接口)投遞到后端的線程池中進行處理, JDK 的線程將維護一個消息隊列和N個活躍線程, 對消息隊列中的任務(wù)進行處理。由于統(tǒng)程池可以設(shè)置消息隊列的大小和最大線程數(shù),因此,它的資源占用是可控的, 無論多少個客戶端并發(fā)訪問, 都不會導(dǎo)致資源的耗盡和省機。

          偽異步I/O 通信框架采用了線程池實現(xiàn),因此避免了為每個請求都創(chuàng)建一個獨立線程造成的線程資源耗盡問題。但是由于它底層的通信依然采用同步阻塞模型,因此無法從根本上解決問題。偽異步I/O 實際上僅僅是對之前I/O 線程模型的一個簡單優(yōu)化,它無法從根本上解決同步I/O 導(dǎo)致的通信線程阻塞問題。下面我們就簡單分析下通信對方返回應(yīng)答時間過長會引起的級聯(lián)故障。

          1. 服務(wù)端處理緩慢,返回應(yīng)答消息耗費60s,平時只需要10ms;
          2. 采用偽異步I/O 的線程在讀取故障服務(wù)節(jié)點的響應(yīng),由于讀/取輸入流是阻塞的,它將會被同步阻塞60s;
          3. 假如所有的可用線程都被故障服務(wù)器阻塞,那后續(xù)的所有的I/O消息都將在隊列中排隊;
          4. 由于線程地采用阻塞隊列實現(xiàn),當(dāng)隊列積滿之后,后續(xù)入隊列的操作將被阻塞;
          5. 由于前端只有一個Accptor 線程接收客戶端接入,它被阻塞在線程池的同步阻塞隊列之后,新的客戶端請求消息將被拒絕,客戶端會發(fā)生大量的連接超時;
          6. 由于幾于所有的連接都超時,調(diào)用者會認為系統(tǒng)已經(jīng)崩潰,無法接收新的請求消息。

          如何破解這個難題?下面我們再看一下NIO。

          1.3 NIO

          NIO,很多人叫他New I/O,由于之前老的I/O 類庫是阻塞I/O ,New I/O 類庫的目標(biāo)就是要讓Java 支持非阻塞I/O,所以,更多的人喜歡稱之為非阻塞I/O(Non-block I/O)。

          與Socket類和ServerSocket 類相對應(yīng), NIO也提供了SocketChannel 和ServerSocketChannel兩種不同的套接字通道實現(xiàn)。這兩種新增的通道都支持阻塞和非阻塞兩種模式。阻塞模式使用非常簡單,但是性能和可靠性都不好,非阻塞模式則正好相反。開發(fā)人員可以根據(jù)自己的需要來選擇合適的模式。一般來說,低負載、低并發(fā)的應(yīng)用程序可以選擇同步阻塞I/O以降低編程復(fù)雜度:對于高負載、高并發(fā)的網(wǎng)絡(luò)應(yīng)用,需要使用NIO 的非阻塞模式進行開發(fā)。

          前面我們已經(jīng)對NIO進行了介紹,我們知道NIO中引入了緩沖區(qū)Buffer,通道Channel和多路復(fù)用器Selector的概念。一個多路復(fù)用器Selector 可以同時輪詢多個Channel,而Channel又是全雙工的,同時支持讀寫操作,使用NIO 編程的優(yōu)點總結(jié)如下:

          1. 客戶端發(fā)起的連接操作是異步的,可以通過在多路復(fù)用器注冊O(shè)P_CONNECT 等待后續(xù)結(jié)果,不需要像之前的客戶端那樣被同步阻塞。
          2. SocketChannel 的讀寫操作都是異步的,如果沒有可讀寫的數(shù)據(jù)它不會同步等待,直接返回,這樣I/O 通信線程就可以處理其他的鏈路,不需要同步等待這個鏈路可用。
          3. 線程模型的優(yōu)化:由于JDK 的Selector 在Linux 等主流操作系統(tǒng)上通過epoll 實現(xiàn),它沒有連接句柄數(shù)的限制(只受限于操作系統(tǒng)的最大句柄數(shù)或者對單個進程的句柄限制),這意味著一個Selector 線程可以同時處理成千上萬個客戶端連接,而且性能不會隨著客戶端的增加而線性下降。因此,它非常適合做高性能、高負載的網(wǎng)絡(luò)服務(wù)器。

          1.4 AIO

          NIO 2.0 引入了新的異步通道的概念,并提供了異步文件通道和異步套接字通道的實現(xiàn)。異步通道提供以下兩種方式獲取獲取操作結(jié)果:

          ?通過java.util.concurrent.Future 類來表示異步操作的結(jié)果;

          ?在執(zhí)行異步操作的時候傳入一個java.nio.channels;

          NIO 2.0 的異步套接字通道是真正的異步非阻塞I/O ,對應(yīng)于UNIX 網(wǎng)絡(luò)編程中的事件 驅(qū)動I/O (AIO) 。它不需要通過多路復(fù)用器( Selector) 對注冊的通道進行輪詢操作即可實 現(xiàn)異步讀寫,從而簡化了NIO 的編程模型。

          前面對不同的I/O模型進行了簡單介紹,不同的I/O 模型由于線程模型、API 等差別很大,所以用法的差異也非常大。我們用一個表格來做一個統(tǒng)一說明:

          2. 為什么用Netty

          開發(fā)出高質(zhì)量的NIO 程序并不是一件簡單的事情,除去NIO 固有的復(fù)雜性和Bug不談,作為一個NIO 服務(wù)端,需要能夠處理網(wǎng)絡(luò)的閃斷、客戶端的重復(fù)接入、客戶端的安全認證、消息的編解碼、半包讀寫等情況, 如果你沒有足夠的NIO 編程經(jīng)驗積累, 一個NIO 框架的穩(wěn)定往往需要半年甚至更長的時間。更為糟糕的是, 一旦在生產(chǎn)環(huán)境中發(fā)生問題, 往往會導(dǎo)致跨節(jié)點的服務(wù)調(diào)用中斷, 嚴重的可能 會導(dǎo)致整個集群環(huán)境都不可用, 需要重啟服務(wù)器,這種非正常停機會帶來巨大的損失。

          從可維護性角度看,由于NIO 采用了異步非阻塞編程模型,而且是一個I/O 線程處理多條鏈路,它的調(diào)試和跟蹤非常麻煩, 特別是生產(chǎn)環(huán)境中的問題,我們無法進行有效的調(diào)試和跟蹤, 往往只能靠一些日志來幫助分析,定位難度很大。

          對于java原生的IO我們之所以不選擇使用是因為:

          1. NIO的類庫和API繁雜使用麻煩,你需要熟練掌握Selectol,ServerSocketChannel, SocketChannel,ByteBuffer 等。
          2. 需妥具備其他的額外技能做制墊,例如熟悉Java 多線程編程。這是因為NIO編程涉及到Reactor 模式,你必須對多錢程和網(wǎng)絡(luò)編程非常如悉,才能編寫出高質(zhì)量的NIO程序。
          3. 可靠性能力補齊, 工作量和難度都非常大。例如客戶端面臨斷連重連、網(wǎng)絡(luò)間斷、半包讀寫、失敗緩存、網(wǎng)絡(luò)擁塞和異常碼流的處理等問題, NI0 編程的特點是功能開發(fā)相對容易,但是可靠性能力補齊的工作量和難度都非常大。
          4. JDK NIO的BUG,比如epoll bug,這個BUG會在linux上導(dǎo)致cpu 100%,使得nio server/client不可用,這個BUG直到j(luò)dk 6u4才解決,但是直到JDK1.7中仍然有這個問題,該問題并未被完全解決,只是發(fā)生的頻率降低了而已。

          基于上述原因大多數(shù)場景下都不建議直接使原生NIO,除非你精通NIO編程或者是有特殊的需要,否則作為服務(wù)器編程的NIO可能會帶來巨大的生產(chǎn)隱患。

          關(guān)于Netty:

          Netty是一個高性能、異步事件驅(qū)動的NIO框架,它提供了對TCP、UDP和文件傳輸?shù)闹С郑鳛橐粋€異步NIO框架,Netty的所有IO操作都是異步非阻塞的,通過Future-Listener機制,用戶可以方便的主動獲取或者通過通知機制獲得IO操作結(jié)果。作為當(dāng)前最流行的NIO框架,Netty在互聯(lián)網(wǎng)領(lǐng)域、大數(shù)據(jù)分布式計算領(lǐng)域、游戲行業(yè)、通信行業(yè)等獲得了廣泛的應(yīng)用,一些業(yè)界著名的開源組件也基于Netty的NIO框架構(gòu)建。

          與Netty同樣功能的NIO框架還有Mina,Netty的主導(dǎo)作者與Mina的主導(dǎo)作者是同一人,在設(shè)計理念上與Mina基本上是一致的。Mina出身于開源界的大牛Apache組織,Netty出身于商業(yè)開源大亨Jboss。這幾年Netty社區(qū)相對比較活躍,所以我們就先選擇Netty作為入手網(wǎng)絡(luò)編程的首選,有時間再學(xué)習(xí)一下Mina。

          - END -

          往期推薦

          少賺10萬塊,字節(jié)跳動1/3員工不支持取消大小周

          分布式定時任務(wù)調(diào)度系統(tǒng)技術(shù)選型

          華為 13 年代碼的寶貴經(jīng)驗

          介紹一款零注解的API接口文檔生成工具

          看完文章,餓了點外賣,點擊 ??《無門檻外賣優(yōu)惠券,每天免費領(lǐng)!》

          END



          若覺得文章對你有幫助,隨手轉(zhuǎn)發(fā)分享,也是我們繼續(xù)更新的動力。


          長按二維碼,掃掃關(guān)注哦

          ?「C語言中文網(wǎng)」官方公眾號,關(guān)注手機閱讀教程 ?


          必備編程學(xué)習(xí)資料


          目前收集的資料包括: Java,Python,C/C++,Linux,PHP,go,C#,QT,git/svn,人工智能,大數(shù)據(jù),單片機,算法,小程序,易語言,安卓,ios,PPT,軟件教程,前端,軟件測試,簡歷,畢業(yè)設(shè)計,公開課 等分類,資源在不斷更新中...


          點擊“閱讀原文”,立即免費領(lǐng)取最新資料!
          ??????
          瀏覽 41
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  久久久精品中文字幕麻豆发布 | 久久中文综合 | 亚洲成A人片777777久久 | 麻豆传媒无码 | 特级无码一区二区三区 |