高性能即時(shí)通訊技術(shù)(或者說(shuō)互聯(lián)網(wǎng))并發(fā)連接問(wèn)題的解決思路
2021-08-20
1、前言
對(duì)于更關(guān)注高性能即時(shí)通訊技術(shù)(或互聯(lián)網(wǎng)編程)的開(kāi)發(fā)者來(lái)說(shuō),應(yīng)該都對(duì)C10K問(wèn)題(即單機(jī)并發(fā)連接問(wèn)題)有所了解。 “C10K”的概念最早由Dan在他的個(gè)人網(wǎng)站上發(fā)表,即出自他的經(jīng)典著作《The C10K(英文PDF版,中文譯本)》。
如你所料,近10年來(lái),通過(guò)高性能網(wǎng)絡(luò)編程技術(shù)領(lǐng)域眾多開(kāi)發(fā)者的努力,C10K問(wèn)題已經(jīng)得到很好的解決,大家也開(kāi)始關(guān)注并著手解決未來(lái)十年的問(wèn)題。正確的C10M問(wèn)題(即單機(jī)1000萬(wàn)并發(fā)連接問(wèn)題,C10M相關(guān)技術(shù)的討論和學(xué)習(xí)將在本系列文章的下一部分開(kāi)始,本文不再深入介紹)。
雖然C10K問(wèn)題已經(jīng)得到妥善解決,但對(duì)于即時(shí)通訊應(yīng)用(或其他網(wǎng)絡(luò)編程)的開(kāi)發(fā)者來(lái)說(shuō),研究C10K問(wèn)題還是有很大的價(jià)值的,因?yàn)榧夹g(shù)的發(fā)展是有規(guī)律的,有線(xiàn)索可循。了解C10K問(wèn)題及其解決方案,通過(guò)對(duì)他人的推論,或許能為你以后解決類(lèi)似問(wèn)題提供更多的參考思路和實(shí)踐思路。而這正是寫(xiě)這篇文章的目的。
2、學(xué)習(xí)交3、C10K系列文章
本文是C10K系列題的第二篇,大致內(nèi)容如下:
4、C10K 提問(wèn)者
丹:軟件工程師
目前在美國(guó)洛杉磯工作,目前受雇于公司。我從1978年開(kāi)始從事計(jì)算機(jī)編程。我是.0的作者,管理員,也是(一個(gè)讓gcc/編譯器更容易使用的工具套件)的作者。發(fā)表著名的《The C10K》技術(shù)文章,是Java JSR-51規(guī)范的提交者網(wǎng)絡(luò)編程技術(shù)實(shí)驗(yàn)2,參與了Java平臺(tái)的NIO和文件鎖的編譯,參與了NAT穿越(P2P打洞)技術(shù)的描述在 RFC 5128 標(biāo)準(zhǔn)和定義中。
5、C10K 問(wèn)題的根源
大家都知道,互聯(lián)網(wǎng)的基礎(chǔ)是網(wǎng)絡(luò)通信。早期的互聯(lián)網(wǎng)可以說(shuō)是小團(tuán)體的集合?;ヂ?lián)網(wǎng)不夠普及,用戶(hù)也不多。一臺(tái)服務(wù)器同時(shí)有100個(gè)用戶(hù)在線(xiàn),估計(jì)當(dāng)時(shí)是大型應(yīng)用,所以C10K是沒(méi)有問(wèn)題的?;ヂ?lián)網(wǎng)的爆發(fā)應(yīng)該是在www、瀏覽器和雅虎出現(xiàn)之后。最早的互聯(lián)網(wǎng)叫做Web1.0。互聯(lián)網(wǎng)的大部分使用場(chǎng)景是下載一個(gè)HTML頁(yè)面,用戶(hù)在瀏覽器中查看頁(yè)面上的信息。這段時(shí)間沒(méi)有C10K問(wèn)題。
Web2.0 時(shí)代不同了。一方面,滲透率大幅提升,用戶(hù)群呈指數(shù)級(jí)增長(zhǎng)。另一方面,互聯(lián)網(wǎng)不再是單純的瀏覽萬(wàn)維網(wǎng)頁(yè)面,逐漸開(kāi)始交互,應(yīng)用的邏輯也變得更加復(fù)雜。從簡(jiǎn)單的表單提交到即時(shí)通訊和在線(xiàn)實(shí)時(shí)交互,C10K的問(wèn)題都體現(xiàn)出來(lái)了。向上。由于每個(gè)用戶(hù)都必須與服務(wù)器保持TCP連接才能進(jìn)行實(shí)時(shí)數(shù)據(jù)交互,因此像這樣的網(wǎng)站同時(shí)的TCP連接數(shù)很可能超過(guò)1億。
早期的騰訊QQ也面臨C10K的問(wèn)題,不過(guò)他們使用UDP的原始包交換協(xié)議來(lái)實(shí)現(xiàn)這一點(diǎn)。這個(gè)問(wèn)題被繞過(guò)了。當(dāng)然,過(guò)程一定是痛苦的。如果當(dāng)時(shí)有技術(shù),肯定會(huì)用TCP。眾所周知,后來(lái)的手機(jī)QQ和微信都采用了TCP協(xié)議。
其實(shí)當(dāng)時(shí)有異步模式,比如:/poll模式,這些技術(shù)都有一定的缺點(diǎn):比如最大不能超過(guò)1024、poll,沒(méi)有限制,但是每次接收數(shù)據(jù),需要遍歷每個(gè)連接,查看哪個(gè)連接有數(shù)據(jù)請(qǐng)求。
這時(shí)候,問(wèn)題來(lái)了。原始服務(wù)器基于進(jìn)程/線(xiàn)程模型。對(duì)于新的 TCP 連接,需要分配一個(gè)進(jìn)程(或線(xiàn)程)。而進(jìn)程是操作系統(tǒng)最昂貴的資源,一臺(tái)機(jī)器不能創(chuàng)建多個(gè)進(jìn)程。如果 C10K 必須創(chuàng)建 10,000 個(gè)進(jìn)程,那么操作系統(tǒng)無(wú)法在單機(jī)上承擔(dān)它(通常效率低下甚至完全癱瘓)。如果采用分布式系統(tǒng),維持1億用戶(hù)在線(xiàn)需要10萬(wàn)臺(tái)服務(wù)器,成本巨大。只有像雅虎這樣的巨頭!雅虎有財(cái)力購(gòu)買(mǎi)這么多服務(wù)器。
基于以上考慮,如何突破單機(jī)性能的局限,是高性能網(wǎng)絡(luò)編程必須直接面對(duì)的問(wèn)題。這些局限和問(wèn)題首先由Dan進(jìn)行了總結(jié)總結(jié),并首次系統(tǒng)地分析并提出了解決方案。后來(lái),這種常見(jiàn)的網(wǎng)絡(luò)現(xiàn)象和技術(shù)限制被稱(chēng)為 C10K 問(wèn)題。
6、技術(shù)C10K問(wèn)題解讀
C10K 問(wèn)題的最大特點(diǎn)是,如果一個(gè)程序設(shè)計(jì)得不好,其性能與連接數(shù)和機(jī)器性能之間的關(guān)系往往是非線(xiàn)性的。
例如:如果不考慮C10K問(wèn)題,一個(gè)基于經(jīng)典的程序在舊服務(wù)器上可以很好地處理1000并發(fā)吞吐量,但在2倍性能的新服務(wù)器上往往無(wú)法處理并發(fā)2000吞吐量。 這是因?yàn)楫?dāng)策略不當(dāng)時(shí),大量操作的消耗與當(dāng)前連接數(shù)n線(xiàn)性相關(guān)。單個(gè)任務(wù)的資源消耗與當(dāng)前連接數(shù)之間的關(guān)系將為 O(n)。服務(wù)程序需要同時(shí)處理數(shù)以萬(wàn)計(jì)的I/O,累積的資源消耗會(huì)相當(dāng)可觀,這顯然會(huì)導(dǎo)致系統(tǒng)吞吐量與機(jī)器性能不匹配。
以上是典型C10K問(wèn)題的技術(shù)方面。這也是為什么大多數(shù)開(kāi)發(fā)者可以輕松實(shí)現(xiàn)相同功能的原因,但是一旦放到大并發(fā)場(chǎng)景中,初級(jí)和高級(jí)開(kāi)發(fā)者的技術(shù)實(shí)現(xiàn)相同功能的實(shí)際應(yīng)用效果就會(huì)體現(xiàn)出來(lái)。完全不一樣。
所以,一些在大并發(fā)方面沒(méi)有太多實(shí)踐經(jīng)驗(yàn)的技術(shù)同行實(shí)現(xiàn)了即時(shí)通訊應(yīng)用等網(wǎng)絡(luò)應(yīng)用。所謂的理論負(fù)載聲稱(chēng)可以支持?jǐn)?shù)萬(wàn)、數(shù)十萬(wàn)甚至數(shù)百萬(wàn)的單機(jī)。情況經(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模型是一樣的,處理方式是per。并發(fā)10K和100的區(qū)別關(guān)鍵在于CPU。
創(chuàng)建的進(jìn)程線(xiàn)程過(guò)多,數(shù)據(jù)拷貝頻繁(緩存I/O,內(nèi)核拷貝數(shù)據(jù)到用戶(hù)進(jìn)程空間,阻塞),進(jìn)程/線(xiàn)程上下文切換消耗大,導(dǎo)致操作系統(tǒng)崩潰。這就是C10K問(wèn)題的本質(zhì)!
可以看出,解決C10K問(wèn)題的關(guān)鍵是盡可能減少CPU等核心計(jì)算資源的消耗,從而擠壓?jiǎn)闻_(tái)服務(wù)器的性能,突破C10K中描述的瓶頸問(wèn)題。
8、C10K 問(wèn)題解決討論
解決這個(gè)問(wèn)題,從純網(wǎng)絡(luò)編程技術(shù)來(lái)看,主要有兩個(gè)思路:
8.1 思路一:每個(gè)進(jìn)程/線(xiàn)程處理一個(gè)連接
這個(gè)想法是最直接的。但是,由于應(yīng)用進(jìn)程/線(xiàn)程會(huì)占用相當(dāng)多的系統(tǒng)資源,并且多進(jìn)程/線(xiàn)程的管理會(huì)給系統(tǒng)帶來(lái)壓力,因此該方案沒(méi)有很好的可擴(kuò)展性。
所以這個(gè)想法在服務(wù)器資源不夠豐富的情況下是不可行的。即使資源足夠豐富,效率也不夠高??傊?,這個(gè)思路的技術(shù)實(shí)現(xiàn)會(huì)造成資源占用過(guò)多網(wǎng)絡(luò)編程技術(shù)實(shí)驗(yàn)2,擴(kuò)展性差。
8.2 思路二:每個(gè)進(jìn)程/線(xiàn)程同時(shí)處理多個(gè)連接(IO復(fù)用)
IO 多路復(fù)用可以分為很多技術(shù)實(shí)現(xiàn)。下面我們來(lái)一一看看以下實(shí)現(xiàn)的優(yōu)缺點(diǎn)。
● 實(shí)現(xiàn)方法一:傳統(tǒng)思維最簡(jiǎn)單的方法是將每個(gè)連接一個(gè)一個(gè)循環(huán)處理,每個(gè)連接對(duì)應(yīng)一個(gè)。當(dāng)他們都有數(shù)據(jù)時(shí),這種方法是可行的。但是當(dāng)應(yīng)用程序讀取某個(gè)文件數(shù)據(jù)失敗時(shí),整個(gè)應(yīng)用程序會(huì)阻塞在這里等待文件句柄,即使其他文件句柄,也無(wú)法進(jìn)一步處理。
實(shí)現(xiàn)總結(jié):直接循環(huán)處理多個(gè)連接。
問(wèn)題總結(jié):任何文件的文件句柄不成功都會(huì)阻塞整個(gè)應(yīng)用程序。
● 實(shí)現(xiàn)2:解決上述阻塞問(wèn)題,思路很簡(jiǎn)單。如果我在閱讀之前檢查文件句柄的狀態(tài),我會(huì)處理它。這個(gè)問(wèn)題解決了嗎?所以有一個(gè)計(jì)劃。使用結(jié)構(gòu)告訴內(nèi)核同時(shí)監(jiān)視多個(gè)文件句柄。當(dāng)文件句柄的狀態(tài)發(fā)生變化(例如,句柄從不可用變?yōu)榭捎茫┗虺瑫r(shí)時(shí),調(diào)用將返回。之后,應(yīng)用程序可以使用它來(lái)一一檢查哪個(gè)文件句柄狀態(tài)發(fā)生了變化。這樣,小規(guī)模的連接問(wèn)題不大,但是當(dāng)連接數(shù)大(文件句柄數(shù)大)時(shí),一一查看狀態(tài)就很慢。因此,托管句柄通常有一個(gè)上限 ()。同時(shí),在使用中,因?yàn)橹挥幸粋€(gè)字段記錄關(guān)注點(diǎn)和發(fā)生,所以每次調(diào)用前都要重新初始化結(jié)構(gòu)體。
intselect(intnfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,structtimeval *timeout);
實(shí)現(xiàn)總結(jié):如果有連接請(qǐng)求到達(dá),再次檢查處理。
問(wèn)題總結(jié):句柄上限+反復(fù)初始化+一一檢查所有文件句柄狀態(tài)效率不高。
● 實(shí)現(xiàn)方法三:poll主要解決的前兩個(gè)問(wèn)題:將需要關(guān)注的事件通過(guò)數(shù)組傳遞給內(nèi)核,消除文件句柄的上限,用不同的字段標(biāo)記感興趣的事件和發(fā)生的事件避免重復(fù)初始化。
實(shí)現(xiàn)總結(jié):設(shè)計(jì)新的數(shù)據(jù)結(jié)構(gòu),提高使用效率。
問(wèn)題總結(jié):一一查看所有文件句柄的狀態(tài)效率不高。
● 實(shí)現(xiàn) 4:由于一一檢查所有文件句柄的狀態(tài)效率不高,因此很自然地在調(diào)用返回時(shí)僅向應(yīng)用程序提供狀態(tài)更改的文件句柄(最可能的數(shù)據(jù)),并且檢查的效率是不是要高很多?這樣的設(shè)計(jì),適合大規(guī)模的應(yīng)用場(chǎng)景。實(shí)驗(yàn)表明,當(dāng)文件句柄數(shù)超過(guò)10個(gè)時(shí),性能會(huì)優(yōu)于和poll;當(dāng)文件句柄數(shù)達(dá)到10K時(shí),已經(jīng)超過(guò)和輪詢(xún)兩個(gè)數(shù)量級(jí)。
實(shí)現(xiàn)總結(jié):只返回狀態(tài)改變的文件句柄。
問(wèn)題總結(jié):依賴(lài)特定的平臺(tái)()。
因?yàn)樗腔ヂ?lián)網(wǎng)公司中使用最多的操作系統(tǒng),所以它已經(jīng)成為C10K、高并發(fā)、高性能、異步和非阻塞技術(shù)的代名詞。啟動(dòng),啟動(dòng),啟動(dòng) IOCP,啟動(dòng) /dev/poll。這些操作系統(tǒng)提供的功能旨在解決C10K問(wèn)題。該技術(shù)的編程模型是異步非阻塞回調(diào),也可以稱(chēng)為事件驅(qū)動(dòng)、事件輪詢(xún)()。 ,, Node.js 這些都是時(shí)代的產(chǎn)物。
● 實(shí)現(xiàn)5:由于,IOCP每個(gè)接口都有自己的特點(diǎn),程序移植非常困難,所以需要對(duì)這些接口進(jìn)行封裝,使其易于使用和移植,庫(kù)就是其中之一??缙脚_(tái),封裝底層平臺(tái)的調(diào)用,提供統(tǒng)一的API,但底層會(huì)自動(dòng)選擇不同平臺(tái)上合適的調(diào)用。根據(jù)官網(wǎng)介紹,該庫(kù)提供了以下功能: 當(dāng)文件描述符的特定事件(如可讀、可寫(xiě)或錯(cuò)誤)發(fā)生,或發(fā)生定時(shí)事件時(shí),會(huì)自動(dòng)執(zhí)行用戶(hù)指定的回調(diào)函數(shù)來(lái)處理事件。目前,支持以下接口 /dev/poll,,,, poll 和 。內(nèi)部事件機(jī)制完全基于所使用的接口。所以它很容易移植,也使得它的可擴(kuò)展性很容易。目前,它已在以下操作系統(tǒng)中編譯通過(guò):BSD、Mac OS X 和.使用該庫(kù)進(jìn)行開(kāi)發(fā)非常簡(jiǎn)單,易于移植到各種unix平臺(tái)。使用該庫(kù)的簡(jiǎn)單程序如下:
9、參考資料
[1] 為什么QQ用的是UDP協(xié)議而不是TCP協(xié)議?
[2]手機(jī)IM/推送系統(tǒng)的協(xié)議選擇:UDP還是TCP?
[3] 高性能網(wǎng)絡(luò)編程經(jīng)典:《The C10K(英文)》【附件下載】
[4] 高性能網(wǎng)絡(luò)編程(一):?jiǎn)闻_(tái)服務(wù)器可以有多少并發(fā)TCP連接
[5]《C10K(英文在線(xiàn)閱讀、英文PDF下載、中文翻譯)》
[6] 搜狗實(shí)驗(yàn)室技術(shù)交流文檔《C10K問(wèn)題討論》().pdf (350.83 KB)
[7]【淺顯易懂】深入理解TCP協(xié)議(上):理論基礎(chǔ)
[8] 【淺顯易懂】深入理解TCP協(xié)議(二):RTT、滑動(dòng)窗口、擁塞處理
[9]《TCP/IP詳解第一卷:協(xié)議(在線(xiàn)閱讀版)》