1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

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

        共 4587字,需瀏覽 10分鐘

         ·

        2021-07-05 09:59


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



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

        每天 11 點(diǎn)更新文章,餓了點(diǎn)外賣,點(diǎn)擊 ??《無門檻外賣優(yōu)惠券,每天免費(fèi)領(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 模型,也就是兩個(gè)進(jìn)程之間進(jìn)行相互通信,其中服務(wù)端提供位置信息(綁定的Ip 地址和監(jiān)聽端口) ,客戶端通過連接操作向服務(wù)端監(jiān)聽的地址發(fā)起連接請(qǐng)求,通過三次握手建立連接,如果連接建在成功,雙方就可以通過網(wǎng)絡(luò)套接字( Socket ) 進(jìn)行通信。在基于傳統(tǒng)同步阻塞模型開發(fā)中, ServerSocket 負(fù)責(zé)綁定IP 地址,啟動(dòng)監(jiān)聽端口:Socket 負(fù)責(zé)發(fā)起連接操作。連接成功之后,雙方通過輸入和輸出流進(jìn)行同步阻塞式通信 。

        BIO通信模型圖:

        解釋一下上圖:

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

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

        1.2 偽異步IO

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

        偽異步IO通信模型圖:

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

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

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

        如何破解這個(gè)難題?下面我們?cè)倏匆幌翹IO。

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

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

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

        1.4 AIO

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

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

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

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

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

        2. 為什么用Netty

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

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

        對(duì)于java原生的IO我們之所以不選擇使用是因?yàn)椋?/p>

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

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

        關(guān)于Netty:

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

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

        - END -

        往期推薦

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

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

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

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

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

        END



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


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

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


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


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


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

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        評(píng)論
        圖片
        表情
        推薦
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            亚洲日韩小电影 | 亚洲国产va | 视频三区| 欧美黑逼 | 男男h双腿涨灌play慎入动漫 | 第一次处破女h圆房~h嗯啊 | 蜜臀久久99精品久久久久久果冻 | 欧美操操操 | 亚洲无码免费 | 丁香五月在线播放 |