關於高性能server,《unix網絡編程》堪稱經典。根據說明,有如下三種相對高效的模型:
模型1(最強)
一個進程中有預先創建多個線程都阻塞在accept函數(爲了免accept驚羣,可以在accept前先thread_lock),任何一個監聽線程從accept返回得到一個socket就自己處理這個socket.
模型2
一個進程中有預先創建多個線程都阻塞在select(事件分配)函數,select有返回就調用accept。《unix網絡編程》指出select會出現驚羣,所以慢了。
模型3
預先創建多個線程,不過只有一個線程阻塞在accept即只有一個監聽線程,這個線程得到socket以後把這個socket給一個空閒線程,用條件變量通知那個空閒進程。由於進程間通信的成本,所以效率比第一種低。
然而模型1並不能充分提高吞吐率,原因是子線程的處理變成了同步IO,一旦多用戶把預先分配的多線程全佔用了,悲劇了。所以要利用事件分配機制。
關於事件分配機制(學名:反應器)
目前已知的Linux反應器有select、poll、epoll。三者可以部分替換(可以參考lighttpd和Nginx,都對反應器封裝了,還可以改運行配置來選擇不同機制)
既然同屬事件分配,神器epoll也應該有驚羣問題,果然找到相關資料(http://bbs.chinaunix.net/thread-1091745-1-1.html)
那怎麼辦?
1鴕鳥算法:就用模型2(lighttpd就是)
2加鎖:模型2,事件分配前加thread__lock
lighttpd看來效率是低了(就算用epoll)
腫麼辦?
根據http://bbs.chinaunix.net/forum.php?mod=viewthread&tid=4080488&highlight=,可以通過給子線程相同的eventpoll,而且如果升級了內核(具體2.6.多少不清楚,但linux3.0+肯定可以),內核已經避免epoll驚羣了。所以說,有以下兩條路
1升級新linux內核(又方便又可靠)。
2理論可以事件分配前加lock(lighttpd是多進程哦,鎖成本高)
(話說爲啥nginx還是比lighttpd高效,它可以用線程池,線程在內存共享方面有極大的優勢)