1. 程式人生 > >【網絡】高性能網絡編程--下一個10年,是時候考慮C10M並發問題了

【網絡】高性能網絡編程--下一個10年,是時候考慮C10M並發問題了

分享 千萬 改善 iii 接下來 field 連接數 開發 總結

轉載:http://www.52im.net/thread-568-1-1.html

1、前言


在本系列文章的上篇中我們回顧了過雲的10年裏,高性能網絡編程領域著名的C10K問題及其成功的解決方案(上篇請見:《高性能網絡編程(二):上一個10年,著名的C10K並發連接問題)。本文將討論單機服務器實現C10M(即單機千萬並發連接)的可能性及其思路。

截至目前,40gpbs、32-cores、256G RAM的X86服務器在Newegg網站上的報價是幾千美元。實際上以這樣的硬件配置來看,它完全可以處理1000萬個以上的並發連接,如果它們不能,那是因為你選擇了錯誤的軟件,而不是底層硬件的問題。

可以預見在接下來的10年裏,因為IPv6協議下每個服務器的潛在連接數都是數以百萬級的,單機服務器處理數百萬的並發連接(甚至千萬)並非不可能,但我們需要重新審視目前主流OS針對網絡編程這一塊的具體技術實現。

2、C10K問題系列文章


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

  • 《高性能網絡編程(一):單臺服務器並發TCP連接數到底可以有多少》
  • 《高性能網絡編程(二):上一個10年,著名的C10K並發連接問題》
  • 《高性能網絡編程(三):下一個10年,是時候考慮C10M並發問題了》(本文
  • 《高性能網絡編程(四):從C10K到C10M高性能網絡應用的理論探索》
  • 《高性能網絡編程經典:《The C10K problem(英文)》[附件下載]》

3、解決C10M問題並非不可能


<ignore_js_op>技術分享圖片很多人會想當然的認為,要實現C10M(即單機千萬)並發連接和處理能力,是不可能的。不過事實並非如此,現在系統已經在用你可能不熟悉甚至激進的方式支持千萬級別的並發連接。

要知道它是如何做到的,我們首先要了解Errata Security的CEO Robert Graham,以及他在Shmoocon 2013大會上的“天方夜談”視頻記錄: C10M Defending The Internet At Scale(此為Yutube視頻,你懂的)。

Robert用一種我以前從未聽說的方式來很巧妙地解釋了這個問題。他首先介紹了一點有關Unix的歷史,Unix的設計初衷並不是一般的服務器操作系統,而是電話網絡的控制系統。由於是實際傳送數據的電話網絡,所以在控制層和數據層之間有明確的界限。問題是我們現在根本不應該使用Unix服務器作為數據層的一部分。正如設計只運行一個應用程序的服務器內核,肯定和設計多用戶的服務器內核是不同的。

Robert Graham的結論是:

OS的內核不是解決C10M問題的辦法,恰恰相反OS的內核正是導致C10M問題的關鍵所在。

這也就意味著:

不要讓OS內核執行所有繁重的任務:將數據包處理、內存管理、處理器調度等任務從內核轉移到應用程序高效地完成,讓諸如Linux這樣的OS只處理控制層,數據層完全交給應用程序來處理。


最終就是要設計這樣一個系統,該系統可以處理千萬級別的並發連接,它在200個時鐘周期內處理數據包,在14萬個時鐘周期內處理應用程序邏輯。由於一次主存儲器訪問就要花費300個時鐘周期,所以這是最大限度的減少代碼和緩存丟失的關鍵。

面向數據層的系統可以每秒處理1千萬個數據包,面向控制層的系統,每秒只能處理1百萬個數據包。這似乎很極端,請記住一句老話:可擴展性是專業化的,為了做好一些事情,你不能把性能問題外包給操作系統來解決,你必須自己做。

4、回顧一下C10K問題


10年前,開發人員處理C10K可擴展性問題時,盡量避免服務器處理超過1萬個的並發連接。通過改進操作系統內核以及用事件驅動服務器(典型技術實現如:Nginx和Node)代替線程服務器(典型代表:Apache),使得這個問題已經被解決。人們用十年的時間從Apache轉移到可擴展服務器,在近幾年,可擴展服務器的采用率增長得更快了。

以傳統網絡編程模型作為代表的Apache為例,我們來看看它在C10K問題上的局限表現在哪些方面,並針對性的討論對應的解決方法。

Apache的問題在於服務器的性能會隨著連接數的增多而變差,實際上性能和可擴展性並不是一回事。當人們談論規模時,他們往往是在談論性能,但是規模和性能是不同的,比如Apache。持續幾秒的短期連接:比如快速事務,如果每秒處理1000個事務,只能有約1000個並發連接到服務器。如果事務延長到10秒,要維持每秒1000個事務則必須打開1萬個並發連接。這種情況下:盡管你不顧DoS攻擊,Apache也會性能陡降,同時大量的下載操作也會使Apache崩潰。

如果每秒處理的連接從5千增加到1萬,你會怎麽做?比方說,你升級硬件並且提高處理器速度到原來的2倍。到底發生了什麽?你得到兩倍的性能,但你沒有得到兩倍的處理規模。每秒處理的連接可能只達到了6000。你繼續提高速度,情況也沒有改善。甚至16倍的性能時,仍然不能處理1萬個並發連接。所以說性能和可擴展性是不一樣的。

問題在於Apache會創建一個CGI進程,然後關閉,這個步驟並沒有擴展。為什麽呢?內核使用的O(N^2)算法使服務器無法處理1萬個並發連接。

OS內核中的兩個基本問題:

  • 連接數=線程數/進程數:當一個數據包進來,內核會遍歷其所有進程以決定由哪個進程來處理這個數據包。
  • 連接數=選擇數/輪詢次數(單線程):同樣的可擴展性問題,每個包都要走一遭列表上所有的socket。


通過上述針對Apache所表現出的問題,實際上徹底解決並發性能問題的解決方法的根本就是改進OS內核使其在常數時間內查找,使線程切換時間與線程數量無關,使用一個新的可擴展epoll()/IOCompletionPort常數時間去做socket查詢。

因為線程調度並沒有得到擴展,所以服務器大規模對socket使用epoll方法,這樣就導致需要使用異步編程模式,而這些編程模式正是Nginx和Node類型服務器具有的。所以當從Apache遷移到Nginx和Node類型服務器時,即使在一個配置較低的服務器上增加連接數,性能也不會突降。所以在處理C10K連接時,一臺筆記本電腦的速度甚至超過了16核的服務器。這也是前一個10年解決C10K問題的普遍方法。

5、實現C10M意味著什麽?


實現10M(即1千萬)的並發連接挑戰意味著什麽:

  • 1千萬的並發連接數;
  • 100萬個連接/秒:每個連接以這個速率持續約10秒;
  • 10GB/秒的連接:快速連接到互聯網;
  • 1千萬個數據包/秒:據估計目前的服務器每秒處理50K數據包,以後會更多;
  • 10微秒的延遲:可擴展服務器也許可以處理這個規模(但延遲可能會飆升);
  • 10微秒的抖動:限制最大延遲;
  • 並發10核技術:軟件應支持更多核的服務器(通常情況下,軟件能輕松擴展到四核,服務器可以擴展到更多核,因此需要重寫軟件,以支持更多核的服務器)。

6、為什麽說實現C10M的挑戰不在硬件而在軟件?

1理由概述


硬件不是10M問題的性能瓶頸所在處,真正的問題出在軟件上,尤其是*nux操作系統。理由如下面這幾點:

首先:最初的設計是讓Unix成為一個電話網絡的控制系統,而不是成為一個服務器操作系統。對於控制系統而言,針對的主要目標是用戶和任務,而並沒有針對作為協助功能的數據處理做特別設計,也就是既沒有所謂的快速路徑、慢速路徑,也沒有各種數據服務處理的優先級差別。

其次:傳統的CPU,因為只有一個核,操作系統代碼以多線程或多任務的形式來提升整體性能。而現在,4核、8核、32核、64核和100核,都已經是真實存在的CPU芯片,如何提高多核的性能可擴展性,是一個必須面對的問題。比如讓同一任務分割在多個核心上執行,以避免CPU的空閑浪費,當然,這裏面要解決的技術點有任務分割、任務同步和異步等。

再次:核心緩存大小與內存速度是一個關鍵問題。現在,內存已經變得非常的便宜,隨便一臺普通的筆記本電腦,內存至少也就是4G以上,高端服務器的內存上24G那是相當的平常。但是,內存的訪問速度仍然很慢,CPU訪問一次內存需要約60~100納秒,相比很久以前的內存訪問速度,這基本沒有增長多少。對於在一個帶有1GHZ主頻CPU的電腦硬件裏,如果要實現10M性能,那麽平均每一個包只有100納秒,如果存在兩次CPU訪問內存,那麽10M性能就達不到了。核心緩存,也就是CPU L1/L2/LL Cache,雖然訪問速度會快些,但大小仍然不夠,我之前接觸到的高端至強,LLC容量大小貌似也就是12M。

2解決思路


解決這些問題的關鍵在於如何將功能邏輯做好恰當的劃分,比如專門負責控制邏輯的控制面和專門負責數據邏輯的數據面。數據面專門負責數據的處理,屬於資源消耗的主要因素,壓力巨大,而相比如此,控制面只負責一些偶爾才有非業務邏輯,比如與外部用戶的交互、信息的統計等等。我之前接觸過幾種網絡數據處理框架,比如Intel的DPDK、6wind、windriver,它們都針對Linux系統做了特別的補充設計,增加了數據面、快速路徑等等特性,其性能的提升自然是相當巨大。

看一下這些高性能框架的共同特點:

  • 數據包直接傳遞到業務邏輯:
    而不是經過Linux內核協議棧。這是很明顯的事情,因為我們知道,Linux協議棧是復雜和繁瑣的,數據包經過它無非會導致性能的巨大下降,並且會占用大量的內存資源,之前有同事測試過,Linux內核要吃掉2.5KB內存/socket。我研究過很長一段時間的DPDK源碼,其提供的82576和82599網卡驅動就直接運行在應用層,將接管網卡收到的數據包直接傳遞到應用層的業務邏輯裏進行處理,而無需經過Linux內核協議棧。當然,發往本服務器的非業務邏輯數據包還是要經過Linux內核協議棧的,比如用戶的SSH遠程登錄操作連接等。
  • 多線程的核間綁定:
    一個具有8核心的設備,一般會有1個控制面線程和7個或8個數據面線程,每一個線程綁定到一個處理核心(其中可能會存在一個控制面線程和一個數據面線程都綁定到同一個處理核心的情況)。這樣做的好處是最大化核心CACHE利用、實現無鎖設計、避免進程切換消耗等等。
  • 內存是另外一個核心要素:
    常見的內存池設計必須在這裏得以切實應用。有幾個考慮點,首先,可以在Linux系統啟動時把業務所需內存直接預留出來,脫離Linux內核的管理。其次,Linux一般采用4K每頁,而我們可以采用更大內存分頁,比如2M,這樣能在一定程度上減少地址轉換等的性能消耗。


關於Intel的DPDK框架介紹:

隨著網絡技術的不斷創新和市場的發展,越來越多的網絡設備基礎架構開始向基於通用處理器平臺的架構方向融合,期望用更低的成本和更短的產品開發周期來提供多樣的網絡單元和豐富的功能,如應用處理、控制處理、包處理、信號處理等。為了適應這一新的產業趨勢, Intel推出了基於Intel x86架構DPDK (Data Plane Development Kit,數據平面開發套件) 實現了高效靈活的包處理解決方案。經過近6年的發展,DPDK已經發展成支持多種高性能網卡和多通用處理器平臺的開源軟件工具包。


有興趣的技術同行,也許可以參考下DPDK的源代碼,目前DPDK已經完全開源並且可以網絡下載了。

7、解決C10M問題的思路總結


綜上所述,解決C10M問題的關鍵主要是從下面幾個方面入手:

網卡問題:通過內核工作效率不高
解決方案:使用自己的驅動程序並管理它們,使適配器遠離操作系統。

CPU問題:使用傳統的內核方法來協調你的應用程序是行不通的。
解決方案:Linux管理前兩個CPU,你的應用程序管理其余的CPU,中斷只發生在你允許的CPU上。

內存問題:內存需要特別關註,以求高效。
解決方案:在系統啟動時就分配大部分內存給你管理的大內存頁。

以Linux為例,解決的思咯就是將控制層交給Linux,應用程序管理數據。應用程序與內核之間沒有交互、沒有線程調度、沒有系統調用、沒有中斷,什麽都沒有。 然而,你有的是在Linux上運行的代碼,你可以正常調試,這不是某種怪異的硬件系統,需要特定的工程師。你需要定制的硬件在數據層提升性能,但是必須是在你熟悉的編程和開發環境上進行。

8、參考資料


[1] The Secret To 10 Million Concurrent Connections -The Kernel Is The Problem, Not The Solution
[2] *nux平臺上的C10M問題
[3] 千萬級並發實現的秘密:內核不是解決方案,而是問題所在
[4] 為什麽QQ用的是UDP協議而不是TCP協議?
[5] 移動端IM/推送系統的協議選型:UDP還是TCP?
[6] 高性能網絡編程經典:《The C10K problem(英文)》[附件下載]
[7] 高性能網絡編程(一):單臺服務器並發TCP連接數到底可以有多少
[8] 《The C10K problem (英文在線閱讀、英文PDF版下載、中文譯文)》
[9] 高性能網絡編程經典:《The C10K problem(英文)》[附件下載]
[10] [通俗易懂]深入理解TCP協議(上):理論基礎
[11] [通俗易懂]深入理解TCP協議(下):RTT、滑動窗口、擁塞處理
[12] 《TCP/IP詳解 卷1:協議 (在線閱讀版)》

9、更多資料


《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中一個包的大小最大能多大?》
《Java新一代網絡編程模型AIO原理及Linux系統AIO介紹》
《NIO框架入門(一):服務端基於Netty4的UDP雙向通信Demo演示》
《NIO框架入門(二):服務端基於MINA2的UDP雙向通信Demo演示》
《NIO框架入門(三):iOS與MINA2、Netty4的跨平臺UDP雙向通信實戰》
《NIO框架入門(四):Android與MINA2、Netty4的跨平臺UDP雙向通信實戰》
《P2P技術詳解(一):NAT詳解——詳細原理、P2P簡介》
《P2P技術詳解(二):P2P中的NAT穿越(打洞)方案詳解》
《P2P技術詳解(三):P2P技術之STUN、TURN、ICE詳解》
《高性能網絡編程(一):單臺服務器並發TCP連接數到底可以有多少》
《高性能網絡編程(二):上一個10年,著名的C10K並發連接問題》
《高性能網絡編程(三):下一個10年,是時候考慮C10M並發問題了》
《高性能網絡編程(四):從C10K到C10M高性能網絡應用的理論探索》
>> 更多同類文章 ……

其他資料:

http://chunqi.li/2015/11/15/Battlefield-Calico-Flannel-Weave-and-Docker-Overlay-Network/

https://www.cnblogs.com/Anker/p/6156149.html

https://www.cnblogs.com/bakari/p/8404650.html

http://www.52im.net/thread-578-1-1.html

http://www.52im.net/thread-568-1-1.html

https://blog.csdn.net/liukuan73/article/details/78883847

https://blog.csdn.net/iiiiher/article/details/76696033

https://blog.csdn.net/sk1137/article/details/64798152

https://blog.csdn.net/chenhaifeng2016/article/details/78710702

https://www.baidu.com/s?wd=netty%20dpdk&pn=0&oq=netty%20dpdk&ie=utf-8&rsv_idx=1&rsv_pq=d13bc2c70001aed6&rsv_t=7e7csBPrU%2FwLr%2BfaEWXwVkuah9sACzGwRoKQ21V19vUK9J%2Fx2p2O1eX%2FiNE

【網絡】高性能網絡編程--下一個10年,是時候考慮C10M並發問題了