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