Jack Jiang

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

          1、前言



          對(duì)于高性能即時(shí)通訊技術(shù)(或者說(shuō)互聯(lián)網(wǎng)編程)比較關(guān)注的開(kāi)發(fā)者,對(duì)C10K問(wèn)題(即單機(jī)1萬(wàn)個(gè)并發(fā)連接問(wèn)題)應(yīng)該都有所了解。“C10K”概念最早由Dan Kegel發(fā)布于其個(gè)人站點(diǎn),即出自其經(jīng)典的《The C10K problem 英文PDF版中文譯文》一文。

          正如你所料,過(guò)去的10年里,高性能網(wǎng)絡(luò)編程技術(shù)領(lǐng)域里經(jīng)過(guò)眾多開(kāi)發(fā)者的努力,已很好地解決了C10K問(wèn)題,大家已開(kāi)始關(guān)注并著手解決下一個(gè)十年要面對(duì)的C10M問(wèn)題即單機(jī)1千萬(wàn)個(gè)并發(fā)連接問(wèn)題,C10M相關(guān)技術(shù)討論和學(xué)習(xí)將在本系列文章的下篇中開(kāi)始展開(kāi),本文不作深入介紹)。

          雖然C10K問(wèn)題已被妥善解決,但對(duì)于即時(shí)通訊應(yīng)用(或其它網(wǎng)絡(luò)編程方面)的開(kāi)發(fā)者而言,研究C10K問(wèn)題仍然價(jià)值巨大,因?yàn)榧夹g(shù)的發(fā)展都是有規(guī)律和線索可循的,了解C10K問(wèn)題及其解決思路,通過(guò)舉一反三,或許可以為你以后面對(duì)類似問(wèn)題提供更多可借鑒的思想和解決問(wèn)題的實(shí)踐思路。而這,也正是撰寫本文的目的所在。

          2、學(xué)習(xí)交流 

          - 即時(shí)通訊開(kāi)發(fā)交流群: 215891622 [推薦]

          - 移動(dòng)端IM開(kāi)發(fā)推薦文章:《新手入門一篇就夠:從零開(kāi)發(fā)移動(dòng)端IM

          3、C10K問(wèn)題系列文章

          本文是C10K問(wèn)題系列文章中的第2篇,總目錄如下:

          4、C10K問(wèn)題的提出者


          Dan Kegel:軟件工程師

          目前工作在美國(guó)的洛杉磯,當(dāng)前受雇于Google公司。從1978年起開(kāi)始接觸計(jì)算機(jī)編程,是Winetricks的作者、也是Wine 1.0的管理員,同時(shí)也是Crosstool( 一個(gè)讓 gcc/glibc 編譯器更易用的工具套件)的作者。發(fā)表了著名的《The C10K problem》技術(shù)文章,是Java JSR-51規(guī)范的提交者并參與編寫了Java平臺(tái)的NIO和文件鎖,同時(shí)參與了RFC 5128標(biāo)準(zhǔn)中有關(guān)NAT 穿越(P2P打洞)技術(shù)的描述和定義。

          5、C10K問(wèn)題的由來(lái)

          大家都知道互聯(lián)網(wǎng)的基礎(chǔ)就是網(wǎng)絡(luò)通信,早期的互聯(lián)網(wǎng)可以說(shuō)是一個(gè)小群體的集合。互聯(lián)網(wǎng)還不夠普及,用戶也不多,一臺(tái)服務(wù)器同時(shí)在線100個(gè)用戶估計(jì)在當(dāng)時(shí)已經(jīng)算是大型應(yīng)用了,所以并不存在什么 C10K 的難題。互聯(lián)網(wǎng)的爆發(fā)期應(yīng)該是在www網(wǎng)站,瀏覽器,雅虎出現(xiàn)后。最早的互聯(lián)網(wǎng)稱之為Web1.0,互聯(lián)網(wǎng)大部分的使用場(chǎng)景是下載一個(gè)HTML頁(yè)面,用戶在瀏覽器中查看網(wǎng)頁(yè)上的信息,這個(gè)時(shí)期也不存在C10K問(wèn)題。

          Web2.0時(shí)代到來(lái)后就不同了,一方面是普及率大大提高了,用戶群體幾何倍增長(zhǎng)。另一方面是互聯(lián)網(wǎng)不再是單純的瀏覽萬(wàn)維網(wǎng)網(wǎng)頁(yè),逐漸開(kāi)始進(jìn)行交互,而且應(yīng)用程序的邏輯也變的更復(fù)雜,從簡(jiǎn)單的表單提交,到即時(shí)通信和在線實(shí)時(shí)互動(dòng),C10K的問(wèn)題才體現(xiàn)出來(lái)了。因?yàn)槊恳粋€(gè)用戶都必須與服務(wù)器保持TCP連接才能進(jìn)行實(shí)時(shí)的數(shù)據(jù)交互,諸如Facebook這樣的網(wǎng)站同一時(shí)間的并發(fā)TCP連接很可能已經(jīng)過(guò)億。

          早期的騰訊QQ也同樣面臨C10K問(wèn)題,只不過(guò)他們是用了UDP這種原始的包交換協(xié)議來(lái)實(shí)現(xiàn)的,繞開(kāi)了這個(gè)難題,當(dāng)然過(guò)程肯定是痛苦的。如果當(dāng)時(shí)有epoll技術(shù),他們肯定會(huì)用TCP。眾所周之,后來(lái)的手機(jī)QQ、微信都采用TCP協(xié)議。

          實(shí)際上當(dāng)時(shí)也有異步模式,如:select/poll模型,這些技術(shù)都有一定的缺點(diǎn):如selelct最大不能超過(guò)1024、poll沒(méi)有限制,但每次收到數(shù)據(jù)需要遍歷每一個(gè)連接查看哪個(gè)連接有數(shù)據(jù)請(qǐng)求。


          這時(shí)候問(wèn)題就來(lái)了,最初的服務(wù)器都是基于進(jìn)程/線程模型的,新到來(lái)一個(gè)TCP連接,就需要分配1個(gè)進(jìn)程(或者線程)。而進(jìn)程又是操作系統(tǒng)最昂貴的資源,一臺(tái)機(jī)器無(wú)法創(chuàng)建很多進(jìn)程。如果是C10K就要?jiǎng)?chuàng)建1萬(wàn)個(gè)進(jìn)程,那么單機(jī)而言操作系統(tǒng)是無(wú)法承受的(往往出現(xiàn)效率低下甚至完全癱瘓)。如果是采用分布式系統(tǒng),維持1億用戶在線需要10萬(wàn)臺(tái)服務(wù)器,成本巨大,也只有Facebook、Google、雅虎等巨頭才有財(cái)力購(gòu)買如此多的服務(wù)器。

          基于上述考慮,如何突破單機(jī)性能局限,是高性能網(wǎng)絡(luò)編程所必須要直面的問(wèn)題。這些局限和問(wèn)題最早被Dan Kegel 進(jìn)行了歸納和總結(jié),并首次成系統(tǒng)地分析和提出解決方案,后來(lái)這種普遍的網(wǎng)絡(luò)現(xiàn)象和技術(shù)局限都被大家稱為 C10K 問(wèn)題。

          6、技術(shù)解讀C10K問(wèn)題

          C10K 問(wèn)題的最大特點(diǎn)是:設(shè)計(jì)不夠良好的程序,其性能和連接數(shù)及機(jī)器性能的關(guān)系往往是非線性的。

          舉個(gè)例子:如果沒(méi)有考慮過(guò) C10K 問(wèn)題,一個(gè)經(jīng)典的基于 select 的程序能在舊服務(wù)器上很好處理 1000 并發(fā)的吞吐量,它在 2 倍性能新服務(wù)器上往往處理不了并發(fā) 2000 的吞吐量。這是因?yàn)樵诓呗圆划?dāng)時(shí),大量操作的消耗和當(dāng)前連接數(shù) n 成線性相關(guān)。會(huì)導(dǎo)致單個(gè)任務(wù)的資源消耗和當(dāng)前連接數(shù)的關(guān)系會(huì)是 O(n)。而服務(wù)程序需要同時(shí)對(duì)數(shù)以萬(wàn)計(jì)的socket 進(jìn)行 I/O 處理,積累下來(lái)的資源消耗會(huì)相當(dāng)可觀,這顯然會(huì)導(dǎo)致系統(tǒng)吞吐量不能和機(jī)器性能匹配。

          以上這就是典型的C10K問(wèn)題在技術(shù)層面的表現(xiàn)。這也是為何同樣的功能,大多數(shù)開(kāi)發(fā)人員都能很容易地從功能上實(shí)現(xiàn),但一旦放到大并發(fā)場(chǎng)景下,初級(jí)與高級(jí)開(kāi)發(fā)者對(duì)同一個(gè)功能的技術(shù)實(shí)現(xiàn)所體現(xiàn)出的實(shí)際應(yīng)用效果,則是截然不同的。

          所以說(shuō),一些沒(méi)有太多大并發(fā)實(shí)踐經(jīng)驗(yàn)的技術(shù)同行,所實(shí)現(xiàn)的諸如即時(shí)通訊應(yīng)用在內(nèi)的網(wǎng)絡(luò)應(yīng)用,所謂的理論負(fù)載動(dòng)不動(dòng)就宣稱能支持單機(jī)上萬(wàn)、上十萬(wàn)甚至上百萬(wàn)的情況,是經(jīng)不起檢驗(yàn)和考驗(yàn)的

          7、C10K問(wèn)題的本質(zhì)

          C10K問(wèn)題本質(zhì)上是操作系統(tǒng)的問(wèn)題。對(duì)于Web1.0/2.0時(shí)代的操作系統(tǒng)而言, 傳統(tǒng)的同步阻塞I/O模型都是一樣的,處理的方式都是requests per second,并發(fā)10K和100的區(qū)別關(guān)鍵在于CPU。

          創(chuàng)建的進(jìn)程線程多了,數(shù)據(jù)拷貝頻繁(緩存I/O、內(nèi)核將數(shù)據(jù)拷貝到用戶進(jìn)程空間、阻塞), 進(jìn)程/線程上下文切換消耗大, 導(dǎo)致操作系統(tǒng)崩潰,這就是C10K問(wèn)題的本質(zhì)!

          可見(jiàn),解決C10K問(wèn)題的關(guān)鍵就是盡可能減少這些CPU等核心計(jì)算資源消耗,從而榨干單臺(tái)服務(wù)器的性能,突破C10K問(wèn)題所描述的瓶頸。

          8、C10K問(wèn)題的解決方案探討

          要解決這一問(wèn)題,從純網(wǎng)絡(luò)編程技術(shù)角度看,主要思路有兩個(gè):

          • 一個(gè)是對(duì)于每個(gè)連接處理分配一個(gè)獨(dú)立的進(jìn)程/線程;
          • 另一個(gè)思路是用同一進(jìn)程/線程來(lái)同時(shí)處理若干連接。

          8.1 思路一:每個(gè)進(jìn)程/線程處理一個(gè)連接

          這一思路最為直接。但是由于申請(qǐng)進(jìn)程/線程會(huì)占用相當(dāng)可觀的系統(tǒng)資源,同時(shí)對(duì)于多進(jìn)程/線程的管理會(huì)對(duì)系統(tǒng)造成壓力,因此這種方案不具備良好的可擴(kuò)展性。

          因此,這一思路在服務(wù)器資源還沒(méi)有富裕到足夠程度的時(shí)候,是不可行的。即便資源足夠富裕,效率也不夠高。總之,此思路技術(shù)實(shí)現(xiàn)會(huì)使得資源占用過(guò)多,可擴(kuò)展性差

          8.2 思路二:每個(gè)進(jìn)程/線程同時(shí)處理多個(gè)連接(IO多路復(fù)用)

          IO多路復(fù)用從技術(shù)實(shí)現(xiàn)上又分很多種,我們逐一來(lái)看看下述各種實(shí)現(xiàn)方式的優(yōu)劣。

          ● 實(shí)現(xiàn)方式1:傳統(tǒng)思路最簡(jiǎn)單的方法是循環(huán)挨個(gè)處理各個(gè)連接,每個(gè)連接對(duì)應(yīng)一個(gè) socket,當(dāng)所有 socket 都有數(shù)據(jù)的時(shí)候,這種方法是可行的。但是當(dāng)應(yīng)用讀取某個(gè) socket 的文件數(shù)據(jù)不 ready 的時(shí)候,整個(gè)應(yīng)用會(huì)阻塞在這里等待該文件句柄,即使別的文件句柄 ready,也無(wú)法往下處理。

          實(shí)現(xiàn)小結(jié):直接循環(huán)處理多個(gè)連接。
          問(wèn)題歸納:任一文件句柄的不成功會(huì)阻塞住整個(gè)應(yīng)用。


          ● 實(shí)現(xiàn)方式2:select要解決上面阻塞的問(wèn)題,思路很簡(jiǎn)單,如果我在讀取文件句柄之前,先查下它的狀態(tài),ready 了就進(jìn)行處理,不 ready 就不進(jìn)行處理,這不就解決了這個(gè)問(wèn)題了嘛?于是有了 select 方案。用一個(gè) fd_set 結(jié)構(gòu)體來(lái)告訴內(nèi)核同時(shí)監(jiān)控多個(gè)文件句柄,當(dāng)其中有文件句柄的狀態(tài)發(fā)生指定變化(例如某句柄由不可用變?yōu)榭捎茫┗虺瑫r(shí),則調(diào)用返回。之后應(yīng)用可以使用 FD_ISSET 來(lái)逐個(gè)查看是哪個(gè)文件句柄的狀態(tài)發(fā)生了變化。這樣做,小規(guī)模的連接問(wèn)題不大,但當(dāng)連接數(shù)很多(文件句柄個(gè)數(shù)很多)的時(shí)候,逐個(gè)檢查狀態(tài)就很慢了。因此,select 往往存在管理的句柄上限(FD_SETSIZE)。同時(shí),在使用上,因?yàn)橹挥幸粋€(gè)字段記錄關(guān)注和發(fā)生事件,每次調(diào)用之前要重新初始化 fd_set 結(jié)構(gòu)體。

          1
          intselect(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);

          實(shí)現(xiàn)小結(jié):有連接請(qǐng)求抵達(dá)了再檢查處理。
          問(wèn)題歸納:句柄上限+重復(fù)初始化+逐個(gè)排查所有文件句柄狀態(tài)效率不高。


          ● 實(shí)現(xiàn)方式3:poll 主要解決 select 的前兩個(gè)問(wèn)題:通過(guò)一個(gè) pollfd 數(shù)組向內(nèi)核傳遞需要關(guān)注的事件消除文件句柄上限,同時(shí)使用不同字段分別標(biāo)注關(guān)注事件和發(fā)生事件,來(lái)避免重復(fù)初始化。

          實(shí)現(xiàn)小結(jié):設(shè)計(jì)新的數(shù)據(jù)結(jié)構(gòu)提供使用效率。
          問(wèn)題歸納:逐個(gè)排查所有文件句柄狀態(tài)效率不高。


          ● 實(shí)現(xiàn)方式4:epoll既然逐個(gè)排查所有文件句柄狀態(tài)效率不高,很自然的,如果調(diào)用返回的時(shí)候只給應(yīng)用提供發(fā)生了狀態(tài)變化(很可能是數(shù)據(jù) ready)的文件句柄,進(jìn)行排查的效率不就高多了么。epoll 采用了這種設(shè)計(jì),適用于大規(guī)模的應(yīng)用場(chǎng)景。實(shí)驗(yàn)表明,當(dāng)文件句柄數(shù)目超過(guò) 10 之后,epoll 性能將優(yōu)于 select 和 poll;當(dāng)文件句柄數(shù)目達(dá)到 10K 的時(shí)候,epoll 已經(jīng)超過(guò) select 和 poll 兩個(gè)數(shù)量級(jí)。

          實(shí)現(xiàn)小結(jié):只返回狀態(tài)變化的文件句柄。
          問(wèn)題歸納:依賴特定平臺(tái)(Linux)。


          因?yàn)長(zhǎng)inux是互聯(lián)網(wǎng)企業(yè)中使用率最高的操作系統(tǒng),Epoll就成為C10K killer、高并發(fā)、高性能、異步非阻塞這些技術(shù)的代名詞了。FreeBSD推出了kqueue,Linux推出了epoll,Windows推出了IOCP,Solaris推出了/dev/poll。這些操作系統(tǒng)提供的功能就是為了解決C10K問(wèn)題。epoll技術(shù)的編程模型就是異步非阻塞回調(diào),也可以叫做Reactor,事件驅(qū)動(dòng),事件輪循(EventLoop)。Nginx,libevent,node.js這些就是Epoll時(shí)代的產(chǎn)物。

          ● 實(shí)現(xiàn)方式5:由于epoll, kqueue, IOCP每個(gè)接口都有自己的特點(diǎn),程序移植非常困難,于是需要對(duì)這些接口進(jìn)行封裝,以讓它們易于使用和移植,其中l(wèi)ibevent庫(kù)就是其中之一。跨平臺(tái),封裝底層平臺(tái)的調(diào)用,提供統(tǒng)一的 API,但底層在不同平臺(tái)上自動(dòng)選擇合適的調(diào)用。按照l(shuí)ibevent的官方網(wǎng)站,libevent庫(kù)提供了以下功能:當(dāng)一個(gè)文件描述符的特定事件(如可讀,可寫或出錯(cuò))發(fā)生了,或一個(gè)定時(shí)事件發(fā)生了,libevent就會(huì)自動(dòng)執(zhí)行用戶指定的回調(diào)函數(shù),來(lái)處理事件。目前,libevent已支持以下接口/dev/poll, kqueue, event ports, select, poll 和 epoll。Libevent的內(nèi)部事件機(jī)制完全是基于所使用的接口的。因此libevent非常容易移植,也使它的擴(kuò)展性非常容易。目前,libevent已在以下操作系統(tǒng)中編譯通過(guò):Linux,BSD,Mac OS X,Solaris和Windows。使用libevent庫(kù)進(jìn)行開(kāi)發(fā)非常簡(jiǎn)單,也很容易在各種unix平臺(tái)上移植。一個(gè)簡(jiǎn)單的使用libevent庫(kù)的程序如下:

           

          9、參考資料

          [1] 為什么QQ用的是UDP協(xié)議而不是TCP協(xié)議?
          [2] 移動(dòng)端IM/推送系統(tǒng)的協(xié)議選型:UDP還是TCP?
          [3] 高性能網(wǎng)絡(luò)編程經(jīng)典:《The C10K problem(英文)》[附件下載]
          [4] 高性能網(wǎng)絡(luò)編程(一):?jiǎn)闻_(tái)服務(wù)器并發(fā)TCP連接數(shù)到底可以有多少
          [5] 《The C10K problem (英文在線閱讀英文PDF版下載中文譯文)》
          [6]  搜狗實(shí)驗(yàn)室技術(shù)交流文檔《C10K問(wèn)題探討》(52im.net).pdf (350.83 KB) 
          [7] [通俗易懂]深入理解TCP協(xié)議(上):理論基礎(chǔ)
          [8] [通俗易懂]深入理解TCP協(xié)議(下):RTT、滑動(dòng)窗口、擁塞處理
          [9] 《TCP/IP詳解 卷1:協(xié)議 (在線閱讀版)

          10、更多資料

          TCP/IP詳解 - 第11章·UDP:用戶數(shù)據(jù)報(bào)協(xié)議
          TCP/IP詳解 - 第17章·TCP:傳輸控制協(xié)議
          TCP/IP詳解 - 第18章·TCP連接的建立與終止
          TCP/IP詳解 - 第21章·TCP的超時(shí)與重傳
          技術(shù)往事:改變世界的TCP/IP協(xié)議(珍貴多圖、手機(jī)慎點(diǎn))
          通俗易懂-深入理解TCP協(xié)議(上):理論基礎(chǔ)
          通俗易懂-深入理解TCP協(xié)議(下):RTT、滑動(dòng)窗口、擁塞處理
          理論經(jīng)典:TCP協(xié)議的3次握手與4次揮手過(guò)程詳解
          理論聯(lián)系實(shí)際:Wireshark抓包分析TCP 3次握手、4次揮手過(guò)程
          計(jì)算機(jī)網(wǎng)絡(luò)通訊協(xié)議關(guān)系圖(中文珍藏版)
          UDP中一個(gè)包的大小最大能多大?
          Java新一代網(wǎng)絡(luò)編程模型AIO原理及Linux系統(tǒng)AIO介紹
          NIO框架入門(一):服務(wù)端基于Netty4的UDP雙向通信Demo演示
          NIO框架入門(二):服務(wù)端基于MINA2的UDP雙向通信Demo演示
          NIO框架入門(三):iOS與MINA2、Netty4的跨平臺(tái)UDP雙向通信實(shí)戰(zhàn)
          NIO框架入門(四):Android與MINA2、Netty4的跨平臺(tái)UDP雙向通信實(shí)戰(zhàn)
          P2P技術(shù)詳解(一):NAT詳解——詳細(xì)原理、P2P簡(jiǎn)介
          P2P技術(shù)詳解(二):P2P中的NAT穿越(打洞)方案詳解
          P2P技術(shù)詳解(三):P2P技術(shù)之STUN、TURN、ICE詳解
          高性能網(wǎng)絡(luò)編程(一):?jiǎn)闻_(tái)服務(wù)器并發(fā)TCP連接數(shù)到底可以有多少
          高性能網(wǎng)絡(luò)編程(二):上一個(gè)10年,著名的C10K并發(fā)連接問(wèn)題
          高性能網(wǎng)絡(luò)編程(三):下一個(gè)10年,是時(shí)候考慮C10M并發(fā)問(wèn)題了
          >> 更多同類文章 ……

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

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



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


          只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。


          網(wǎng)站導(dǎo)航:
           
          Jack Jiang的 Mail: jb2011@163.com, 聯(lián)系QQ: 413980957, 微信: hellojackjiang
          主站蜘蛛池模板: 诸暨市| 金坛市| 郓城县| 岫岩| 洱源县| 西平县| 东乡族自治县| 中西区| 蓬莱市| 平和县| 黄石市| 上饶市| 兴山县| 峨眉山市| 织金县| 绿春县| 汉寿县| 临泽县| 盐亭县| 宣城市| 安平县| 宕昌县| 灵山县| 泰顺县| 蒙自县| 长岛县| 萨嘎县| 望江县| 西充县| 出国| 苍山县| 阳西县| 高平市| 三明市| 涪陵区| 沙湾县| 怀远县| 嘉定区| 义乌市| 临安市| 营口市|