Jack Jiang

          我的最新工程MobileIMSDK:http://git.oschina.net/jackjiang/MobileIMSDK
          posts - 499, comments - 13, trackbacks - 0, articles - 1

          1、前言

          隨著互聯網的發展,面對海量用戶高并發業務,傳統的阻塞式的服務端架構模式已經無能為力。本文(和下篇《高性能網絡編程(六):一文讀懂高性能網絡編程中的線程模型》)旨在為大家提供有用的高性能網絡編程的I/O模型概覽以及網絡服務進程模型的比較,以揭開設計和實現高性能網絡架構的神秘面紗。

          限于篇幅原因,請將本文與《高性能網絡編程(六):一文讀懂高性能網絡編程中的線程模型》連起來讀,這樣會讓知識更連貫。

          學習交流:

          - 即時通訊開發交流3群:185926912[推薦]

          - 移動端IM開發入門文章:《新手入門一篇就夠:從零開發移動端IM

          (本文同步發布于:http://www.52im.net/thread-1935-1-1.html

          2、關于作者

          陳彩華(caison):主要從事服務端開發、需求分析、系統設計、優化重構工作,主要開發語言是 Java,現任廣州貝聊服務端研發工程師。

          關于廣州貝聊:

          廣州市貝聊信息科技有限公司成立于2013年8月21日,是一家專注于搭建幼兒園家園共育平臺的信息科技公司。

          公司產品“貝聊”是中國幼兒園家長工作平臺,致力于通過互聯網產品及定制化解決方案,幫助幼兒園解決展示、通知、溝通等家長工作中的痛點,促進家園關系和諧。貝聊是威創股份(A股幼教第一股)、清華啟迪、網易聯手投資的唯一品牌。

          截止目前,“貝聊”已覆蓋全國31省份的5萬所幼兒園及機構,注冊用戶超過1000萬,用戶次月留存率高達74%,復合增長率為18.94%,領跑全行業。

          3、C10K問題系列文章

          本文是C10K問題系列文章中的第5篇,總目錄如下:

          高性能網絡編程(一):單臺服務器并發TCP連接數到底可以有多少

          高性能網絡編程(二):上一個10年,著名的C10K并發連接問題

          高性能網絡編程(三):下一個10年,是時候考慮C10M并發問題了

          高性能網絡編程(四):從C10K到C10M高性能網絡應用的理論探索

          高性能網絡編程(五):一文讀懂高性能網絡編程中的I/O模型》(本文)

          高性能網絡編程(六):一文讀懂高性能網絡編程中的線程模型

          高性能網絡編程經典:《The C10K problem(英文)》[附件下載]

          4、互聯網服務端處理網絡請求的原理

          首先看看一個典型互聯網服務端處理網絡請求的典型過程:

          由上圖可以看到,主要處理步驟包括: 

          1)獲取請求數據,客戶端與服務器建立連接發出請求,服務器接受請求(1-3);

          2)構建響應,當服務器接收完請求,并在用戶空間處理客戶端的請求,直到構建響應完成(4);

          3)返回數據,服務器將已構建好的響應再通過內核空間的網絡 I/O 發還給客戶端(5-7)。

          設計服務端并發模型時,主要有如下兩個關鍵點: 

          1)服務器如何管理連接,獲取輸入數據;

          2)服務器如何處理請求。

          以上兩個關鍵點最終都與操作系統的 I/O 模型以及線程(進程)模型相關,這也是本文和下篇《高性能網絡編程(六):一文讀懂高性能網絡編程中的線程模型》將要介紹的內容。下面先詳細介紹這I/O模型。

          5、“I/O 模型”的基本認識

          介紹操作系統的 I/O 模型之前,先了解一下幾個概念: 

          1)阻塞調用與非阻塞調用;

          2)阻塞調用是指調用結果返回之前,當前線程會被掛起,調用線程只有在得到結果之后才會返回;

          3)非阻塞調用指在不能立刻得到結果之前,該調用不會阻塞當前線程。

          兩者的最大區別在于被調用方在收到請求到返回結果之前的這段時間內,調用方是否一直在等待。

          阻塞是指調用方一直在等待而且別的事情什么都不做;非阻塞是指調用方先去忙別的事情。

          同步處理與異步處理:同步處理是指被調用方得到最終結果之后才返回給調用方;異步處理是指被調用方先返回應答,然后再計算調用結果,計算完最終結果后再通知并返回給調用方。

          阻塞、非阻塞和同步、異步的區別(阻塞、非阻塞和同步、異步其實針對的對象是不一樣的)

          1)阻塞、非阻塞的討論對象是調用者;

          2)同步、異步的討論對象是被調用者。

          recvfrom 函數:

          recvfrom 函數(經 Socket 接收數據),這里把它視為系統調用。

          一個輸入操作通常包括兩個不同的階段:

          1)等待數據準備好;

          2)從內核向進程復制數據。

          對于一個套接字上的輸入操作,第一步通常涉及等待數據從網絡中到達。當所等待分組到達時,它被復制到內核中的某個緩沖區。第二步就是把數據從內核緩沖區復制到應用進程緩沖區。

          實際應用程序在系統調用完成上面的 2 步操作時,調用方式的阻塞、非阻塞,操作系統在處理應用程序請求時,處理方式的同步、異步處理的不同,可以分為 5 種 I/O 模型(下面的章節將逐個展開介紹)。(參考《UNIX網絡編程卷1》)

          6、I/O模型1:阻塞式 I/O 模型(blocking I/O)

          在阻塞式 I/O 模型中,應用程序在從調用 recvfrom 開始到它返回有數據報準備好這段時間是阻塞的,recvfrom 返回成功后,應用進程開始處理數據報。

          比喻:一個人在釣魚,當沒魚上鉤時,就坐在岸邊一直等。

          優點:程序簡單,在阻塞等待數據期間進程/線程掛起,基本不會占用 CPU 資源。

          缺點:每個連接需要獨立的進程/線程單獨處理,當并發請求量大時為了維護程序,內存、線程切換開銷較大,這種模型在實際生產中很少使用。

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

          在非阻塞式 I/O 模型中,應用程序把一個套接口設置為非阻塞,就是告訴內核,當所請求的 I/O 操作無法完成時,不要將進程睡眠。

          而是返回一個錯誤,應用程序基于 I/O 操作函數將不斷的輪詢數據是否已經準備好,如果沒有準備好,繼續輪詢,直到數據準備好為止。

          比喻:邊釣魚邊玩手機,隔會再看看有沒有魚上鉤,有的話就迅速拉桿。

          優點:不會阻塞在內核的等待數據過程,每次發起的 I/O 請求可以立即返回,不用阻塞等待,實時性較好。

          缺點:輪詢將會不斷地詢問內核,這將占用大量的 CPU 時間,系統資源利用率較低,所以一般 Web 服務器不使用這種 I/O 模型。

          8、I/O模型3:I/O 復用模型(I/O multiplexing)

          在 I/O 復用模型中,會用到 Select 或 Poll 函數或 Epoll 函數(Linux 2.6 以后的內核開始支持),這兩個函數也會使進程阻塞,但是和阻塞 I/O 有所不同。

          這兩個函數可以同時阻塞多個 I/O 操作,而且可以同時對多個讀操作,多個寫操作的 I/O 函數進行檢測,直到有數據可讀或可寫時,才真正調用 I/O 操作函數。

          比喻:放了一堆魚竿,在岸邊一直守著這堆魚竿,沒魚上鉤就玩手機。

          優點:可以基于一個阻塞對象,同時在多個描述符上等待就緒,而不是使用多個線程(每個文件描述符一個線程),這樣可以大大節省系統資源。

          缺點:當連接數較少時效率相比多線程+阻塞 I/O 模型效率較低,可能延遲更大,因為單個連接處理需要 2 次系統調用,占用時間會有增加。

          眾所周之,Nginx這樣的高性能互聯網反向代理服務器大獲成功的關鍵就是得益于Epoll。

          9、I/O模型4:信號驅動式 I/O 模型(signal-driven I/O)

          在信號驅動式 I/O 模型中,應用程序使用套接口進行信號驅動 I/O,并安裝一個信號處理函數,進程繼續運行并不阻塞。

          當數據準備好時,進程會收到一個 SIGIO 信號,可以在信號處理函數中調用 I/O 操作函數處理數據。

          比喻:魚竿上系了個鈴鐺,當鈴鐺響,就知道魚上鉤,然后可以專心玩手機。

          優點:線程并沒有在等待數據時被阻塞,可以提高資源的利用率。

          缺點:信號 I/O 在大量 IO 操作時可能會因為信號隊列溢出導致沒法通知。

          信號驅動 I/O 盡管對于處理 UDP 套接字來說有用,即這種信號通知意味著到達一個數據報,或者返回一個異步錯誤。

          但是,對于 TCP 而言,信號驅動的 I/O 方式近乎無用,因為導致這種通知的條件為數眾多,每一個來進行判別會消耗很大資源,與前幾種方式相比優勢盡失。

          10、I/O模型5:異步 I/O 模型(即AIO,全稱asynchronous I/O)

          由 POSIX 規范定義,應用程序告知內核啟動某個操作,并讓內核在整個操作(包括將數據從內核拷貝到應用程序的緩沖區)完成后通知應用程序。

          這種模型與信號驅動模型的主要區別在于:信號驅動 I/O 是由內核通知應用程序何時啟動一個 I/O 操作,而異步 I/O 模型是由內核通知應用程序 I/O 操作何時完成。

          優點:異步 I/O 能夠充分利用 DMA 特性,讓 I/O 操作與計算重疊。

          缺點:要實現真正的異步 I/O,操作系統需要做大量的工作。目前 Windows 下通過 IOCP 實現了真正的異步 I/O。

          而在 Linux 系統下,Linux 2.6才引入,目前 AIO 并不完善,因此在 Linux 下實現高并發網絡編程時都是以 IO 復用模型模式為主。

          關于AOI的介紹,請見:《Java新一代網絡編程模型AIO原理及Linux系統AIO介紹》。

          11、5 種 I/O 模型總結

          從上圖中我們可以看出,越往后,阻塞越少,理論上效率也是最優。

          這五種 I/O 模型中,前四種屬于同步 I/O,因為其中真正的 I/O 操作(recvfrom)將阻塞進程/線程,只有異步 I/O 模型才與 POSIX 定義的異步 I/O 相匹配。

          (本文下篇《高性能網絡編程(六):一文讀懂高性能網絡編程中的線程模型》已發布,敬請閱讀!)

          附錄:更多網絡編程精華文章

          [1] 網絡編程基礎資料:

          TCP/IP詳解 - 第11章·UDP:用戶數據報協議

          TCP/IP詳解 - 第17章·TCP:傳輸控制協議

          TCP/IP詳解 - 第18章·TCP連接的建立與終止

          TCP/IP詳解 - 第21章·TCP的超時與重傳

          技術往事:改變世界的TCP/IP協議(珍貴多圖、手機慎點)

          通俗易懂-深入理解TCP協議(上):理論基礎

          通俗易懂-深入理解TCP協議(下):RTT、滑動窗口、擁塞處理

          理論經典:TCP協議的3次握手與4次揮手過程詳解

          理論聯系實際:Wireshark抓包分析TCP 3次握手、4次揮手過程

          計算機網絡通訊協議關系圖(中文珍藏版)

          UDP中一個包的大小最大能多大?

          P2P技術詳解(一):NAT詳解——詳細原理、P2P簡介

          P2P技術詳解(二):P2P中的NAT穿越(打洞)方案詳解

          P2P技術詳解(三):P2P技術之STUN、TURN、ICE詳解

          通俗易懂:快速理解P2P技術中的NAT穿透原理

          不為人知的網絡編程(一):淺析TCP協議中的疑難雜癥(上篇)

          不為人知的網絡編程(二):淺析TCP協議中的疑難雜癥(下篇)

          不為人知的網絡編程(三):關閉TCP連接時為什么會TIME_WAIT、CLOSE_WAIT

          不為人知的網絡編程(四):深入研究分析TCP的異常關閉

          不為人知的網絡編程(五):UDP的連接性和負載均衡

          不為人知的網絡編程(六):深入地理解UDP協議并用好它

          不為人知的網絡編程(七):如何讓不可靠的UDP變的可靠?

          網絡編程懶人入門(一):快速理解網絡通信協議(上篇)

          網絡編程懶人入門(二):快速理解網絡通信協議(下篇)

          網絡編程懶人入門(三):快速理解TCP協議一篇就夠

          網絡編程懶人入門(四):快速理解TCP和UDP的差異

          網絡編程懶人入門(五):快速理解為什么說UDP有時比TCP更有優勢

          網絡編程懶人入門(六):史上最通俗的集線器、交換機、路由器功能原理入門

          網絡編程懶人入門(七):深入淺出,全面理解HTTP協議

          網絡編程懶人入門(八):手把手教你寫基于TCP的Socket長連接

          技術掃盲:新一代基于UDP的低延時網絡傳輸層協議——QUIC詳解

          讓互聯網更快:新一代QUIC協議在騰訊的技術實踐分享

          現代移動端網絡短連接的優化手段總結:請求速度、弱網適應、安全保障

          聊聊iOS中網絡編程長連接的那些事

          移動端IM開發者必讀(一):通俗易懂,理解移動網絡的“弱”和“慢”

          移動端IM開發者必讀(二):史上最全移動弱網絡優化方法總結

          IPv6技術詳解:基本概念、應用現狀、技術實踐(上篇)

          IPv6技術詳解:基本概念、應用現狀、技術實踐(下篇)

          從HTTP/0.9到HTTP/2:一文讀懂HTTP協議的歷史演變和設計思路

          腦殘式網絡編程入門(一):跟著動畫來學TCP三次握手和四次揮手

          腦殘式網絡編程入門(二):我們在讀寫Socket時,究竟在讀寫什么?

          腦殘式網絡編程入門(三):HTTP協議必知必會的一些知識

          腦殘式網絡編程入門(四):快速理解HTTP/2的服務器推送(Server Push)

          以網游服務端的網絡接入層設計為例,理解實時通信的技術挑戰

          >> 更多同類文章 ……

          [2] NIO高性能異步網絡編程資料:

          Java新一代網絡編程模型AIO原理及Linux系統AIO介紹

          有關“為何選擇Netty”的11個疑問及解答

          開源NIO框架八卦——到底是先有MINA還是先有Netty?

          選Netty還是Mina:深入研究與對比(一)

          選Netty還是Mina:深入研究與對比(二)

          NIO框架入門(一):服務端基于Netty4的UDP雙向通信Demo演示

          NIO框架入門(二):服務端基于MINA2的UDP雙向通信Demo演示

          NIO框架入門(三):iOS與MINA2、Netty4的跨平臺UDP雙向通信實戰

          NIO框架入門(四):Android與MINA2、Netty4的跨平臺UDP雙向通信實戰

          Netty 4.x學習(一):ByteBuf詳解

          Netty 4.x學習(二):Channel和Pipeline詳解

          Netty 4.x學習(三):線程模型詳解

          Apache Mina框架高級篇(一):IoFilter詳解

          Apache Mina框架高級篇(二):IoHandler詳解

          MINA2 線程原理總結(含簡單測試實例)

          Apache MINA2.0 開發指南(中文版)[附件下載]

          MINA、Netty的源代碼(在線閱讀版)已整理發布

          解決MINA數據傳輸中TCP的粘包、缺包問題(有源碼)

          解決Mina中多個同類型Filter實例共存的問題

          實踐總結:Netty3.x升級Netty4.x遇到的那些坑(線程篇)

          實踐總結:Netty3.x VS Netty4.x的線程模型

          詳解Netty的安全性:原理介紹、代碼演示(上篇)

          詳解Netty的安全性:原理介紹、代碼演示(下篇)

          詳解Netty的優雅退出機制和原理

          NIO框架詳解:Netty的高性能之道

          Twitter:如何使用Netty 4來減少JVM的GC開銷(譯文)

          絕對干貨:基于Netty實現海量接入的推送服務技術要點

          Netty干貨分享:京東京麥的生產級TCP網關技術實踐總結

          >> 更多同類文章 ……

          (本文同步發布于:http://www.52im.net/thread-1935-1-1.html



          作者:Jack Jiang (點擊作者姓名進入Github)
          出處:http://www.52im.net/space-uid-1.html
          交流:歡迎加入即時通訊開發交流群 215891622
          討論:http://www.52im.net/
          Jack Jiang同時是【原創Java Swing外觀工程BeautyEye】【輕量級移動端即時通訊框架MobileIMSDK】的作者,可前往下載交流。
          本博文 歡迎轉載,轉載請注明出處(也可前往 我的52im.net 找到我)。


          只有注冊用戶登錄后才能發表評論。


          網站導航:
           
          Jack Jiang的 Mail: jb2011@163.com, 聯系QQ: 413980957, 微信: hellojackjiang
          主站蜘蛛池模板: 嘉祥县| 茂名市| 元阳县| 四子王旗| 上林县| 常熟市| 昌都县| 盱眙县| 当阳市| 河池市| 肃南| 三都| 疏附县| 东山县| 高邮市| 依安县| 额济纳旗| 庄河市| 娱乐| 察隅县| 湘乡市| 高唐县| 宁晋县| 绥阳县| 康平县| 沅江市| 芜湖市| 宁明县| 双城市| 武宣县| 屏东市| 北海市| 青龙| 福清市| 罗平县| 乌什县| 开鲁县| 宁乡县| 徐闻县| 怀化市| 延津县|