C10K問題
在傳統的同步阻塞處理模型中,當創建的進程或線程過多時,緩存I/O、內核將數據拷貝到用戶進程空間、阻塞,進程/線程上下文切換消耗大,簡而言之 ,C10K問題就是無法同時處理大量客戶端(10,000)的網絡套接字。
解決思路
- 每個連接創建一個進程或線程
- 一個進程或線程同時處理多個連接
多線程處理多連接
申請和管理多線程需要佔用額外資源,擴展性差,如tomcat。
單線程處理多連接
select方式:使用fd_set結構體告訴內核同時監控那些文件句柄,使用逐個排查方式去檢查是否有文件句柄就緒或者超時。該方式有以下缺點:文件句柄數量是有上線的,逐個檢查吞吐量低,每次調用都要重複初始化fd_set。
poll方式:該方式主要解決了select方式的2個缺點,文件句柄上限問題(鏈表方式存儲)以及重複初始化問題(不同字段標註關注事件和發生事件),但是逐個去檢查文件句柄是否就緒的問題仍然沒有解決。
epoll方式:該方式可以說是C10K問題的killer,他不去輪詢監聽所有文件句柄是否已經就緒。epoll只對發生變化的文件句柄感興趣。其工作機制是,使用"事件"的就緒通知方式,通過epoll_ctl註冊文件描述符fd,一旦該fd就緒,內核就會採用類似callback的回調機制來激活該fd, epoll_wait便可以收到通知, 並通知應用程序。而且epoll使用一個文件描述符管理多個描述符,將用戶進程的文件描述符的事件存放到內核的一個事件表中, 這樣數據只需要從內核緩存空間拷貝一次到用戶進程地址空間。而且epoll是通過內核與用戶空間共享內存方式來實現事件就緒消息傳遞的,其效率非常高,但是epoll是依賴系統的(Linux)。
Nginx中支持的事件驅動模型
kqueue | rtsig | epoll | /dev/poll | select | poll | eventport
標準事件模型
Select、poll屬於標準事件模型,如果當前系統不存在更有效的方法,nginx會選擇select或poll。
高級事件模型
/dev/poll適用於 Solaris 7 11/99+, HP/UX 11.22+ (eventport), IRIX 6.5.15+ 和 Tru64 UNIX 5.1A+;
Eventport適用於 Solaris 10. 爲了防止出現內核崩潰的問題, 有必要安裝安全補丁;
Kqueue適用用於 FreeBSD 4.1+, OpenBSD 2.9+, NetBSD 2.0 和 MacOS X,使用雙處理器的MacOS X系統使用kqueue可能會造成內核崩潰;
epoll適用於於Linux內核2.6版本及以後的系統。