99999久久久久久亚洲,欧美人与禽猛交狂配,高清日韩av在线影院,一个人在线高清免费观看,啦啦啦在线视频免费观看www

熱線電話:13121318867

登錄
首頁精彩閱讀千萬級并發(fā)實(shí)現(xiàn)的秘密:內(nèi)核不是解決方案,而是問題所在!
千萬級并發(fā)實(shí)現(xiàn)的秘密:內(nèi)核不是解決方案,而是問題所在!
2014-11-27
收藏

千萬級并發(fā)實(shí)現(xiàn)的秘密:內(nèi)核不是解決方案,而是問題所在!

既然我們已經(jīng)解決了 C10K并發(fā)連接問題,應(yīng)該如何提高水平支持千萬級并發(fā)連接?你可能會(huì)說不可能。不,現(xiàn)在系統(tǒng)已經(jīng)在用你可能不熟悉甚至激進(jìn)的方式支持千萬級別的并發(fā)連接。

要知道它是如何做到的,我們首先要了解Errata Security的CEO Errata Security,以及他在Shmoocon 2013大會(huì)上的無稽之談 C10M Defending The Internet At Scale。

Robert用一種我以前從未聽說的方式來很巧妙地解釋了這個(gè)問題。他首先介紹了一點(diǎn)有關(guān)Unix的歷史,Unix的設(shè)計(jì)初衷并不是一般的服務(wù)器操作系統(tǒng),而是電話網(wǎng)絡(luò)的控制系統(tǒng)。由于是實(shí)際傳送數(shù)據(jù)的電話網(wǎng)絡(luò),所以在控制層和數(shù)據(jù)層之間有明確的界限。問題是我們現(xiàn)在根本不應(yīng)該使用Unix服務(wù)器作為數(shù)據(jù)層的一部分。正如設(shè)計(jì)只運(yùn)行一個(gè)應(yīng)用程序的服務(wù)器內(nèi)核,肯定和設(shè)計(jì)多用戶的服務(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è)計(jì)這樣一個(gè)系統(tǒng),該系統(tǒng)可以處理千萬級別的并發(fā)連接,它在200個(gè)時(shí)鐘周期內(nèi)處理數(shù)據(jù)包,在14萬個(gè)時(shí)鐘周期內(nèi)處理應(yīng)用程序邏輯。由于一次主存儲(chǔ)器訪問就要花費(fèi)300個(gè)時(shí)鐘周期,所以這是最大限度的減少代碼和緩存丟失的關(guān)鍵。

面向數(shù)據(jù)層的系統(tǒng)可以每秒處理1千萬個(gè)數(shù)據(jù)包,面向控制層的系統(tǒng),每秒只能處理1百萬個(gè)數(shù)據(jù)包。

這似乎很極端,請記住一句老話:可擴(kuò)展性是專業(yè)化的。為了做好一些事情,你不能把性能問題外包給操作系統(tǒng)來解決,你必須自己做。
現(xiàn)在,讓我們學(xué)習(xí)Robert如何創(chuàng)建一個(gè)能夠處理千萬級別并發(fā)連接的系統(tǒng)。

C10K問題最近十年

十年前,工程師處理C10K可擴(kuò)展性問題時(shí),盡量避免服務(wù)器處理超過1萬個(gè)的并發(fā)連接。通過改進(jìn)操作系統(tǒng)內(nèi)核以及用事件驅(qū)動(dòng)服務(wù)器(如Nginx和Node)代替線程服務(wù)器(Apache),這個(gè)問題已經(jīng)被解決。人們用十年的時(shí)間從Apache轉(zhuǎn)移到可擴(kuò)展服務(wù)器,在近幾年,可擴(kuò)展服務(wù)器的采用率增長得更快了。

Apache的問題

Apache的問題在于服務(wù)器的性能會(huì)隨著連接數(shù)的增多而變差

關(guān)鍵點(diǎn):性能和可擴(kuò)展性并不是一回事。當(dāng)人們談?wù)撘?guī)模時(shí),他們往往是在談?wù)撔阅?,但是?guī)模和性能是不同的,比如Apache。

持續(xù)幾秒的短期連接,比如快速事務(wù),如果每秒處理1000個(gè)事務(wù),只有約1000個(gè)并發(fā)連接到服務(wù)器。

事務(wù)延長到10秒,要維持每秒1000個(gè)事務(wù),必須打開1萬個(gè)并發(fā)連接。這種情況下:盡管你不顧DoS攻擊,Apache也會(huì)性能陡降;同時(shí)大量的下載操作也會(huì)使Apache崩潰。

如果每秒處理的連接從5千增加到1萬,你會(huì)怎么做?比方說,你升級硬件并且提高處理器速度到原來的2倍。發(fā)生了什么?你得到兩倍的性能,但你沒有得到兩倍的處理規(guī)模。每秒處理的連接可能只達(dá)到了6000。你繼續(xù)提高速度,情況也沒有改善。甚至16倍的性能時(shí),仍然不能處理1萬個(gè)并發(fā)連接。所以說性能和可擴(kuò)展性是不一樣的。

問題在于Apache會(huì)創(chuàng)建一個(gè)CGI進(jìn)程,然后關(guān)閉,這個(gè)步驟并沒有擴(kuò)展。

為什么呢?內(nèi)核使用的O(N^2)算法使服務(wù)器無法處理1萬個(gè)并發(fā)連接。

內(nèi)核中的兩個(gè)基本問題:

連接數(shù)=線程數(shù)/進(jìn)程數(shù)。當(dāng)一個(gè)數(shù)據(jù)包進(jìn)來,內(nèi)核會(huì)遍歷其所有進(jìn)程以決定由哪個(gè)進(jìn)程來處理這個(gè)數(shù)據(jù)包。

連接數(shù)=選擇數(shù)/輪詢次數(shù)(單線程)。同樣的可擴(kuò)展性問題,每個(gè)包都要走一遭列表上所有的socket。

解決方法:改進(jìn)內(nèi)核使其在常數(shù)時(shí)間內(nèi)查找。

使線程切換時(shí)間與線程數(shù)量無關(guān)。

使用一個(gè)新的可擴(kuò)展epoll()/IOCompletionPort常數(shù)時(shí)間去做socket查詢。

因?yàn)榫€程調(diào)度并沒有得到擴(kuò)展,所以服務(wù)器大規(guī)模對socket使用epoll方法,這樣就導(dǎo)致需要使用異步編程模式,而這些編程模式正是Nginx和Node類型服務(wù)器具有的;所以當(dāng)從Apache遷移到Nginx和Node類型服務(wù)器時(shí),即使在一個(gè)配置較低的服務(wù)器上增加連接數(shù),性能也不會(huì)突降;所以在10K連接時(shí),一臺筆記本電腦的速度甚至超過了16核的服務(wù)器。

C10M問題未來十年

不遠(yuǎn)的將來,服務(wù)器將要處理數(shù)百萬的并發(fā)連接。IPv6協(xié)議下,每個(gè)服務(wù)器的潛在連接數(shù)都是數(shù)以百萬級的,所以處理規(guī)模需要升級。

如IDS / IPS這類應(yīng)用程序需要支持這種規(guī)模,因?yàn)樗鼈冞B接到一個(gè)服務(wù)器骨干網(wǎng)。其他例子:DNS根服務(wù)器,TOR節(jié)點(diǎn),互聯(lián)網(wǎng)Nmap,視頻流,銀行,Carrier NAT,VoIP PBX,負(fù)載均衡器,網(wǎng)頁緩存,防火墻,電子郵件接收,垃圾郵件過濾。

通常人們將互聯(lián)網(wǎng)規(guī)模問題歸根于應(yīng)用程序而不是服務(wù)器,因?yàn)樗麄冑u的是硬件+軟件。你買設(shè)備,并將其應(yīng)用到你的數(shù)據(jù)中心。這些設(shè)備可能包含一塊Intel主板或網(wǎng)絡(luò)處理器以及用來加密和檢測數(shù)據(jù)包的專用芯片等。

截至2013年2月,40Gpbs,32芯,256G RAM 的X86處理器在Newegg網(wǎng)站上的報(bào)價(jià)是5000美元。該服務(wù)器可以處理1萬個(gè)以上的并發(fā)連接,如果它們不能,那是因?yàn)槟氵x擇了錯(cuò)誤的軟件,而不是底層硬件的問題。這個(gè)硬件可以很容易地?cái)U(kuò)展到1千萬個(gè)并發(fā)連接。

10M的并發(fā)連接挑戰(zhàn)意味著什么:


  1. 1千萬的并發(fā)連接數(shù)
  2. 100萬個(gè)連接/秒每個(gè)連接以這個(gè)速率持續(xù)約10秒
  3. 10GB/秒的連接快速連接到互聯(lián)網(wǎng)。
  4. 1千萬個(gè)數(shù)據(jù)包/秒據(jù)估計(jì)目前的服務(wù)器每秒處理50K的數(shù)據(jù)包,以后會(huì)更多。過去服務(wù)器每秒可以處理100K的中斷,并且每一個(gè)數(shù)據(jù)包都產(chǎn)生中斷。
  5. 10微秒的延遲可擴(kuò)展服務(wù)器也許可以處理這個(gè)規(guī)模,但延遲可能會(huì)飆升。
  6. 10微秒的抖動(dòng)限制最大延遲
  7. 并發(fā)10核技術(shù)軟件應(yīng)支持更多核的服務(wù)器。通常情況下,軟件能輕松擴(kuò)展到四核。服務(wù)器可以擴(kuò)展到更多核,因此需要重寫軟件,以支持更多核的服務(wù)器。


我們所學(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的上層寫一個(gè)小服務(wù)器。但內(nèi)核規(guī)模不夠,解決的辦法是盡可能將業(yè)務(wù)移動(dòng)到內(nèi)核之外,并且自己處理所有繁重的業(yè)務(wù)。

這方面有影響的一個(gè)例子是Apache每個(gè)連接線程的模型。這意味著線程調(diào)度程序根據(jù)將要到來的數(shù)據(jù)確定接下來調(diào)用哪一個(gè)read()函數(shù),也就是把線程調(diào)度系統(tǒng)當(dāng)作數(shù)據(jù)包調(diào)度系統(tǒng)來用。(我真的很喜歡這一點(diǎn),從來沒有想過這樣的說法)。

Nginx宣稱,它不把線程調(diào)度當(dāng)作數(shù)據(jù)包調(diào)度程序,而是自己進(jìn)行數(shù)據(jù)包調(diào)度。使用select找到socket,我們知道數(shù)據(jù)來了,就可以立即讀取并處理數(shù)據(jù),數(shù)據(jù)也不會(huì)堵塞。

經(jīng)驗(yàn):讓Unix處理網(wǎng)絡(luò)堆棧,但之后的業(yè)務(wù)由你來處理。

怎樣編寫規(guī)模較大的軟件?

如何改變你的軟件,使其規(guī)?;吭S多只提升硬件性能去支撐項(xiàng)目擴(kuò)展的經(jīng)驗(yàn)都是錯(cuò)誤的,我們需要知道性能的實(shí)際情況。

要達(dá)到到更高的水平,需要解決的問題如下:


  1. 數(shù)據(jù)包的可擴(kuò)展性
  2. 多核的可擴(kuò)展性
  3. 內(nèi)存的可擴(kuò)展性


實(shí)現(xiàn)數(shù)據(jù)包可擴(kuò)展編寫自己的個(gè)性化驅(qū)動(dòng)來繞過堆棧

數(shù)據(jù)包的問題是它們需經(jīng)Unix內(nèi)核的處理。網(wǎng)絡(luò)堆棧復(fù)雜緩慢,數(shù)據(jù)包最好直接到達(dá)應(yīng)用程序,而非經(jīng)過操作系統(tǒng)處理之后。

做到這一點(diǎn)的方法是編寫自己的驅(qū)動(dòng)程序。所有驅(qū)動(dòng)程序?qū)?shù)據(jù)包直接發(fā)送到應(yīng)用程序,而不是通過堆棧。你可以找到這種驅(qū)動(dòng)程序:PF_RING,NETMAP,Intel DPDK(數(shù)據(jù)層開發(fā)套件)。Intel不是開源的,但有很多相關(guān)的技術(shù)支持。

速度有多快?Intel的基準(zhǔn)是在一個(gè)相當(dāng)輕量級的服務(wù)器上,每秒處理8000萬個(gè)數(shù)據(jù)包(每個(gè)數(shù)據(jù)包200個(gè)時(shí)鐘周期)。這也是通過用戶模式。將數(shù)據(jù)包向上傳遞,使用用戶模式,處理完畢后再返回。Linux每秒處理的數(shù)據(jù)包個(gè)數(shù)不超過百萬個(gè),將UDP數(shù)據(jù)包提高到用戶模式,再次出去??蛻趄?qū)動(dòng)程序和Linux的性能比是80:1。

對于每秒1000萬個(gè)數(shù)據(jù)包的目標(biāo),如果200個(gè)時(shí)鐘周期被用來獲取數(shù)據(jù)包,將留下1400個(gè)時(shí)鐘周期實(shí)現(xiàn)類似DNS / IDS的功能。

通過PF_RING得到的是原始數(shù)據(jù)包,所以你必須做你的TCP堆棧。人們所做的是用戶模式棧。Intel有現(xiàn)成的可擴(kuò)展TCP堆棧

多核的可擴(kuò)展性

多核可擴(kuò)展性不同于多線程可擴(kuò)展性。我們都熟知這個(gè)理念:處理器的速度并沒有變快,我們只是靠增加數(shù)量來達(dá)到目的。
大多數(shù)的代碼都未實(shí)現(xiàn)4核以上的并行。當(dāng)我們添加更多內(nèi)核時(shí),下降的不僅僅是性能等級,處理速度可能也會(huì)變得越來越慢,這是軟件的問題。我們希望軟件的提高速度同內(nèi)核的增加接近線性正相關(guān)。
多線程編程不同于多核編程

多線程

每個(gè)CPU內(nèi)核中不止一個(gè)線程

用鎖來協(xié)調(diào)線程(通過系統(tǒng)調(diào)用)

每個(gè)線程有不同的任務(wù)

多核

每個(gè)CPU內(nèi)核中只有一個(gè)線程

當(dāng)兩個(gè)線程/內(nèi)核訪問同一個(gè)數(shù)據(jù)時(shí),不能停下來互相等待

同一個(gè)任務(wù)的不同線程

要解決的問題是怎樣將一個(gè)應(yīng)用程序分布到多個(gè)內(nèi)核中去

Unix中的鎖在內(nèi)核實(shí)現(xiàn)。4內(nèi)核使用鎖的情況是大多數(shù)軟件開始等待其他線程解鎖。因此,增加內(nèi)核所獲得的收益遠(yuǎn)遠(yuǎn)低于等待中的性能損耗。

我們需要這樣一個(gè)架構(gòu),它更像高速公路而不是紅綠燈控制的十字路口,無需等待,每個(gè)人都以自己的節(jié)奏行進(jìn),盡可能節(jié)省開銷。

解決方案:

在每個(gè)核心中保存數(shù)據(jù)結(jié)構(gòu),然后聚合的對數(shù)據(jù)進(jìn)行讀取。

原子性。CPU支持可以通過C語言調(diào)用的指令,保證原子性,避免沖突發(fā)生。開銷很大,所以不要處處使用。

無鎖的數(shù)據(jù)結(jié)構(gòu)。線程無需等待即可訪問,在不同的架構(gòu)下都是復(fù)雜的工作,請不要自己做。

線程模型,即流水線與工作線程模型。這不只是同步的問題,而是你的線程如何架構(gòu)。

處理器關(guān)聯(lián)。告訴操作系統(tǒng)優(yōu)先使用前兩個(gè)內(nèi)核,然后設(shè)置線程運(yùn)行在哪一個(gè)內(nèi)核上,你也可以通過中斷到達(dá)這個(gè)目的。所以,CPU由你來控制而不是Linux

內(nèi)存的可擴(kuò)展性

如果你有20G的RAM,假設(shè)每次連接占用2K的內(nèi)存,如果你還有20M的三級緩存,緩存中會(huì)沒有數(shù)據(jù)。數(shù)據(jù)轉(zhuǎn)移到主存中處理花費(fèi)300個(gè)時(shí)鐘周期,此時(shí)CPU沒有做任何事情。

每個(gè)數(shù)據(jù)包要有1400個(gè)時(shí)鐘周期(DNS / IDS的功能)和200個(gè)時(shí)鐘周期(獲取數(shù)據(jù)包)的開銷,每個(gè)數(shù)據(jù)包我們只有4個(gè)高速緩存缺失,這是一個(gè)問題。

聯(lián)合定位數(shù)據(jù)

不要通過指針在滿內(nèi)存亂放數(shù)據(jù)。每次你跟蹤一個(gè)指針,都會(huì)是一個(gè)高速緩存缺失:[hash pointer] -> [Task Control Block] -> [Socket] -> [App],這是四個(gè)高速緩存缺失。

保持所有的數(shù)據(jù)在一個(gè)內(nèi)存塊:[TCB |socket| APP]。給所有塊預(yù)分配內(nèi)存,將高速緩存缺失從4減少到1。

分頁

32GB的數(shù)據(jù)需占用64MB的分頁表,不適合都存儲(chǔ)在高速緩存。所以存在兩個(gè)高速緩存缺失分頁表和它所指向的數(shù)據(jù)。這是開發(fā)可擴(kuò)展的軟件不能忽略的細(xì)節(jié)。

解決方案:壓縮數(shù)據(jù),使用有很多內(nèi)存訪問的高速緩存架構(gòu),而不是二叉搜索樹

NUMA架構(gòu)加倍了主存訪問時(shí)間。內(nèi)存可能不在本地socket,而是另一個(gè)socket上。

內(nèi)存池

啟動(dòng)時(shí)立即預(yù)先分配所有的內(nèi)存

在對象,線程和socket的基礎(chǔ)上進(jìn)行分配。

超線程

每個(gè)網(wǎng)絡(luò)處理器最多可以運(yùn)行4個(gè)線程,英特爾只能運(yùn)行2個(gè)。

在適當(dāng)?shù)那闆r下,我們還需要掩蓋延時(shí),比如內(nèi)存訪問中一個(gè)線程在等待另一個(gè)全速的線程。

大內(nèi)存頁

減小頁表規(guī)模。從一開始就預(yù)留內(nèi)存,讓你的應(yīng)用程序管理內(nèi)存。

總結(jié)

網(wǎng)卡

問題:通過內(nèi)核工作效率不高

解決方案:使用自己的驅(qū)動(dòng)程序并管理它們,使適配器遠(yuǎn)離操作系統(tǒng)。

CPU

問題:使用傳統(tǒng)的內(nèi)核方法來協(xié)調(diào)你的應(yīng)用程序是行不通的。

解決方案:Linux管理前兩個(gè)CPU,你的應(yīng)用程序管理其余的CPU。中斷只發(fā)生在你允許的CPU上。

內(nèi)存

問題:內(nèi)存需要特別關(guān)注,以求高效。

解決方案:在系統(tǒng)啟動(dòng)時(shí)就分配大部分內(nèi)存給你管理的大內(nèi)存頁

控制層交給Linux,應(yīng)用程序管理數(shù)據(jù)。應(yīng)用程序與內(nèi)核之間沒有交互,沒有線程調(diào)度,沒有系統(tǒng)調(diào)用,沒有中斷,什么都沒有。
然而,你有的是在Linux上運(yùn)行的代碼,你可以正常調(diào)試,這不是某種怪異的硬件系統(tǒng),需要特定的工程師。你需要定制的硬件在數(shù)據(jù)層提升性能,但是必須是在你熟悉的編程和開發(fā)環(huán)境上進(jìn)行。

數(shù)據(jù)分析咨詢請掃描二維碼

若不方便掃碼,搜微信號:CDAshujufenxi

數(shù)據(jù)分析師資訊
更多

OK
客服在線
立即咨詢
客服在線
立即咨詢
') } function initGt() { var handler = function (captchaObj) { captchaObj.appendTo('#captcha'); captchaObj.onReady(function () { $("#wait").hide(); }).onSuccess(function(){ $('.getcheckcode').removeClass('dis'); $('.getcheckcode').trigger('click'); }); window.captchaObj = captchaObj; }; $('#captcha').show(); $.ajax({ url: "/login/gtstart?t=" + (new Date()).getTime(), // 加隨機(jī)數(shù)防止緩存 type: "get", dataType: "json", success: function (data) { $('#text').hide(); $('#wait').show(); // 調(diào)用 initGeetest 進(jìn)行初始化 // 參數(shù)1:配置參數(shù) // 參數(shù)2:回調(diào),回調(diào)的第一個(gè)參數(shù)驗(yàn)證碼對象,之后可以使用它調(diào)用相應(yīng)的接口 initGeetest({ // 以下 4 個(gè)配置參數(shù)為必須,不能缺少 gt: data.gt, challenge: data.challenge, offline: !data.success, // 表示用戶后臺檢測極驗(yàn)服務(wù)器是否宕機(jī) new_captcha: data.new_captcha, // 用于宕機(jī)時(shí)表示是新驗(yàn)證碼的宕機(jī) product: "float", // 產(chǎn)品形式,包括:float,popup width: "280px", https: true // 更多配置參數(shù)說明請參見:http://docs.geetest.com/install/client/web-front/ }, handler); } }); } function codeCutdown() { if(_wait == 0){ //倒計(jì)時(shí)完成 $(".getcheckcode").removeClass('dis').html("重新獲取"); }else{ $(".getcheckcode").addClass('dis').html("重新獲取("+_wait+"s)"); _wait--; setTimeout(function () { codeCutdown(); },1000); } } function inputValidate(ele,telInput) { var oInput = ele; var inputVal = oInput.val(); var oType = ele.attr('data-type'); var oEtag = $('#etag').val(); var oErr = oInput.closest('.form_box').next('.err_txt'); var empTxt = '請輸入'+oInput.attr('placeholder')+'!'; var errTxt = '請輸入正確的'+oInput.attr('placeholder')+'!'; var pattern; if(inputVal==""){ if(!telInput){ errFun(oErr,empTxt); } return false; }else { switch (oType){ case 'login_mobile': pattern = /^1[3456789]\d{9}$/; if(inputVal.length==11) { $.ajax({ url: '/login/checkmobile', type: "post", dataType: "json", data: { mobile: inputVal, etag: oEtag, page_ur: window.location.href, page_referer: document.referrer }, success: function (data) { } }); } break; case 'login_yzm': pattern = /^\d{6}$/; break; } if(oType=='login_mobile'){ } if(!!validateFun(pattern,inputVal)){ errFun(oErr,'') if(telInput){ $('.getcheckcode').removeClass('dis'); } }else { if(!telInput) { errFun(oErr, errTxt); }else { $('.getcheckcode').addClass('dis'); } return false; } } return true; } function errFun(obj,msg) { obj.html(msg); if(msg==''){ $('.login_submit').removeClass('dis'); }else { $('.login_submit').addClass('dis'); } } function validateFun(pat,val) { return pat.test(val); }