摘要:問題任一文件句柄的不成功會(huì)阻塞住整個(gè)應(yīng)用。主要解決的前兩個(gè)問題通過一個(gè)數(shù)組向內(nèi)核傳遞需要關(guān)注的事件消除文件句柄上限,同時(shí)使用不同字段分別標(biāo)注關(guān)注事件和發(fā)生事件,來避免重復(fù)初始化。問題逐個(gè)排查所有文件句柄狀態(tài)效率不高。
C10K問題思維導(dǎo)圖 C10K問題出現(xiàn)前期
大家都知道互聯(lián)網(wǎng)的基礎(chǔ)就是網(wǎng)絡(luò)通信,早期的互聯(lián)網(wǎng)可以說是一個(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頁面,用戶在瀏覽器中查看網(wǎng)頁上的信息。這個(gè)時(shí)期也不存在C10K問題。
Web2.0時(shí)代到來后就不同了,一方面是普及率大大提高了,用戶群體幾何倍增長。另一方面是互聯(lián)網(wǎng)不再是單純的瀏覽萬維網(wǎng)網(wǎng)頁,逐漸開始進(jìn)行交互,而且應(yīng)用程序的邏輯也變的更復(fù)雜,從簡單的表單提交,到即時(shí)通信和在線實(shí)時(shí)互動(dòng)。
C10K的問題才體現(xiàn)出來了。每一個(gè)用戶都必須與服務(wù)器保持TCP連接才能進(jìn)行實(shí)時(shí)的數(shù)據(jù)交互。
Facebook這樣的網(wǎng)站同一時(shí)間的并發(fā)TCP連接可能會(huì)過億。
騰訊QQ也是有C10K問題的,只不過他們是用了UDP這種原始的包交換協(xié)議來實(shí)現(xiàn)的,繞開了這個(gè)難題。當(dāng)然過程肯定是痛苦的。如果當(dāng)時(shí)有epoll技術(shù),他們肯定會(huì)用TCP。后來的手機(jī)QQ,微信都采用TCP協(xié)議。C10K問題出現(xiàn)和本質(zhì)
這時(shí)候問題就來了,最初的服務(wù)器都是基于進(jìn)程/線程模型的,新到來一個(gè)TCP連接,就需要分配1個(gè)進(jìn)程(或者線程)。
而進(jìn)程又是操作系統(tǒng)最昂貴的資源,一臺(tái)機(jī)器無法創(chuàng)建很多進(jìn)程。
如果是C10K就要?jiǎng)?chuàng)建1萬個(gè)進(jìn)程,那么操作系統(tǒng)是無法承受的。
如果是采用分布式系統(tǒng),維持1億用戶在線需要10萬臺(tái)服務(wù)器,成本巨大,也只有Facebook,Google,雅虎才有財(cái)力購買如此多的服務(wù)器。這就是C10K問題的本質(zhì)。
實(shí)際上當(dāng)時(shí)也有異步模式,如:select/poll模型,這些技術(shù)都有一定的缺點(diǎn),如selelct最大不能超過1024,poll沒有限制,但每次收到數(shù)據(jù)需要遍歷每一個(gè)連接查看哪個(gè)連接有數(shù)據(jù)請(qǐng)求。C10K解決方案C10K解決方案
解決這一問題,主要思路有兩個(gè):
一個(gè)是對(duì)于每個(gè)連接處理分配一個(gè)獨(dú)立的進(jìn)程/線程;
另一個(gè)思路是用同一進(jìn)程/線程來同時(shí)處理若干連接。
每個(gè)進(jìn)程/線程處理一個(gè)連接這一思路最為直接。但是由于申請(qǐng)進(jìn)程/線程會(huì)占用相當(dāng)可觀的系統(tǒng)資源,同時(shí)對(duì)于多進(jìn)程/線程的管理會(huì)對(duì)系統(tǒng)造成壓力,因此這種方案不具備良好的可擴(kuò)展性。
因此,這一思路在服務(wù)器資源還沒有富裕到足夠程度的時(shí)候,是不可行的;即便資源足夠富裕,效率也不夠高。
問題:資源占用過多,可擴(kuò)展性差
每個(gè)進(jìn)程/線程同時(shí)處理多個(gè)連接(IO多路復(fù)用) 傳統(tǒng)思路最簡單的方法是循環(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,也無法往下處理。
思路:直接循環(huán)處理多個(gè)連接。select問題:任一文件句柄的不成功會(huì)阻塞住整個(gè)應(yīng)用。
要解決上面阻塞的問題,思路很簡單,如果我在讀取文件句柄之前,先查下它的狀態(tài),ready 了就進(jìn)行處理,不 ready 就不進(jìn)行處理,這不就解決了這個(gè)問題了嘛?
于是有了 select 方案。用一個(gè) fd_set 結(jié)構(gòu)體來告訴內(nèi)核同時(shí)監(jiān)控多個(gè)文件句柄,當(dāng)其中有文件句柄的狀態(tài)發(fā)生指定變化(例如某句柄由不可用變?yōu)榭捎茫┗虺瑫r(shí),則調(diào)用返回。之后應(yīng)用可以使用 FD_ISSET 來逐個(gè)查看是哪個(gè)文件句柄的狀態(tài)發(fā)生了變化。
這樣做,小規(guī)模的連接問題不大,但當(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)體。
int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
思路:有連接請(qǐng)求抵達(dá)了再檢查處理。poll問題:句柄上限+重復(fù)初始化+逐個(gè)排查所有文件句柄狀態(tài)效率不高。
poll 主要解決 select 的前兩個(gè)問題:通過一個(gè) pollfd 數(shù)組向內(nèi)核傳遞需要關(guān)注的事件消除文件句柄上限,同時(shí)使用不同字段分別標(biāo)注關(guān)注事件和發(fā)生事件,來避免重復(fù)初始化。
int poll(struct pollfd *fds, nfds_t nfds, int timeout);
思路:設(shè)計(jì)新的數(shù)據(jù)結(jié)構(gòu)提供使用效率。epoll問題:逐個(gè)排查所有文件句柄狀態(tài)效率不高。
既然逐個(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ù)目超過 10 之后,epoll 性能將優(yōu)于 select 和 poll;當(dāng)文件句柄數(shù)目達(dá)到 10K 的時(shí)候,epoll 已經(jīng)超過 select 和 poll 兩個(gè)數(shù)量級(jí)。
int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);
思路:只返回狀態(tài)變化的文件句柄。問題:依賴特定平臺(tái)(Linux)。
因?yàn)長inux是互聯(lián)網(wǎng)企業(yè)中使用率最高的操作系統(tǒng),Epoll就成為C10K killer、高并發(fā)、高性能、異步非阻塞這些技術(shù)的代名詞了。
這些操作系統(tǒng)提供的功能就是為了解決C10K問題:
FreeBSD推出了kqueue,
Linux推出了epoll
Windows推出了IOCP,
Solaris推出了/dev/poll。
這些操作系統(tǒng)提供的功能就是為了解決C10K問題。
epoll技術(shù)的編程模型就是異步非阻塞回調(diào),也可以叫做Reactor,事件驅(qū)動(dòng),事件輪循(EventLoop)。Nginx,libevent,node.js這些就是Epoll時(shí)代的產(chǎn)物。
select、poll、epoll具體原理詳解,
libevent由于epoll, kqueue, IOCP每個(gè)接口都有自己的特點(diǎn),程序移植非常困難,于是需要對(duì)這些接口進(jìn)行封裝,以讓它們易于使用和移植,其中l(wèi)ibevent庫就是其中之一。
跨平臺(tái),封裝底層平臺(tái)的調(diào)用,提供統(tǒng)一的 API,但底層在不同平臺(tái)上自動(dòng)選擇合適的調(diào)用。
按照libevent的官方網(wǎng)站,libevent庫提供了以下功能:
當(dāng)一個(gè)文件描述符的特定事件(如可讀,可寫或出錯(cuò))發(fā)生了,或一個(gè)定時(shí)事件發(fā)生了,libevent就會(huì)自動(dòng)執(zhí)行用戶指定的回調(diào)函數(shù),來處理事件。
目前,libevent已支持以下接口/dev/poll, kqueue, event ports, select, poll 和 epoll。
Libevent的內(nèi)部事件機(jī)制完全是基于所使用的接口的。因此libevent非常容易移植,也使它的擴(kuò)展性非常容易。
目前,libevent已在以下操作系統(tǒng)中編譯通過:Linux,BSD,Mac OS X,Solaris和Windows。
使用libevent庫進(jìn)行開發(fā)非常簡單,也很容易在各種unix平臺(tái)上移植。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/72525.html
摘要:對(duì)端,通過增加內(nèi)存修改最大文件描述符個(gè)數(shù)等參數(shù),單機(jī)最大并發(fā)連接數(shù)超過萬甚至上百萬是沒問題的,國外公司在產(chǎn)品環(huán)境中已做到萬并發(fā) [TOC] 前言 曾幾何時(shí)我們還在尋求網(wǎng)絡(luò)編程中C10K問題的解決方案,但是現(xiàn)在從硬件和操作系統(tǒng)支持來看單臺(tái)服務(wù)器支持上萬并發(fā)連接已經(jīng)沒有多少挑戰(zhàn)性了。 我們先假設(shè)單臺(tái)服務(wù)器最多只能支持萬級(jí)并發(fā)連接,其實(shí)對(duì)絕大多數(shù)應(yīng)用來說已經(jīng)遠(yuǎn)遠(yuǎn)足夠了,但是對(duì)于一些擁有很大用...
摘要:如需了解更多物聯(lián)網(wǎng)網(wǎng)絡(luò)編程知識(shí)請(qǐng)點(diǎn)擊物聯(lián)網(wǎng)云端開發(fā)武器庫物聯(lián)網(wǎng)高并發(fā)編程之網(wǎng)絡(luò)編程中的線程模型值得說明的是,具體選擇線程還是進(jìn)程,更多是與平臺(tái)及編程語言相關(guān)。 如需了解更多物聯(lián)網(wǎng)網(wǎng)絡(luò)編程知識(shí)請(qǐng)點(diǎn)擊:物聯(lián)網(wǎng)云端開發(fā)武器庫 物聯(lián)網(wǎng)高并發(fā)編程之網(wǎng)絡(luò)編程中的線程模型 值得說明的是,具體選擇線程還是進(jìn)程,更多是與平臺(tái)及編程語言相關(guān)。例如 C 語言使用線程和進(jìn)程都可以(例如 Nginx 使用進(jìn)程...
摘要:缺點(diǎn)每個(gè)連接需要獨(dú)立的進(jìn)程線程單獨(dú)處理,當(dāng)并發(fā)請(qǐng)求量大時(shí)為了維護(hù)程序,內(nèi)存線程切換開銷較大,這種模型在實(shí)際生產(chǎn)中很少使用。而在系統(tǒng)下,才引入,目前并不完善,因此在下實(shí)現(xiàn)高并發(fā)網(wǎng)絡(luò)編程時(shí)都是以復(fù)用模型模式為主。 思維導(dǎo)圖 showImg(https://segmentfault.com/img/bVbkrNz?w=1766&h=994); 互聯(lián)網(wǎng)服務(wù)端處理網(wǎng)絡(luò)請(qǐng)求的原理 首先看看一個(gè)典型...
摘要:一閱前熱身為了更加形象的說明同步異步阻塞非阻塞,我們以小明去買奶茶為例。等奶茶做好了,店員喊一聲小明,奶茶好了,然后小明去取奶茶。將響應(yīng)結(jié)果發(fā)給相應(yīng)的連接請(qǐng)求處理完成因?yàn)榛?,所以每個(gè)可以處理無數(shù)個(gè)連接請(qǐng)求。如此,就輕松的處理了高并發(fā)。 一、閱前熱身 為了更加形象的說明同步異步、阻塞非阻塞,我們以小明去買奶茶為例。 1、同步與異步 ①同步與異步的理解 同步與異步的重點(diǎn)在消息通知的方式上...
摘要:一閱前熱身為了更加形象的說明同步異步阻塞非阻塞,我們以小明去買奶茶為例。等奶茶做好了,店員喊一聲小明,奶茶好了,然后小明去取奶茶。將響應(yīng)結(jié)果發(fā)給相應(yīng)的連接請(qǐng)求處理完成因?yàn)榛?,所以每個(gè)可以處理無數(shù)個(gè)連接請(qǐng)求。如此,就輕松的處理了高并發(fā)。 一、閱前熱身 為了更加形象的說明同步異步、阻塞非阻塞,我們以小明去買奶茶為例。 1、同步與異步 ①同步與異步的理解 同步與異步的重點(diǎn)在消息通知的方式上...
閱讀 1937·2021-11-11 16:55
閱讀 808·2019-08-30 15:53
閱讀 3667·2019-08-30 15:45
閱讀 796·2019-08-30 14:10
閱讀 3326·2019-08-30 12:46
閱讀 2182·2019-08-29 13:15
閱讀 2083·2019-08-26 13:48
閱讀 988·2019-08-26 12:23