您好,登錄后才能下訂單哦!
本篇文章為大家展示了怎么深入理解Linux高性能網絡架構,內容簡明扼要并且容易理解,絕對能使你眼前一亮,通過這篇文章的詳細介紹希望你能有所收獲。
1. 落寞的小黑
上周北京很冷,周五晚上大白下班奔地鐵站,收到了好基友小黑的微信:
于是大白掉頭掃了個單車奔五道口了,小黑靠譜地選了個不錯的位置。
小黑: 你今天下班挺早呀!
大白: 就咱這覺悟,心里有工作,哪里都是辦公桌,不要拘泥于形式嘛。
明顯能感覺得到小黑哥最近好像比較累,之前眼里bulingbuling閃的光是看不到了。
大白: 下午去面的哪家?啥崗位?咋樣?
小黑: 是一家做自動駕駛的創業公司,網站是看團隊介紹還不錯,就去看看了,這次沒咋準備,很多問題其實都熟悉,但是回答的不到位。
大白: 哦,明白了,那就是當時理解的不到位,稀里糊涂過去了,現在忽然問起來,想不起重點。
小黑: 差不多吧,問我都做過哪些高性能的網絡框架模型,也就是IO和事件驅動那一套。
話說完,小黑喝了一大口啤酒,大白看出了小黑心里有一些落寞。畢竟在帝都這個地方競爭和工作壓力,以及生活瑣事都一直圍繞著我們,但是金錢和好運都巧妙地避開了自己...
想到這里,大白也深深喝了一大口,我命由我不由天,開整!
大白:黑哥,你說這個問題確實不好回答,全是術語和略帶歧義的東西,我覺得我們抓住本質去闡述就好。
小黑:來,請開始你的表演,我學習學習。
大白決定和小黑好好聊聊,Linux開發中常用的高性能網絡框架中的一些事兒,火鍋的映襯下讓夜色和天氣都不那么寒冷了。
通過本文你將會了解到以下內容:
IO事件和IO復用
線程模型和事件驅動模型的架構
基于事件驅動的Reactor模式詳解
同步IO和異步IO簡介
2. IO事件和IO復用
2.1 什么是IO事件
IO指的是輸入Input/輸出Output,但是從漢語角度來說,出和入是相對的,所以我們需要個參照物。這里我們的參照物選擇為程序運行時的主存儲空間,外部通常包括網卡、磁盤等。有了上述的設定理解起來就方便多了,我們來一起看下:
IO的本質是數據的流動,數據可以從網卡到程序內存,也可以從程序內存寫到網卡,磁盤操作也是如此。
所以可以把常見的IO分為:
網絡IO:內存和網卡的數據交互
文件IO:內存和磁盤的數據交互
那什么又是IO事件呢?事件可以理解為一種狀態或者動作,也就是狀態的遷移會觸發一種相應的動作。網絡IO的事件通常包括:
可讀事件
可寫事件
異常事件
理解可讀可寫事件是非常有必要的,一般來說一個socket大部分時候是可寫的,但是并不是都可讀。可讀一般代表是一個新連接或者原有連接有新數據交互,對于服務端程序來說也是重點關注的事件。
2.2 什么是IO復用
設想假如有幾萬個IO事件,那么應用程序該如何管理呢?這就要提到IO復用了。IO復用從本質上來說就是應用程序借助于IO復用函數向內核注冊很多類型的IO事件,當這些注冊的IO事件發生變化時內核就通過IO復用函數來通知應用程序。
從圖中可以看到,IO復用中復用的就是一個負責監聽管理這些IO事件的線程。之所以可以實現一個線程管理成百上千個IO事件,是因為大部分時間里某個時刻只有少量IO事件被觸發。
大概就像這樣:草原上的一只大狗可以看管幾十只綿羊,因為大部分時候只有個別綿羊不守規矩亂跑,其他的都是乖乖吃草。
3. 網絡框架設計要素
要理解網絡框架有哪些,必須要清楚網絡框架完成了哪些事情。
大致描述下這個請求處理的流程:
遠端的機器A發送了一個HTTP請求到服務器B,此時服務器B網卡接收到數據并產生一個IO可讀事件;
我們以同步IO為例,此時內核將該可讀事件通知到應用程序的Listen線程;
Listen線程將任務甩給Handler線程,由Handler將數據從內核讀緩沖區拷貝到用戶空間讀緩沖區;
請求數據包在應用程序內部進行計算和處理并封裝響應包;
Handler線程等待可寫事件的到來;
當這個連接可寫時將數據從用戶態寫緩沖區拷貝到內核緩沖區,并通過網卡發送出去;
備注:上述例子是以同步IO為例,并且將線程中的角色分為Listen線程、Handler線程、Worker線程,分別完成不同的工作,后續會詳細展開。
所以我們可以知道,要完成一個數據交互,涉及了幾大塊內容:
IO事件監聽
數據拷貝
數據處理和計算
大白認為,這三大塊內容,不論什么形式的框架都繞不開,也是理解網絡架構的關鍵所在。
4. 高性能網絡框架實踐
4.1 基于線程模型
在早期并發數不多的場景中,有一種One Request One Thread的架構模式。該模式下每次接收一個新請求就創建一個處理線程,線程雖然消耗資源并不多,但是成千上萬請求打過來,性能也是扛不住的。
這是一種比較原始的架構,思路也非常清晰,創建多個線程來提供處理能力,但在高并發生產環境中幾乎沒有應用,本文不再展開。
4.2 基于事件驅動模型
當前流行的是基于事件驅動的IO復用模型,相比多線程模型優勢很明顯。
在此我們先理解一下什么是事件驅動Event-Drive-Model。
事件驅動編程是一種編程范式,程序的執行流由外部事件來決定,它的特點是包含一個事件循環,當外部事件發生時使用回調機制來觸發相應的處理。
通俗來說就是:有一個循環裝置在一直等待各種事件的到來,并將到達的事件放到隊列中,再由一個分揀裝置來調用對應的處理裝置來響應。
4.3 Reactor反應堆模式
第一次聽到這個模式的時候很困惑,究竟反應堆是個啥?研究了一下發現,反應堆是個核物理的概念,大致是這個樣子的:
核反應堆是核電站的心臟 ,它的工作原理是這樣的:原子由原子核與核外電子組成,原子核由質子與中子組成。
當鈾235的原子核受到外來中子轟擊時,一個原子核會吸收一個中子分裂成兩個質量較小的原子核,同時放出2-3個中子。
這裂變產生的中子又去轟擊另外的鈾235原子核,引起新的裂變,如此持續進行就是裂變的鏈式反應。
結合這種核裂變的圖,好像是一個請求打過來,服務器內部瞬間延伸出很多分支來完成響應,一變二,二變四,甚至更多,確實有種反應堆的感覺。接下來我們看看究竟反應堆模式是如何構建高性能網絡框架的。
5.反應堆模式詳解
反應堆模式是一種思想,形式卻有很多種。
5.1 反應堆模式的本質是什么
從本質上理解,無論什么網絡框架都要完成兩部分操作:
IO操作:數據包的讀取和寫入
CPU操作:數據請求的處理和封裝
所以上述這些問題由誰來做以及多少線程來做,就衍生出了很多形式,所以不要被表面現象迷惑,出現必有原因,追溯之后我們才能真正掌握它。
反應堆模式根據處理IO環節和處理數據環節的數量差異分為如下幾種:
單Reactor線程
單Reactor線程和線程池
多Reactor線程和線程池
我們來看看這三種常見模式的特點、原理、優缺點、應用場景等。
5.2 單Reactor線程模式
這種模式最為簡潔,一個線程完成了連接的監聽、接收新連接、處理連接、讀取數據、寫入數據全套工作。由于只使用了一個線程,對于多核利用率偏低,但是編程簡單。是不是覺得這個種單線程的模式沒有市場?那可未必,不信你看Redis。
在這種模式種IO操作和CPU操作是沒有分開的,都是由1個線程來完成的,顯然如果在Handler處理某個請求超時了將會阻塞客戶端的正常連接。在Redis中由于都是內存操作,速度很快,這種瓶頸雖然存在但是不夠明顯。
5.3 單Reactor線程和線程池模式
為了解決IO操作和CPU操作的不匹配,也就是IO操作和CPU操作是在一個線程內部串行執行的,這樣就拉低了CPU操作效率。
一種解決方法就是將IO操作和CPU操作分別由單獨的線程來完成,各玩各的互不影響。單Reactor線程完成IO操作、復用工作線程池來完成CPU操作就是一種解決思路。
在這種模式種由Reactor線程完成連接的管理和數據讀取&寫回,完全掌管IO操作。工作線程池處理來自上游分發的任務,對其中的數據進行解碼、計算、編碼再返回給Reactor線程和客戶端完成交互。這種模式有效利用了多核,但是單Reactor線程來完成IO操作在高并發場景中仍然會出現瓶頸。換句話說,連接實在太多了,一個Reactor線程忙不過來建立新連接和響應舊連接這些事情,因此Reactor線程也需要幾個幫手。
5.4 多Reactor線程和線程池模式
水平擴展往往是提供性能的有效方法。
我們將Reactor線程進行擴展,一個Reactor線程負責處理新連接,多個Reactor線程負責處理連接成功的IO數據讀寫。也就是進一步將監聽&創建連接 和 處理連接 分別由兩個及以上的線程來完成,進一步提高了IO操作部分的效率。
這種模式算是比較高配的版本了,在實際生產環境也有使用。
5.5 拓展:同步IO和異步IO
我們可以輕易區分什么是阻塞IO和非阻塞IO,那么什么是同步IO和異步IO呢?前面提到Reactor模式其中非常重要的一環就是調用read/write函數來完成數據拷貝,這部分是應用程序自己完成的,內核只負責通知監控的事件到來了,所以本質上Reactor模式屬于非阻塞同步IO。還有一種Preactor模式,借助于系統本身的異步IO特性,由操作系統進行數據拷貝,在完成之后來通知應用程序來取就可以,效率更高一些,但是底層需要借助于內核的異步IO機制來實現。
底層的異步IO機制可能借助于DMA和Zero-Copy技術來實現,理論上性能更高。當前Windows系統通過IOCP實現了真正的異步I/O,而在Linux 系統的異步I/O還不完善,比如Linux中的boost.asio模塊就是異步IO的支持,但是目前Linux系統還是以基于Reactor模式的非阻塞同步IO為主。
6. 小結
本文從IO事件和IO復用出發,闡述了網絡架構最底層的組成。繼續展開了基于線程模型和基于事件驅動模型的網絡框架特點及其設計要素。之后重點描述了反應堆模式的核心本質,以及生產環境中的多種形式。最后簡單介紹了同步IO和異步IO的區別,以及Preactor模式的優勢。希望讀者朋友可以摒棄專業術語和表述,抓住問題的本質和重點,找到一個適合自己思維方法去理解和掌握高性能網絡架構的設計之道。或許,高性能網絡框架只是一個紙老虎。
上述內容就是怎么深入理解Linux高性能網絡架構,你們學到知識或技能了嗎?如果還想學到更多技能或者豐富自己的知識儲備,歡迎關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。