
千萬級并發(fā)實現(xiàn)的秘密:內(nèi)核不是解決方案,而是問題所在!
既然我們已經(jīng)解決了 C10K并發(fā)連接問題,應(yīng)該如何提高水平支持千萬級并發(fā)連接?你可能會說不可能。不,現(xiàn)在系統(tǒng)已經(jīng)在用你可能不熟悉甚至激進的方式支持千萬級別的并發(fā)連接。
要知道它是如何做到的,我們首先要了解Errata Security的CEO Errata Security,以及他在Shmoocon 2013大會上的無稽之談 C10M Defending The Internet At Scale。
Robert用一種我以前從未聽說的方式來很巧妙地解釋了這個問題。他首先介紹了一點有關(guān)Unix的歷史,Unix的設(shè)計初衷并不是一般的服務(wù)器操作系統(tǒng),而是電話網(wǎng)絡(luò)的控制系統(tǒng)。由于是實際傳送數(shù)據(jù)的電話網(wǎng)絡(luò),所以在控制層和數(shù)據(jù)層之間有明確的界限。問題是我們現(xiàn)在根本不應(yīng)該使用Unix服務(wù)器作為數(shù)據(jù)層的一部分。正如設(shè)計只運行一個應(yīng)用程序的服務(wù)器內(nèi)核,肯定和設(shè)計多用戶的服務(wù)器內(nèi)核是不同的。
也就是他所說的關(guān)鍵要理解內(nèi)核不是解決辦法,內(nèi)核是問題所在。
這意味著:
不要讓內(nèi)核執(zhí)行所有繁重的任務(wù)。將數(shù)據(jù)包處理,內(nèi)存管理,處理器調(diào)度等任務(wù)從內(nèi)核轉(zhuǎn)移到應(yīng)用程序高效地完成。讓Linux只處理控制層,數(shù)據(jù)層完全交給應(yīng)用程序來處理。
最終就是要設(shè)計這樣一個系統(tǒng),該系統(tǒng)可以處理千萬級別的并發(fā)連接,它在200個時鐘周期內(nèi)處理數(shù)據(jù)包,在14萬個時鐘周期內(nèi)處理應(yīng)用程序邏輯。由于一次主存儲器訪問就要花費300個時鐘周期,所以這是最大限度的減少代碼和緩存丟失的關(guān)鍵。
面向數(shù)據(jù)層的系統(tǒng)可以每秒處理1千萬個數(shù)據(jù)包,面向控制層的系統(tǒng),每秒只能處理1百萬個數(shù)據(jù)包。
這似乎很極端,請記住一句老話:可擴展性是專業(yè)化的。為了做好一些事情,你不能把性能問題外包給操作系統(tǒng)來解決,你必須自己做。
現(xiàn)在,讓我們學(xué)習(xí)Robert如何創(chuàng)建一個能夠處理千萬級別并發(fā)連接的系統(tǒng)。
C10K問題最近十年
十年前,工程師處理C10K可擴展性問題時,盡量避免服務(wù)器處理超過1萬個的并發(fā)連接。通過改進操作系統(tǒng)內(nèi)核以及用事件驅(qū)動服務(wù)器(如Nginx和Node)代替線程服務(wù)器(Apache),這個問題已經(jīng)被解決。人們用十年的時間從Apache轉(zhuǎn)移到可擴展服務(wù)器,在近幾年,可擴展服務(wù)器的采用率增長得更快了。
Apache的問題
Apache的問題在于服務(wù)器的性能會隨著連接數(shù)的增多而變差
關(guān)鍵點:性能和可擴展性并不是一回事。當(dāng)人們談?wù)撘?guī)模時,他們往往是在談?wù)撔阅?,但是?guī)模和性能是不同的,比如Apache。
持續(xù)幾秒的短期連接,比如快速事務(wù),如果每秒處理1000個事務(wù),只有約1000個并發(fā)連接到服務(wù)器。
事務(wù)延長到10秒,要維持每秒1000個事務(wù),必須打開1萬個并發(fā)連接。這種情況下:盡管你不顧DoS攻擊,Apache也會性能陡降;同時大量的下載操作也會使Apache崩潰。
如果每秒處理的連接從5千增加到1萬,你會怎么做?比方說,你升級硬件并且提高處理器速度到原來的2倍。發(fā)生了什么?你得到兩倍的性能,但你沒有得到兩倍的處理規(guī)模。每秒處理的連接可能只達到了6000。你繼續(xù)提高速度,情況也沒有改善。甚至16倍的性能時,仍然不能處理1萬個并發(fā)連接。所以說性能和可擴展性是不一樣的。
問題在于Apache會創(chuàng)建一個CGI進程,然后關(guān)閉,這個步驟并沒有擴展。
為什么呢?內(nèi)核使用的O(N^2)算法使服務(wù)器無法處理1萬個并發(fā)連接。
內(nèi)核中的兩個基本問題:
連接數(shù)=線程數(shù)/進程數(shù)。當(dāng)一個數(shù)據(jù)包進來,內(nèi)核會遍歷其所有進程以決定由哪個進程來處理這個數(shù)據(jù)包。
連接數(shù)=選擇數(shù)/輪詢次數(shù)(單線程)。同樣的可擴展性問題,每個包都要走一遭列表上所有的socket。
解決方法:改進內(nèi)核使其在常數(shù)時間內(nèi)查找。
使線程切換時間與線程數(shù)量無關(guān)。
使用一個新的可擴展epoll()/IOCompletionPort常數(shù)時間去做socket查詢。
因為線程調(diào)度并沒有得到擴展,所以服務(wù)器大規(guī)模對socket使用epoll方法,這樣就導(dǎo)致需要使用異步編程模式,而這些編程模式正是Nginx和Node類型服務(wù)器具有的;所以當(dāng)從Apache遷移到Nginx和Node類型服務(wù)器時,即使在一個配置較低的服務(wù)器上增加連接數(shù),性能也不會突降;所以在10K連接時,一臺筆記本電腦的速度甚至超過了16核的服務(wù)器。
C10M問題未來十年
不遠的將來,服務(wù)器將要處理數(shù)百萬的并發(fā)連接。IPv6協(xié)議下,每個服務(wù)器的潛在連接數(shù)都是數(shù)以百萬級的,所以處理規(guī)模需要升級。
如IDS / IPS這類應(yīng)用程序需要支持這種規(guī)模,因為它們連接到一個服務(wù)器骨干網(wǎng)。其他例子:DNS根服務(wù)器,TOR節(jié)點,互聯(lián)網(wǎng)Nmap,視頻流,銀行,Carrier NAT,VoIP PBX,負載均衡器,網(wǎng)頁緩存,防火墻,電子郵件接收,垃圾郵件過濾。
通常人們將互聯(lián)網(wǎng)規(guī)模問題歸根于應(yīng)用程序而不是服務(wù)器,因為他們賣的是硬件+軟件。你買設(shè)備,并將其應(yīng)用到你的數(shù)據(jù)中心。這些設(shè)備可能包含一塊Intel主板或網(wǎng)絡(luò)處理器以及用來加密和檢測數(shù)據(jù)包的專用芯片等。
截至2013年2月,40Gpbs,32芯,256G RAM 的X86處理器在Newegg網(wǎng)站上的報價是5000美元。該服務(wù)器可以處理1萬個以上的并發(fā)連接,如果它們不能,那是因為你選擇了錯誤的軟件,而不是底層硬件的問題。這個硬件可以很容易地擴展到1千萬個并發(fā)連接。
10M的并發(fā)連接挑戰(zhàn)意味著什么:
我們所學(xué)的是Unix而不是網(wǎng)絡(luò)編程
很多程序員通過W. Richard Stevens所著的《Unix網(wǎng)絡(luò)編程》學(xué)習(xí)網(wǎng)絡(luò)編程技術(shù)。問題是,這本書是關(guān)于Unix的,而不只是網(wǎng)絡(luò)編程。它告訴你,讓Unix做所有繁重的工作,你只需要在Unix的上層寫一個小服務(wù)器。但內(nèi)核規(guī)模不夠,解決的辦法是盡可能將業(yè)務(wù)移動到內(nèi)核之外,并且自己處理所有繁重的業(yè)務(wù)。
這方面有影響的一個例子是Apache每個連接線程的模型。這意味著線程調(diào)度程序根據(jù)將要到來的數(shù)據(jù)確定接下來調(diào)用哪一個read()函數(shù),也就是把線程調(diào)度系統(tǒng)當(dāng)作數(shù)據(jù)包調(diào)度系統(tǒng)來用。(我真的很喜歡這一點,從來沒有想過這樣的說法)。
Nginx宣稱,它不把線程調(diào)度當(dāng)作數(shù)據(jù)包調(diào)度程序,而是自己進行數(shù)據(jù)包調(diào)度。使用select找到socket,我們知道數(shù)據(jù)來了,就可以立即讀取并處理數(shù)據(jù),數(shù)據(jù)也不會堵塞。
經(jīng)驗:讓Unix處理網(wǎng)絡(luò)堆棧,但之后的業(yè)務(wù)由你來處理。
怎樣編寫規(guī)模較大的軟件?
如何改變你的軟件,使其規(guī)?;??許多只提升硬件性能去支撐項目擴展的經(jīng)驗都是錯誤的,我們需要知道性能的實際情況。
要達到到更高的水平,需要解決的問題如下:
實現(xiàn)數(shù)據(jù)包可擴展編寫自己的個性化驅(qū)動來繞過堆棧
數(shù)據(jù)包的問題是它們需經(jīng)Unix內(nèi)核的處理。網(wǎng)絡(luò)堆棧復(fù)雜緩慢,數(shù)據(jù)包最好直接到達應(yīng)用程序,而非經(jīng)過操作系統(tǒng)處理之后。
做到這一點的方法是編寫自己的驅(qū)動程序。所有驅(qū)動程序?qū)?shù)據(jù)包直接發(fā)送到應(yīng)用程序,而不是通過堆棧。你可以找到這種驅(qū)動程序:PF_RING,NETMAP,Intel DPDK(數(shù)據(jù)層開發(fā)套件)。Intel不是開源的,但有很多相關(guān)的技術(shù)支持。
速度有多快?Intel的基準是在一個相當(dāng)輕量級的服務(wù)器上,每秒處理8000萬個數(shù)據(jù)包(每個數(shù)據(jù)包200個時鐘周期)。這也是通過用戶模式。將數(shù)據(jù)包向上傳遞,使用用戶模式,處理完畢后再返回。Linux每秒處理的數(shù)據(jù)包個數(shù)不超過百萬個,將UDP數(shù)據(jù)包提高到用戶模式,再次出去。客戶驅(qū)動程序和Linux的性能比是80:1。
對于每秒1000萬個數(shù)據(jù)包的目標(biāo),如果200個時鐘周期被用來獲取數(shù)據(jù)包,將留下1400個時鐘周期實現(xiàn)類似DNS / IDS的功能。
通過PF_RING得到的是原始數(shù)據(jù)包,所以你必須做你的TCP堆棧。人們所做的是用戶模式棧。Intel有現(xiàn)成的可擴展TCP堆棧
多核的可擴展性
多核可擴展性不同于多線程可擴展性。我們都熟知這個理念:處理器的速度并沒有變快,我們只是靠增加數(shù)量來達到目的。
大多數(shù)的代碼都未實現(xiàn)4核以上的并行。當(dāng)我們添加更多內(nèi)核時,下降的不僅僅是性能等級,處理速度可能也會變得越來越慢,這是軟件的問題。我們希望軟件的提高速度同內(nèi)核的增加接近線性正相關(guān)。
多線程編程不同于多核編程
多線程
每個CPU內(nèi)核中不止一個線程
用鎖來協(xié)調(diào)線程(通過系統(tǒng)調(diào)用)
每個線程有不同的任務(wù)
多核
每個CPU內(nèi)核中只有一個線程
當(dāng)兩個線程/內(nèi)核訪問同一個數(shù)據(jù)時,不能停下來互相等待
同一個任務(wù)的不同線程
要解決的問題是怎樣將一個應(yīng)用程序分布到多個內(nèi)核中去
Unix中的鎖在內(nèi)核實現(xiàn)。4內(nèi)核使用鎖的情況是大多數(shù)軟件開始等待其他線程解鎖。因此,增加內(nèi)核所獲得的收益遠遠低于等待中的性能損耗。
我們需要這樣一個架構(gòu),它更像高速公路而不是紅綠燈控制的十字路口,無需等待,每個人都以自己的節(jié)奏行進,盡可能節(jié)省開銷。
解決方案:
在每個核心中保存數(shù)據(jù)結(jié)構(gòu),然后聚合的對數(shù)據(jù)進行讀取。
原子性。CPU支持可以通過C語言調(diào)用的指令,保證原子性,避免沖突發(fā)生。開銷很大,所以不要處處使用。
無鎖的數(shù)據(jù)結(jié)構(gòu)。線程無需等待即可訪問,在不同的架構(gòu)下都是復(fù)雜的工作,請不要自己做。
線程模型,即流水線與工作線程模型。這不只是同步的問題,而是你的線程如何架構(gòu)。
處理器關(guān)聯(lián)。告訴操作系統(tǒng)優(yōu)先使用前兩個內(nèi)核,然后設(shè)置線程運行在哪一個內(nèi)核上,你也可以通過中斷到達這個目的。所以,CPU由你來控制而不是Linux。
內(nèi)存的可擴展性
如果你有20G的RAM,假設(shè)每次連接占用2K的內(nèi)存,如果你還有20M的三級緩存,緩存中會沒有數(shù)據(jù)。數(shù)據(jù)轉(zhuǎn)移到主存中處理花費300個時鐘周期,此時CPU沒有做任何事情。
每個數(shù)據(jù)包要有1400個時鐘周期(DNS / IDS的功能)和200個時鐘周期(獲取數(shù)據(jù)包)的開銷,每個數(shù)據(jù)包我們只有4個高速緩存缺失,這是一個問題。
聯(lián)合定位數(shù)據(jù)
不要通過指針在滿內(nèi)存亂放數(shù)據(jù)。每次你跟蹤一個指針,都會是一個高速緩存缺失:[hash pointer] -> [Task Control Block] -> [Socket] -> [App],這是四個高速緩存缺失。
保持所有的數(shù)據(jù)在一個內(nèi)存塊:[TCB |socket| APP]。給所有塊預(yù)分配內(nèi)存,將高速緩存缺失從4減少到1。
分頁
32GB的數(shù)據(jù)需占用64MB的分頁表,不適合都存儲在高速緩存。所以存在兩個高速緩存缺失分頁表和它所指向的數(shù)據(jù)。這是開發(fā)可擴展的軟件不能忽略的細節(jié)。
解決方案:壓縮數(shù)據(jù),使用有很多內(nèi)存訪問的高速緩存架構(gòu),而不是二叉搜索樹
NUMA架構(gòu)加倍了主存訪問時間。內(nèi)存可能不在本地socket,而是另一個socket上。
內(nèi)存池
啟動時立即預(yù)先分配所有的內(nèi)存
在對象,線程和socket的基礎(chǔ)上進行分配。
超線程
每個網(wǎng)絡(luò)處理器最多可以運行4個線程,英特爾只能運行2個。
在適當(dāng)?shù)那闆r下,我們還需要掩蓋延時,比如內(nèi)存訪問中一個線程在等待另一個全速的線程。
大內(nèi)存頁
減小頁表規(guī)模。從一開始就預(yù)留內(nèi)存,讓你的應(yīng)用程序管理內(nèi)存。
總結(jié)
網(wǎng)卡
問題:通過內(nèi)核工作效率不高
解決方案:使用自己的驅(qū)動程序并管理它們,使適配器遠離操作系統(tǒng)。
CPU
問題:使用傳統(tǒng)的內(nèi)核方法來協(xié)調(diào)你的應(yīng)用程序是行不通的。
解決方案:Linux管理前兩個CPU,你的應(yīng)用程序管理其余的CPU。中斷只發(fā)生在你允許的CPU上。
內(nèi)存
問題:內(nèi)存需要特別關(guān)注,以求高效。
解決方案:在系統(tǒng)啟動時就分配大部分內(nèi)存給你管理的大內(nèi)存頁
控制層交給Linux,應(yīng)用程序管理數(shù)據(jù)。應(yīng)用程序與內(nèi)核之間沒有交互,沒有線程調(diào)度,沒有系統(tǒng)調(diào)用,沒有中斷,什么都沒有。
然而,你有的是在Linux上運行的代碼,你可以正常調(diào)試,這不是某種怪異的硬件系統(tǒng),需要特定的工程師。你需要定制的硬件在數(shù)據(jù)層提升性能,但是必須是在你熟悉的編程和開發(fā)環(huán)境上進行。
數(shù)據(jù)分析咨詢請掃描二維碼
若不方便掃碼,搜微信號:CDAshujufenxi
LSTM 模型輸入長度選擇技巧:提升序列建模效能的關(guān)鍵? 在循環(huán)神經(jīng)網(wǎng)絡(luò)(RNN)家族中,長短期記憶網(wǎng)絡(luò)(LSTM)憑借其解決長序列 ...
2025-07-11CDA 數(shù)據(jù)分析師報考條件詳解與準備指南? ? 在數(shù)據(jù)驅(qū)動決策的時代浪潮下,CDA 數(shù)據(jù)分析師認證愈發(fā)受到矚目,成為眾多有志投身數(shù) ...
2025-07-11數(shù)據(jù)透視表中兩列相乘合計的實用指南? 在數(shù)據(jù)分析的日常工作中,數(shù)據(jù)透視表憑借其強大的數(shù)據(jù)匯總和分析功能,成為了 Excel 用戶 ...
2025-07-11尊敬的考生: 您好! 我們誠摯通知您,CDA Level I和 Level II考試大綱將于 2025年7月25日 實施重大更新。 此次更新旨在確保認 ...
2025-07-10BI 大數(shù)據(jù)分析師:連接數(shù)據(jù)與業(yè)務(wù)的價值轉(zhuǎn)化者? ? 在大數(shù)據(jù)與商業(yè)智能(Business Intelligence,簡稱 BI)深度融合的時代,BI ...
2025-07-10SQL 在預(yù)測分析中的應(yīng)用:從數(shù)據(jù)查詢到趨勢預(yù)判? ? 在數(shù)據(jù)驅(qū)動決策的時代,預(yù)測分析作為挖掘數(shù)據(jù)潛在價值的核心手段,正被廣泛 ...
2025-07-10數(shù)據(jù)查詢結(jié)束后:分析師的收尾工作與價值深化? ? 在數(shù)據(jù)分析的全流程中,“query end”(查詢結(jié)束)并非工作的終點,而是將數(shù) ...
2025-07-10CDA 數(shù)據(jù)分析師考試:從報考到取證的全攻略? 在數(shù)字經(jīng)濟蓬勃發(fā)展的今天,數(shù)據(jù)分析師已成為各行業(yè)爭搶的核心人才,而 CDA(Certi ...
2025-07-09【CDA干貨】單樣本趨勢性檢驗:捕捉數(shù)據(jù)背后的時間軌跡? 在數(shù)據(jù)分析的版圖中,單樣本趨勢性檢驗如同一位耐心的偵探,專注于從單 ...
2025-07-09year_month數(shù)據(jù)類型:時間維度的精準切片? ? 在數(shù)據(jù)的世界里,時間是最不可或缺的維度之一,而year_month數(shù)據(jù)類型就像一把精準 ...
2025-07-09CDA 備考干貨:Python 在數(shù)據(jù)分析中的核心應(yīng)用與實戰(zhàn)技巧? ? 在 CDA 數(shù)據(jù)分析師認證考試中,Python 作為數(shù)據(jù)處理與分析的核心 ...
2025-07-08SPSS 中的 Mann-Kendall 檢驗:數(shù)據(jù)趨勢與突變分析的有力工具? ? ? 在數(shù)據(jù)分析的廣袤領(lǐng)域中,準確捕捉數(shù)據(jù)的趨勢變化以及識別 ...
2025-07-08備戰(zhàn) CDA 數(shù)據(jù)分析師考試:需要多久?如何規(guī)劃? CDA(Certified Data Analyst)數(shù)據(jù)分析師認證作為國內(nèi)權(quán)威的數(shù)據(jù)分析能力認證 ...
2025-07-08LSTM 輸出不確定的成因、影響與應(yīng)對策略? 長短期記憶網(wǎng)絡(luò)(LSTM)作為循環(huán)神經(jīng)網(wǎng)絡(luò)(RNN)的一種變體,憑借獨特的門控機制,在 ...
2025-07-07統(tǒng)計學(xué)方法在市場調(diào)研數(shù)據(jù)中的深度應(yīng)用? 市場調(diào)研是企業(yè)洞察市場動態(tài)、了解消費者需求的重要途徑,而統(tǒng)計學(xué)方法則是市場調(diào)研數(shù) ...
2025-07-07CDA數(shù)據(jù)分析師證書考試全攻略? 在數(shù)字化浪潮席卷全球的當(dāng)下,數(shù)據(jù)已成為企業(yè)決策、行業(yè)發(fā)展的核心驅(qū)動力,數(shù)據(jù)分析師也因此成為 ...
2025-07-07剖析 CDA 數(shù)據(jù)分析師考試題型:解鎖高效備考與答題策略? CDA(Certified Data Analyst)數(shù)據(jù)分析師考試作為衡量數(shù)據(jù)專業(yè)能力的 ...
2025-07-04SQL Server 字符串截取轉(zhuǎn)日期:解鎖數(shù)據(jù)處理的關(guān)鍵技能? 在數(shù)據(jù)處理與分析工作中,數(shù)據(jù)格式的規(guī)范性是保證后續(xù)分析準確性的基礎(chǔ) ...
2025-07-04CDA 數(shù)據(jù)分析師視角:從數(shù)據(jù)迷霧中探尋商業(yè)真相? 在數(shù)字化浪潮席卷全球的今天,數(shù)據(jù)已成為企業(yè)決策的核心驅(qū)動力,CDA(Certifie ...
2025-07-04CDA 數(shù)據(jù)分析師:開啟數(shù)據(jù)職業(yè)發(fā)展新征程? ? 在數(shù)據(jù)成為核心生產(chǎn)要素的今天,數(shù)據(jù)分析師的職業(yè)價值愈發(fā)凸顯。CDA(Certified D ...
2025-07-03