http://hi.baidu.com/netpet/blog/item/2cc79216d9012b54f2de32b9.htmlhtml
前段時間將新的web模型辦到linux上來,用epoll代替了IOCP,經測試確實性能提升了不少,吞吐量也寓所提升,對於linux下面的網絡編程不是三言兩語就能說得透的了,加上多線程就更麻煩了,可是epoll模型的精髓就是事件驅動,這種模型提供了保持鏈接socket直線增漲而性能不會直線降低的特性,縱觀epoll kueuen select等等,全部都是在解決一個socket不須要一個線程的問題,將事件去分開來
在ningx(有人用他同時保持了3萬個處理鏈接)上的到了一些體會,這些不只使用於web這樣模型的server,一樣適合於全部其餘的好比遊戲、ftp服務器等。
維持高在線人數的關鍵問題在於事件處理模型須要m:n,m遠<n, m爲socket,n爲鏈接socket,無論你有多少個cpu(好比2cpu 4核),計算機能同時處理的線程數都是不多的,socket的關鍵在於網絡等IO的延遲,若是讓線程堵塞在一個網絡IO上那全部的基礎優化算法都是白搭,由於算法的不佳只能影想很短的時間,可是網絡IO延遲就很難講了,有位前輩說了很好的一句話:作多服務器網絡協做程序任什麼時候候記住減小一次路由比優化100次一個算法都划算。
nginx的作法是將處理程序嚴格區分開來(本次我做的Flower web server也是基於此原理),等待epoll等事件通知,他在全局範圍內維護了兩個鏈表,一個讀連表,一個寫鏈表,epoll等系統網絡通知通知了某個socket可操做後他便將狀態保存在相應的變量裏面,而後採起m個線程輪詢執行任務,這樣線程就不用等待網絡io堵塞,正常的一個read socket數據須要循環,直到數據讀完或者產生錯誤,但個人處理不是這樣的,我在全局範圍內維護一個統一的socket fd表,這是linux的特性決定的,由於linux的socket fd是從很小的值開始的,而且同一時間內不會重複(估計內部有線程鎖),全部fd自己就是一個重要的標識量,而且一個大的fd釋放後還會從小的開始重複利用,winsows下的就不同,他是一個長長的指針,全部個人全局狀態表就須要一個用fd做爲索引的標識就能夠了,最大的fd也就是同時保持在線人數的大致數字,我設置了一個20000的狀態表,暫用棧內存很小,基本上不會被用完。
而後我一樣對read和write設置兩個獨立的狀態鏈表,用m個線程來處理,所不一樣的是這兩個表只有一個fd項,其他的數據都是保存在堆分配的全局狀態表中,我對全局狀態表設置不少的狀態值,好比:read write readed writed needRepetRead needrepetWrite restart等等,這樣我能夠將其餘的處理分別用新的狀態鏈表來保持,鎖不一樣的是全局表的狀態不同,從而達到多個處理程序協做的問題,互斥鎖只存在於各個處理環節,若是讀的環節慢了就能夠加大讀的線程數,寫的慢了能夠加大寫的,處理的過程慢了能夠加大處理的,這樣方便系統後期調試優化,可是每個環節都不會影響全局表的處理,不會由於一個線程堵塞或則死掉致使全局的狀態都無法進行
初步做出來的模型一樣採用sendfile +epoll狀況下,經測試個人server已經略微超過nginx,下面就是進一步的規範和優化擴展的部分了linux
我也是剛剛轉到linux下面來,polled,select是早期的兩個模型,總的來講這個種都是爲了到達到事件通知功能,內部實現原理不同,因此在實際應用的過程當中就能夠作這樣的分層:事件模型和協議處理模型分開。有不少這樣的例子,nginx就是這樣的,編譯的時候根據不一樣的系統選擇不一樣的事件通知模型,也就是說你寫的程序覺大部分跟這幾個函數不要緊,他們只是起到檢測socket事件的做用,至於內部區別你能夠去看源代碼,也有網上的大量說明,不必這裏再細細羅列,目前epoll在處理大量用戶鏈接的狀況下綜合性能最好,少許鏈接(1-200個)就都差很少了,甚至pool或者select比epoll還好,這是他們實現的機制不一樣nginx
Reference:web
epoll爲何這麼快 http://www.cppblog.com/converse/archive/2008/10/12/63836.html算法