多路IO復用模型 select epoll

2021-07-24 18:50:08 字數 2797 閱讀 1015

我們先來介紹下nginx  nginx :

支援高併發連線.官方測試的是5w併發連線但在實際生產中可製成2-4w併發連線數,得益於nginx使用最新的epoll(linux 2.6核心)和kqueue(freebsd)網路i/o模型.而apache使用的則是傳統的select模型,其比較穩定的prefork模式為多程序模式,需要經常派生子程序,所消耗的cpu等伺服器資源要比nginx高的多.

select 和epoll效率差的原因: select是輪詢、epoll是觸發式的,所以效率高。單單這樣講,那能懂了才見鬼了.好...我們暫且客觀的記住這句話.

先說select: 

1.socket數量限制:該模式可操作的socket數由fd_setsize決定,核心預設32*32=1024. 

2.操作限制:通過遍歷fd_setsize(1024)個socket來完成排程,不管哪個socket是活躍的,都遍歷一遍. 

後說poll: 

1.socket數量幾乎無限制:該模式下的socket對應的fd列表由乙個陣列來儲存,大小不限(預設4k). 

2.操作限制:同select. 

再說:epoll: 

1.socket數量無限制:同poll 

2.操作無限制:基於核心提供的反射模式,有活躍socket時,核心訪問該socket的callback,不需要遍歷輪詢. 但是當所有socket都活躍的時候,這時候所有的callback都被喚醒,會導致資源的競爭.既然都是要處理所有的socket,那麼遍歷是最簡單最有效的實現方式.

舉例來說: 

對於im伺服器,伺服器和伺服器之間都是長鏈結,但數量不多,一般一台60\70個,比如採用ice這種架構設計,但請求相當頻繁和密集,這時候通過反射喚醒callback不一定比用select去遍歷處理更好. 

對於web portal(門戶)伺服器,都是瀏覽器客戶端發起的http短鏈結請求,數量很大,好一點的**動輒每分鐘上千個請求過來,同時伺服器端還有更多的閒置等待超時的socket,這時候沒必要把全部的socket都遍歷處理,因為那些等待超時的請求是大多數的,這樣用epoll會更好.

支援乙個程序開啟大數目的socket描述符

select 最不能忍受的是乙個程序所開啟的fd是有一定限制的,由fd_setsize設定,預設值是1024。對於那些需要支援的上萬連線數目的im伺服器來說顯然太少了。這時候你一是可以選擇修改這個巨集然後重新編譯核心,不過資料也同時指出這樣會帶來網路效率的下降,二是可以選擇多程序的解決方案(傳統的 apache方案),不過雖然linux上面建立程序的代價比較小,但仍舊是不可忽視的,加上程序間資料同步遠 比不上執行緒間同步的高效,所以也不是一種完美的方案。不過 epoll則沒有這個限制,它所支援的fd上限是最大可以開啟檔案的數目,這個數字一般遠大於2048,舉個例子,在1gb記憶體的機器上大約是10萬左右,具體數目可以cat /proc/sys/fs/file-max察看,一般來說這個數目和系統記憶體關係很大。

io效率不隨fd數目增加而線性下降

傳統的select/poll另乙個致命弱點就是當你擁有乙個很大的socket集合,不過由於網路延時, 任一時間只有部分的socket是「活躍」的,但是select/poll每次呼叫都會線性掃瞄全部的集合,導致效率呈現線性下降。但是epoll不存在這個問題,它只會對「活躍」的socket進行操作---這是因為在核心實現中epoll是根據每個fd上面的callback函式實現的。那麼,只有「活躍」的socket才會主動的去呼叫 callback函式,其他idle狀態socket則不會,在這點上,epoll實現了乙個「偽」aio,因為這時候推動力在os核心。在一些 benchmark中,如果所有的socket基本上都是活躍的---比如乙個高速lan環境,epoll並不比select/poll有什麼效率,相反,如果過多使用epoll_ctl,效率相比還有稍微的下降。但是一旦使用idle connections模擬wan環境,epoll的效率就遠在select/poll之上了。 

使用mmap加速核心與使用者空間的訊息傳遞。 

這點實際上涉及到epoll的具體實現了。無論是select,poll還是epoll都需要核心把fd訊息通知給使用者空間,如何避免不必要的記憶體拷貝就很重要,在這點上,epoll是通過核心於使用者空間mmap同一塊記憶體實現的。而如果你想我一樣從2.5核心就關注epoll的話,一定不會忘記手工 mmap這一步的。

核心微調

這一點其實不算epoll的優點了,而是整個linux平台的優點。也許你可以懷疑linux平台,但是你無法迴避linux平台賦予你微調核心的能力。比如,核心tcp/ip協議棧 使用記憶體池管理sk_buff結構,那麼可以在執行時期動態調整這個記憶體pool(skb_head_pool)的大小--- 通過echo ***x>/proc/sys/net/core/hot_list_length完成。再比如listen函式的第2個引數(tcp完成3次握手 的資料報佇列長度),也可以根據你平台記憶體大小動態調整。更甚至在乙個資料報面數目巨大但同時每個資料報本身大小卻很小的特殊系統上嘗試最新的napi網 卡驅動架構。

select模式低效的原因

select 模式低效是由select的定義所決定的,與作業系統實現無關,任何核心在實現select時必須做輪循,才能知道這些socket的情況,這是會消耗 cpu的。此外,當你擁有乙個很大socket集的時候,儘管任一時間只有小部分的socket是"活躍"的,但每次你都不得不將所有的socket填入到乙個fd_set中,這也會消耗一些cpu,並且當select返回後,處理業務時你可能還需要做「上下文對映」,同樣也會有一些效能影響,因此 select比epoll相對低效。

epoll的適用情景就是大量的socket,但是活躍多不是很高的情況。   

還有 kqueue,實際上有不少伺服器是基於 bsd 開發的

kqueue 和 epoll 類似,據說效率上稍微高一些,不過沒比較過 

IO模型 IO多路復用

用socket 一定會用到accept recv recvfrom這些方法 正常情況下 accept recv recvfrom都是阻塞的 如果setblocking false 整個程式就變成乙個非阻塞的程式了非阻塞的特點 沒有併發程式設計的機制 是乙個同步的程式 程式不會在某乙個連線的recv或...

IO模型 多路復用

乙個輸入操作通常包括兩個階段 應用程序被阻塞,直到資料從核心緩衝區複製到應用程序緩衝區中才返回。應該注意到,在阻塞的過程中,其它應用程序還可以執行,因此阻塞不意味著整個作業系統都被阻塞。因為其它應用程序還可以執行,所以不消耗 cpu 時間,這種模型的 cpu 利用率會比較高。應用程序執行系統呼叫之後...

IO模型 io多路復用(三)

兩者相互比較 1 如果只有乙個使用者連線server端,多路復用io還不如阻塞io效率高 2 相比阻塞io,多路復用io中間多了個反饋機制 3 多路復用io的 可以同時監控socket 多個socket物件coon1 coon2.recv 4 多路復用io可以識別有人連線某個coon3,然後告知有c...