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