C10K問題2

http://blog.csdn.net/zhoudaxia/article/details/12920993php

是時候讓 Web 服務器同時處理一萬客戶端了,你不以爲嗎?畢竟,如今的 Web 是一個大地盤了。css

  而且,計算機也是同樣的大。 你能夠花 $1200 左右購買一臺 1000MHz,2Gb RAM 和一塊 1000Mbit/s 以太網卡的機器。咱們來看看——在 20000 客戶端(是 50KHz,100Kb 和 50Kb/s/客戶端)時,它不採起任何更多的馬力而是採用 4Kb 的硬盤和爲2萬客戶端中的每一個一秒一次的發送它們到網絡。(順便說一句,這是$0.08 每客戶端。 那些按 $100/客戶端 許可費來收取費用的一些操做系統開始看起來有點沉重!)。因此硬件再也不是瓶頸了。html

  1999年最繁忙的FTP網站: cdrom.com,實際上經過一個千兆的以太網管道同時地處理了 10000 客戶端。截至 2001年,一樣的速度如今由多個ISP提供,指望它變得愈來愈受大型商業客戶的歡迎。前端

  瘦客戶端計算模式顯現出回來的風格——這一時刻,在互聯網上的服務器正在爲數千計的客戶端服務。java

  考慮到這一點,這裏有幾個關於如何配置操做系統和編寫代碼以支持數千客戶端的注意事項。討論的中心是圍繞類 Unix 操做系統的。由於這是我我的感興趣的領域。但Windows也包括了一點。node

 

目錄

 

 

相關站點

 

  閱讀Nick Black寫的超級棒的 Fast UNIX Servers 文章.
  2003年十月, Felix von Leitner 作了一個超級好的網頁,展現了網絡的可擴展性,他完成了在各類不一樣的網絡系統請求和操做系統下的benchmark比較。他的一個實驗觀察結果就是linux2.6的內核確實比2.4的要好,但還有有不少不少好的圖表數據能夠引發OS開發者的深思(若有興趣能夠看看 Slashdot 的評論;是否真的有遵循Felix的實驗結果對benchm的提升進行跟蹤的)linux

提早閱讀

  若是你尚未讀過上述,那麼先出去買一本W. Richard Stevens寫的 Unix Network Programming : Networking Apis: Sockets and Xti (Volume 1)  . 這本書描述了不少編寫高性能服務器的I/O策略和誤區,甚至還講解了關於 'thundering herd' 問題。驚羣問題
  若是你讀過了,那麼請讀這本 Jeff Darcy's notes on high-performance server design.(Cal Henderson寫的,對更加傾向於使用一款web 服務器而非開發一款服務器 來構建可擴展web站點的同志,這本書更加有用.)nginx

I/O 框架

  如下所列的爲幾個包裝好的庫,它們抽象出了一些下面所表達的技術,而且能夠使你的代碼與具體操做系統隔離,從而具備更好的移植性。
  ·   ACE, 一個重量級的C++ I/O框架,用面向對象實現了一些I/O策略和其它有用的東西,特別的,它的Reactor框架是用OO方式處理非阻塞I/O,而Proactor框架是用OO方式處理異步I/O的。
  ·   ASIO 一個C++的I/O框架,正在成爲Boost庫的一部分。它像是ACE過渡到STL時代。(譯註:ACE內部有本身的容器實現,它和C++ 標準庫中的容器是不兼容的。)
  ·   libevent 由Niels Provos用C 語言編寫的一個輕量級的I/O框架。它支持kqueue和select,而且很快就能夠支持poll和epoll(翻譯此文時已經支持)。我想它應該是隻採用了水平觸發機制,該機制功過參半。Niels給出了 一張圖 來講明時間和鏈接數目在處理一個事件上的功能,從圖上能夠看出kqueue和sys_epoll明顯勝出。
  ·  我本人也嘗試過寫一個輕量級的框架(很惋惜沒有維持至今):
           o   Poller 是一個輕量級的C++ I/O框架,它使用任何一種準備就緒API(poll, select, /dev/poll, kqueue, sigio)實現水平觸發準備就緒API。以其它 不一樣的API爲基準,Poller的性能好得多。該連接文檔的下面一部分說明了如何使用這些準備就緒API。
           o   rn 是一個輕量級的C I/O框架,也是我繼Poller後的第二個框架。該框架能夠很容易的被用於商業應用中,也容易的適用於非C++應用中。它現在已經在幾個商業產品中使用。
  ·  2000年4月,Matt Welsh就構建服務器如何平衡工做線程和事件驅動技術的使用方面寫了一篇  論文,在該論文中描述了他本身的Sandstorm I/O框架。
·       Cory Nelson's Scale! library - 一個Windows下的異步套接字,文件和管道的I/O庫。

 

I/O 策略

  網絡軟件設計者每每有不少種選擇,如下列出一些:git

  • 是否處理多個I/O?如何處理在單一線程中的多個I/O調用?
    • 不處理,從頭至尾使用阻塞和同步I/O調用,能夠使用多線程或多進程來達到併發效果。
    • 使用非阻塞調用(如在一個設置O_NONBLOCK選項的socket上使用write)讀取I/O,當I/O完成時發出通知(如poll,/dev/poll)從而開始下一個I/O。這種主要使用在網絡I/O上,而不是磁盤的I/O上.
    • 使用異步調用(如aio_write())讀取I/O,當I/O完成時會發出通知(如信號或者完成端口),能夠同時使用在網絡I/O和磁盤I/O上.
  • 如何控制對每一個客戶的服務?
    • 對每一個客戶使用一個進程(經典的Unix方法,自從1980年一直使用)
    • 一個系統級的線程處理多個客戶,每一個客戶是以下一種:
      • 一種用戶級的線程(如GNU 狀態線程,經典的java綠色線程)
      • 一個狀態機 (有點深奧,但一些場景下很流行; 我喜歡)
      • 一個延續性線程 (有點深奧,但一些場景下很流行)
    • 一個系統級的線程對應一個來自客戶端的鏈接 (如經典的java中的帶native 線程)
    • 一個系統級的線程對應每個活動的客戶端鏈接(如Tomcat坐鎮而 apache 作前端的;NT完成端口; 線程池)
  • 是否使用標準的操做系統服務,仍是把一些代碼放入內核中(如自定義驅動,內核模塊,VxD)

 

  下面的五種組合應該是最經常使用的了:web

  1. 一個線程服務多個客戶端,使用非阻塞I/O和水平觸發的就緒通知
  2. 一個線程服務多個客戶端,使用非阻塞I/O和就緒改變時通知
  3. 一個服務線程服務多個客戶端,使用異步I/O
  4. 一個服務線程服務一個客戶端,使用阻塞I/O
  5. 把服務器代碼編譯進內核

1.一個線程服務多個客戶端,並使用非阻塞I/O和水平觸發的就緒通知

  ... 將全部網絡處理單元設置爲非阻塞狀態,並使用select() 或 poll()識別哪一個網絡處理單元有等待數據。這是傳統所推崇的。在這種場景,內核會告訴你一個文件描述符是否已經具有,自從上次內核告訴你這個文件描述符之後,你是否對它完成了某種事件。(名詞「水平觸發」(level triggered)來自於計算機硬件設計領域;它是'邊緣觸發' (edge triggered)的對立面。Jonathon Lemon在他的BSDCON 2000 關於kqueue()的論文 中引入了這些術語。)

 注意:特別重要的是,要記住來自內核的就緒通知只是一個提示;當你準備從文件描述符讀的時候,它可能還未準備就緒。這就是爲何當使用就緒通知的時候要使用非阻塞狀態如此重要了。

  這個方法中的一個重要瓶頸,就是read()或sendfile()對磁盤塊操做時,若是當前內存中並不存在該頁;將磁盤文件描述符設置爲非阻塞將沒有效果。一樣的問題也發生在內存映射磁盤文件中。當一個服務端第一次須要磁盤I/O時,它的進程模塊,全部的客戶端都必須等待,所以最初的非線程的性能就被消耗了。
  這也是異步I/O的目的所在,可是僅僅是在沒有AIO的系統,處理磁盤I/O的工做線程或工做進程也可能遭遇此瓶頸。一條途徑就是使用內存映射文件,若是mincore()指明I/O爲必需的話,那麼就會要求一個工做線程來完成此I/O,而後繼續處理網絡事件。Jef Poskanzer提到Pai,Druschel和Zwaenepoel的1999Flash web服務器就使用了這個方法;他們還就此在 Usenix '99上作了一個演講。看上去就好像BSD衍生出來的 Unixes如 FreeBSD和Solaris 中提供了mincore()同樣,可是它並非 單一 Unix 規範的一部分,在Linux的2.3.51 的內核中提供了該方法, 感謝Chuck Lever

  但在 2003年11月的 freebsd-hackers列表中,Vivek Pei報告了一個不錯的成果,他們對它們的Flash Web服務器在系統範圍作性能分析,而後再攻擊其瓶頸。他們找到的一個瓶頸就是mincore(猜想根本就不是什麼好方法),另一個事實就是sendfile在磁盤塊訪問時阻塞了;他們引入了一個修改後的sendfile(),當須要讀 取的磁盤頁不在內核中時,返回相似EWOULDBLOCK的值,這樣便提升了性能。(不肯定你怎樣告訴用戶頁面如今位於何處…在我看來這裏真正須要的是aio_sendfile()。) 他們優化的最終結果是SpecWeb99,在1GHZ/1GB FreeBSD沙箱上跑了約800分,這要比在spec.org存檔的任何記錄都要好。

 

  對於單線程來講有不少方法來分辨一組非阻塞socket中哪個已經準備好I/O了:

  • 傳統的select() 
    很不幸select()受FD_SETSIZE限制。這個限制已經被編譯到了標準庫和用戶程序。(有些版本的C語言庫容許在用戶應用編譯的時候提升這個值。)

    參照 Poller_select (cc,h) 作爲一個如何使用select()替代其它就緒通知場景例子。

  • 傳統的poll() 
    poll()能夠處理的文件描述符數量沒有硬編碼的限制,可是這種方式會慢幾千倍,由於大部分文件描述符老是空閒的,掃描上千個文件描述符是耗時的。
    有些操做系統(好比Solaris8)使用相似輪詢暗示(poll hinting)的辦法來加速poll(),在1999年Niels Provos實現了這種辦法而且作了基準測試

    參照 Poller_poll (cc,h,benchmarks) 作爲一個如何使用poll()替代其它就緒通知場景的例子。

  • /dev/poll
    在Solaris系統中,這是推薦的poll的替代品。
    隱藏在/dev/poll後面的想法是利用poll()常常以相同的參數調用不少次的事實。使用/dev/poll,你獲取一個對/dev/poll的打開的句柄,經過寫這個句柄就能夠一次性告訴操做系統你對哪些文件感興趣;從這之後,你只須要讀從那個句柄返回的當前準備好的文件描述符。

    這一特性悄悄出如今了Solaris7 (see patchid 106541) 可是首先公開出現是在 Solaris 8參照Sun的數據,在750個客戶端的時候,這種實現僅佔poll()開銷的10%。

    在Linux上/dev/poll有不少種實現,可是沒有一種性能與epoll同樣好,這些實現歷來沒有真正完整過。在linux上/dev/poll是不建議的。

    參照 Poller_devpoll (cc,hbenchmarks ) 作爲一個如何使用/dev/poll替代其它就緒通知場景的例子。(注意-這個例子是針對linux /dev/poll的,在Solaris上多是沒法工做的。)

  • kqueue()
    在FreeBSD(以及NetBSD)上,這是推薦的poll的替代品。
    看下面,kqueue()能夠被指定爲邊緣觸發或者水平觸發。

2. 一個線程服務多個客戶端,並使用非阻塞I/O和變動就緒通知

  變動就緒通知(或邊緣觸發就緒通知)意味着你給內核一個文件描述符,這以後,當描述符從未就緒變換到就緒時,內核就以某種方式通知你。而後假設你知道文件描述符是就緒的,直到你作一些事情使得文件描述符再也不是就緒的時纔不會繼續發送更多該類型的文件描述符的就緒通知(例如:直到在一次發送,接收或接受調用,或一次發送或接收傳輸小於請求的字節數的時候你收到 EWOULDBLOCK 錯誤)。

  當你使用變動就緒通知時,你必須準備好僞事件,由於一個共同的信號就緒實現時,任何接收數據包,不管是文件描述符都已是就緒的。

 

  這是「水平觸發」就緒通知的對立面。這是有點不寬容的編程錯誤,由於若是你錯過了惟一的事件,鏈接事件就將永遠的卡住。不過,我發現邊沿觸發就緒通知使使用 OpenSSL 編程非阻塞客戶端更容易,因此是值得嘗試的。

  [Banga, Mogul, Drusha '99] 在1999年描述了這種方案。 

  有幾種APIs能夠使得應用程序得到「文件描述符已就緒」的通知:

  • kqueue() 這是在FreeBSD系統上推薦使用邊緣觸發的方法 (and, soon, NetBSD).

    FreeBSD 4.3及之後版本,NetBSD(2002.10)都支持 kqueue()/kevent(), 支持邊沿觸發和水平觸發(請查看Jonathan Lemon 的網頁和他的BSDCon 2000關於kqueue的論文)。

    就像/dev/poll同樣,你分配一個監聽對象,不過不是打開文件/dev/poll,而是調用kqueue ()來得到。須要改變你所監聽的事件或者得到當前事件的列表,能夠在kqueue()返回的描述符上 調用kevent()來達到目的。它不只能夠監聽套接字,還能夠監聽普通的文件的就緒,信號和I/O完 成的事件也能夠.

    Note: 在2000.10,FreeBSD的線程庫和kqueue()並不能一塊兒工做得很好,當kqueue()阻塞時, 那麼整個進程都將會阻塞,而不只僅是調用kqueue()的線程。

    See Poller_kqueue (cchbenchmarks) for an example of how to use kqueue() interchangeably with many other readiness notification schemes.

    使用kqueue()的例程和庫:

  • epoll
    這是Linux 2.6的內核中推薦使用的邊沿觸發poll.

    2001.7.11, Davide Libenzi提議了一個實時信號的可選方法,他稱之/dev/epoll(www.xmailserver.org/linux-patches/nio-improve.html), 該方法相似與實時信號就緒通知機制,可是結合了其它更多的事件,從而在大多數的事件獲取上擁有更高的效率。

    epoll在將它的接口從一個/dev下的指定文件改變爲系統調用sys_epoll後就合併到2.5版本的 Linux內核開發樹中,另外也提供了一個爲2.4老版本的內核能夠使用epoll的補丁。

    unifying epoll, aio, 2002 年萬聖節前夕的Linux內核郵件列表就統一epoll,aio和其它的event sources 展開了好久的爭論,it may yet happen,but Davide is concentrating on firming up epoll in general first.

  • Polyakov's kevent (Linux 2.6+) 的最後新聞:2006.2.9和2006.7.9,Evgeniy Polyakov發表了融合epoll和 aio的補丁,他的目標是支持網絡AIO. See:
  • Drepper的最新網絡接口 (proposal for Linux 2.6+)
    在2006 OLS上,Ulrich Drepper提議了一種最新的高速異步網絡API. See:
  • Realtime Signals實時信號
    Linux2.4內核中推薦使用的邊沿觸發poll.

    2.4的linux內核能夠經過實時信號來分派套接字事件,示例以下:

    /* Mask off SIGIO and the signal you want to use. */ 
    sigemptyset(&sigset); 
    sigaddset(&sigset, signum); 
    sigaddset(&sigset, SIGIO); 
    sigprocmask(SIG_BLOCK, &m_sigset, NULL);
    /* For each file descriptor, invoke F_SETOWN, F_SETSIG, and set O_ASYNC. */ 
    fcntl(fd, F_SETOWN, (int) getpid()); 
    fcntl(fd, F_SETSIG, signum); 
    flags = fcntl(fd, F_GETFL); flags |= O_NONBLOCK|O_ASYNC; fcntl(fd, F_SETFL, flags); 
    

    當正常的I/O函數如read()或write()完成時,發送信號。要使用該段的話,在外層循環中編寫 一個普通的poll(),在循環裏面,當poll()處理完全部的描述符後,進入 sigwaitinfo()循環。 若是sigwaitinfo()或sigtimedwait()返回了實時信號,那麼siginfo.si_fd和 siginfo_si_band給出的信息和調用poll()後pollfd.fd和pollfd.revents的幾乎同樣。若是你處 理該I/O,那麼就繼續調用sigwaitinfo()。 

    若是sigwaitinfo()返回了傳統的SIGIO,那麼信號隊列溢出了,你必須經過臨時 改變信號處理 程序爲SIG_DFL來刷新信號隊列,而後返回到外層的poll()循環。

    See Poller_sigio (cch) for an example of how to use rtsignals interchangeably with many other readiness notification schemes.

    See Zach Brown's phhttpd 示例代碼來如何直接使用這些特色. (Or don't; phhttpd is a bit hard to figure out...)

    [Provos, Lever, and Tweedie 2000] 描述了最新的phhttp的基準測試,使用了不一樣的sigtimewait()和sigtimedwait4(),這些調用能夠使你只用一次調用便得到多個信號。 有趣的是,sigtimedwait4()的主要好處是它容許應用程序測量系統負載(so it could behave appropriately)(poll()也提供了一樣的系統負載 測量)。

  • Signal-per-fd
    Signal-per-fd是由Chandra和Mosberger提出的對實時信號的一種改進,它能夠減小甚至削除實 時信號的溢出經過oalescing redundant events。然而是它的性能並無epoll好. 論文(www.hpl.hp.com/techreports/2000/HPL-2000-174.html) 比較了它和select(),/dev/poll的性能.

    Vitaly Luban在2001.5.18公佈了一個實現Signal-per-fd的補丁; 受權見www.luban.org/GPL/gpl.html. (到2001.9,在很重的負載狀況下仍然存在穩定性問題,利用dkftpbench測試在4500個用戶時將引起問題.

    如何使用signal-per-fd互換及通知計劃請參考參考 Poller_sigfd (cch)

3. 每一個服務器線程處理多個客戶端請求,並使用異步I/O

  在Unix中這種方式還不是很流行,可能由於少有操做系統支持異步I/O,也可能由於這種非阻塞I/O使得你不得不從新修改應用。在標準unix下,異步I/O功能是由 aio 接口(下滾查看 "異步輸入輸出"小節)提供, 它將一個信號和一個值與每一個I/O操做關聯。Signals信號和他們的值經過隊列形式快速傳遞到用戶進程中。這是 POSIX 1003.1b 實時擴展中的,同時也是單Unix規範的第2個版本。

  AIO一般和邊緣觸發完成消息一塊兒使用,例如當操做完成時,一個信號進入隊列 (也能夠在水平觸發完成通知時,經過調用aio_suspend(), 但我以爲應該不多人這樣作.)

glibc 2.1和後續版本提供了一個普通的實現,僅僅是爲了兼容標準,而不是爲了得到性能上的提升.

en LaHaise編寫的Linux AIO實現合併到了2.5.32的內核中,它並無採用內核線程,而是使 用了一個高效的underlying api,可是目前它還不支持套接字(2.4內核也有了AIO的補丁,不過 2.5/2.6的實現有必定程序上的不一樣)。更多信息以下:

  Suparma建議先看看 AIO的API.

  RedHat AS和Suse SLES都在2.4的內核中提供了高性能的實現,與2.6的內核實現類似,但並不徹底同樣。

 

  2006.2,在網絡AIO有了一個新的嘗試,具體請看Evgeniy Polyakov的基於kevent的AIO.

  1999, SGI爲Linux實現了一個高速的AIO,在到1.1版本時,聽說能夠很好的工做於磁盤I/O和網 絡套接字,且使用了內核線程。目前該實現依然對那些不能等待Ben的AIO套接字支持的人來講是頗有用的。

  O'Reilly 的"POSIX.4: Programming for the Real World"一書對aio作了很好的介紹.

  這裏 有一個指南介紹了早期的非標準的aio實現,能夠看看,可是請記住你得把"aioread"轉換爲"aio_read"。

  注意AIO並無提供無阻塞的爲磁盤I/O打開文件的方法,若是你在乎因打開磁盤文件而引發 sleep的話,Linus建議 你在另一個線程中調用open()而不是把但願寄託在對aio_open()系統調用上。

  在Windows下,異步I/O與術語"重疊I/O"和"IOCP"(I/O Completion Port,I/O完成端口)有必定聯繫。Microsoft的IOCP結合了 先前的如異步I/O(如aio_write)的技術,把事件完成的通知進行排隊(就像使用了aio_sigevent字段的aio_write),而且它 爲了保持單一IOCP線程的數量從而阻止了一部分請求。(Microsoft's IOCP combines techniques from the prior art like asynchronous I/O (like aio_write) and queued completion notification (like when using the aio_sigevent field with aio_write) with a new idea of holding back some requests to try to keep the number of running threads associated with a single IOCP constant.) 更多信息請看 Mark russinovich在sysinternals.com上的文章 Inside I/O Completion Ports, Jeffrey Richter的書"Programming Server-Side Applications for Microsoft Windows 2000" (AmazonMSPress), U.S. patent #06223207, or MSDN.

4. 一個服務線程服務一個客戶端,使用阻塞I/O

 

  ... 讓read()和write()阻塞. 這樣很差的地方在於須要爲每一個客戶端使用一個完整的棧,從而比較浪費內存。許多操做系統在處理數百個線程時仍存在必定的問題。若是每一個線程使用2MB的棧,那麼當你在32位的機器上運行 512(2^30 / 2^21=512)個線程時,你就會用光全部的1GB的用戶可訪問虛擬內存(Linux也是同樣運行在x86上的)。你能夠減少每一個線程所擁有的棧內存大小,可是因爲大部分線程庫在一旦線程建立後就不能增大線程棧大小,因此這樣作就意味着你必須使你的程序最小程度地使用內存。固然你也能夠把你的程序運行在64位的處理器上去。

  Linux,FreeBSD和Solaris系統的線程庫一直在更新,64位的處理器也已經開始在大部分的用戶中所使用。也許在不遠的未來,這些喜歡使用一個線程來服務一個客戶端的人也有能力服務於10000個客戶了。可是在目前,若是你想支持更多的客戶,你最好仍是使用其它的方法。

  那些厚着臉皮同意使用線程的觀點,如加州大學伯克利分校的von Behren,Condit和 Brewer在HostOS IX項目中提出的論文Why Events Are A Bad Idea (for High-concurrency Servers).有沒有反對使用線程的人要反駁此論文呢?:-)

LinuxTheads 

  LinuxTheads是標準Linux線程庫.自glib2.0後已經將LinuxTheads集成,同時LinuxTheads是兼容Posix的,可是不支持優秀的信號量機制。

NGPT:下一代Linux Posix線程工程

  NGPT是IBM發起的兼容Posix線程的Linux工程。如今的穩定版本是2.2,並且工做的很穩定...可是NGPT團隊宣稱他們已經對NGPT是僅支持模式,由於他們以爲「從長遠的角度看,社區貢獻是最好的方式」.NGPT團隊將繼續致力於Linux線程的研究,可是目前他們關注NPTL(Native POSIX Thread Library比較譯者加註).(因爲NGPT團隊辛勤的工做,他們已經被NPTL所承認)

NPTL: Linux的本地Posix線程庫

 

  NPTL是由 Ulrich Drepper ( glibc的主要維護人員)和 Ingo Molnar發起的項目,目的是提供world-class的Posix Linux線程支持。

  2003.10.5,NPTL做爲一個add-on目錄(就像linuxthreads同樣)被合併到glibc的cvs樹中,因此頗有可能隨glibc的下一次release而 一塊兒發佈。

  Red Hat 9是最先的包含NPTL的發行版本(對一些用戶來講有點不太方便,可是必須有人來打破這沉默[break the ice]...)

  NPTL links:

  這是我嘗試寫的描述NPTL歷史的文章(也能夠參考 Jerry Cooperstein的文章 ):

  2002.3,NGPT小組的Bill Abt,glibc的維護者Ulrich Drepper 和其它人召開了個會議來探討LinuxThreads的發展,會議的一個idea就是要改進mutex的性能。 Rusty Russell 等人 隨後實現了 fast userspace mutexes (futexes), (現在已在NGPT和NPTL中應用了)。 與會的大部分人都認爲NGPT應該合併到glibc中。

  然而Ulrich Drepper並不怎麼喜歡NGPT,他認爲他能夠作得更好。 (對那些曾經想提供補丁給glibc的人來講,這應該不會令他們感到驚訝:-) 因而在接下來的幾個月裏,Ulrich Drepper, Ingo Molnar和其它人致力於glibc和內核的改變,而後就弄出了 Native Posix Threads Library (NPTL). NPTL使用了NGPT設計的全部內核改進(kernel enhancement),而且採用了幾個最新的改進。 Ingo Molnar描述了 一下的幾個內核改進:

NPTL使用了三個由NGPT引入的內核特徵: getpid()返回PID,CLONE_THREAD和futexes; NPTL還使用了(並依賴)也是該項目的一部分的一個更爲wider的內核特徵集。

一些由NGPT引入內核的items也被修改,清除和擴展,例如線程組的處理(CLONE_THREAD). [the CLONE_THREAD changes which impacted NGPT's compatibility got synced with the NGPT folks, to make sure NGPT does not break in any unacceptable way.]

這些爲NPTL開發的而且後來在NPTL中使用的內核特徵都描述在設計白皮書中, http://people.redhat.com/drepper/nptl-design.pdf ...

A short list: TLS support, various clone extensions (CLONE_SETTLS, CLONE_SETTID, CLONE_CLEARTID), POSIX thread-signal handling, sys_exit() extension (release TID futex upon VM-release), the sys_exit_group() system-call, sys_execve() enhancements and support for detached threads.

There was also work put into extending the PID space - eg. procfs crashed due to 64K PID assumptions, max_pid, and pid allocation scalability work. Plus a number of performance-only improvements were done as well.

In essence the new features are a no-compromises approach to 1:1 threading - the kernel now helps in everything where it can improve threading, and we precisely do the minimally necessary set of context switches and kernel calls for every basic threading primitive.

  NGPT和NPTL的一個最大的不一樣就是NPTL是1:1的線程模型,而NGPT是M:N的編程模型(具體請看下面). 儘管這樣, Ulrich的最初的基準測試 仍是代表NPTL比NGPT快不少。(NGPT小組期待查看Ulrich的測試程序來覈實他的結果.)

FreeBSD線程支持

  FreeBSD支持LinuxThreads和用戶空間的線程庫。一樣,M:N的模型實現KSE在FreeBSD 5.0中引入。 具體請查看 www.unobvious.com/bsd/freebsd-threads.html.

2003.3.25, Jeff Roberson 發表於freebsd-arch:

...感謝Julian, David Xu, Mini, Dan Eischen,和其它的每一位參加了KSE和libpthread開發的成員所提供的基礎, Mini和我已經開發出了一個1:1模型的線程實現,它能夠和KSE並行工做而不會帶來任何影響。實際上,它有助於把M:N線程共享位測試. ...

  2006.7,  Robert Watson提議1:1的線程模型應該爲FreeBSD 7.x的默認實現:

我知道曾經討論過這個問題,可是我認爲隨着7.x的向前推動,這個問題應該從新考慮。 在不少普通的應用程序和特定的基準測試中,libthr明顯的比libpthread在性能上要好得多。 libthr是在咱們大量的平臺上實現的,而libpthread卻只有在幾個平臺上。 最主要的是由於咱們使得Mysql和其它的大量線程的使用者轉換到"libthr",which is suggestive, also! ... 因此strawman提議:讓libthr成爲7.x上的默認線程庫。

NetBSD線程支持

  根據Noriyuki Soda的描述:

內核支持M:N線程庫是基於調度程序激活模型,合併於2003.1.18當時的NetBSD版本中。

  詳情請看Nathan J. Williams, Wasabi Systems, Inc.在2002年的FREENIX上的演示  An Implementation of Scheduler Activations on the NetBSD Operating System

 

Solaris線程支持

  Solaris的線程支持還在進一步提升evolving... 從Solaris 2到Solaris 8,默認的線程庫使用的都是M:N模型, 可是Solaris 9卻默認使用了1:1線程模型. 查看Sun多線程編程指南 和Sun的關於Java和Solaris線程的note.

Java在JDK 1.3.x及更早的線程支持

  你們都知道,Java一直到JDK1.3.x都沒有支持任何處理網絡鏈接的方法,除了一個線程服務一個客戶端的模型以外。  Volanomark是一個不錯的微型測試程序,能夠用來測量在 某個時候不一樣數目的網絡鏈接時每秒鐘的信息吞吐量。在2003.5, JDK 1.3的實現實際上能夠同時處理10000個鏈接,可是性能卻嚴重降低了。 從Table 4 能夠看出JVMs能夠處理10000個鏈接,可是隨着鏈接數目的增加性能也逐步降低。

 

 

注意: 1:1線程 vs M:N線程

   在實現線程庫的時候有一個選擇就是你能夠把全部的線程支持都放到內核中(也就是所謂的1:1的模型),也能夠把一些線程移到用戶空間上去(也就是所謂的M:N模型)。從某個角度來講, M:N被認爲擁有更好的性能,可是因爲很難被正確的編寫,因此大部分人都遠離了該方法.

5. 把服務代碼編譯進內核

 

  Novell和Microsoft都宣稱已經在不一樣時期完成了該工做,至少NFS的實現完成了該工做。 khttpd在Linux下爲靜態web頁面完成了該工做, Ingo Molnar完成了"TUX" (Threaded linUX webserver) ,這是一個Linux下的快速的可擴展的內核空間的HTTP服務器。 Ingo在2000.9.1宣佈 alpha版本的TUX能夠在ftp://ftp.redhat.com/pub/redhat/tux下載, 而且介紹瞭如何加入其郵件列表來獲取更多信息。

  在Linux內核的郵件列表上討論了該方法的好處和缺點,多數人認爲不該該把web服務器放進內核中,相反內核加入最小的鉤子hooks來提升web服務器的性能,這樣對其它形式的服務器就有益。具體請看  Zach Brown的討論 對比用戶級別和內核的http服務器。在2.4的linux內核中爲用戶程序提供了足夠的權力(power),就像 X15 服務器運行的速度和TUX幾乎同樣,可是它沒有對內核作任何改變

註釋

  Richard Gooch曾經寫了一篇討論  I/O選項的論文。
  在2001, Tim Brecht和MMichal Ostrowski爲使用簡單的基於select的服務器   作了各類策略的測試。 測試的數據值得看一看。
  在2003, Tim Brecht發表了  userver的源碼, 該web服務器是整合了Abhishek Chandra, David Mosberger, David Pariag和Michal Ostrowski所寫的幾個服務器,能夠使用select(), poll(), epoll()和sigio.

  早在1999年, Dean Gaudet就表示:

我一直在問「爲何大家不使用基於select/event像Zeus的模型,它明顯是最快的。」...
  他們不使用它的緣由能夠簡單歸結爲「太難理解了,而且其中的性能指標還不清楚」,可是幾個月後,當該模型變得易懂時人們就開始願意使用它了。

  Mark Russinovich寫了 一篇評論和 文章討論了在2.2的linux內核只可以I/O策略問題。 儘管某些地方彷佛有點錯誤,不過仍是值得去看。特別是他認爲Linux2.2的異步I/O (請看上面的F_SETSIG) 並無在數據準備好時通知用戶進程,而只有在新的鏈接到達時纔有。 這看起來是一個奇怪的誤解。 還能夠看看 早期的一些commentsIngo Molnar在1999.4.30所舉的反例Russinovich在1999.5.2的comments, Alan Cox的 反例,和各類 linux內核郵件. 我懷疑他想說的是Linux不支持異步磁盤I/O,這在過去是正確的,可是如今SGI已經實現了KAIO,它已再也不正確了。

  查看頁面 sysinternals.com和 MSDN瞭解一下「完成端口」, 聽說它是NT中獨特的技術, 簡單說,win32的"重疊I/O"被認爲是過低水平而不方面使用,「完成端口」是提供了完成事件隊列的封裝,再加上魔法般的調度, 經過容許更多的線程來得到完成事件若是該端口上的其它已得到完成事件的線程處於睡眠中時(可能正在處理阻塞I/O),從而能夠保持運行線程數目恆定(scheduling magic that tries to keep the number of running threads constant by allowing more threads to pick up completion events if other threads that had picked up completion events from this port are sleeping (perhaps doing blocking I/O).

  查看OS/400的I/O完成端口支持.

  在1999年9月,有一場頗有趣的關於linux內核的討論,它叫作 "> 15,000個併發鏈接" (主題的第二週 ). 重點以下:

  • Ed Hall根據他的經驗 發表 一些他的觀點;他在跑着Solaris系統的UP P2/333上完成了超過1000鏈接/秒的任務。他代碼裏使用不多的線程(一兩個CPU),每一個線程管理大量的使用事件模型模擬的用戶
  • Mike Jagdis posted 發表的分析poll/select系統開銷的文章 並說 "當前的 select/poll實現部分能夠改良,特別在阻塞狀態下, 但系統開銷仍然會隨着描述符的增長而增長,由於select/poll不會也不能記住描述符參與了什麼。不過很容易經過使用新的API來修復這個問題。歡迎提出建議....."
  • Mike發表了  關於 改善select()和poll()的文章.
  • Mike 發表了一個可能替換poll()/select()的API: "爲什麼不試試'類設備'的API?你能夠用它寫出類pollfd的結構,而後「設備」就會偵探事件並在你讀取它的時候傳送類pollfd結構表示的結果... "
  • Rogier Wolff 推薦使用 "digital guys推薦的API", http://www.cs.rice.edu/~gaurav/papers/usenix99.ps
  • Joerg Pommnitz 指出t that任何新API都應不只能等待文件描述符事件,還要能接受信號和處理SYSV-IPC。咱們的同步原語至少應該可以作到Win32下的WaitForMultipleObjects可以作的。
  • Stephen Tweedie 指出F_SETSIG, 排隊的實時信號和sigwaitinfo()的結合是http://www.cs.rice.edu/~gaurav/papers/usenix99.ps中建議的API的超集. 他同時提到若是你對性能感興趣,你應該老是讓信號阻塞,而不是讓信號異步傳送,以至於處理器調用sigwaitinfo()在隊列中調度下一個進程。
  • Jayson Nordwick用F_SETSIG同步事件模型 比較 完成端口,並得出了類似的結論。
  • Alan Cox 指出老版本的SCT's SIGIO 補丁包括在了 2.3.18ac.
  • Jordan Mendelson 貼出了一些示例代碼並演示如何使用F_SETSIG.
  • Stephen C. Tweedie 繼續比較完成端口和F_SETSIG, 並稱: "在信號出隊列的機制下,若是類庫使用一樣的機制,那麼你的應用程序就會爲不一樣庫組件預約受信" ,類庫也能夠創建本身的受信句柄,這樣就不會過多地影響程序自己了。
  • Doug Royer 指出當他在Sun的日程服務器上工做時,他已經在Solaris 2.6上創建了100,000 個鏈接。其餘人也附和地談到在Linux上須要多少RAM,可能會遇到什麼瓶頸。

 

  感謝閱讀!

打開文件句柄的限制

  • 任何Unix系統:限制數由 ulimit 或 setrlimit 來設置
  • Solaris  系統:參考 the Solaris FAQ, question 3.46 (或先後不久,他們按期地從新編號了問題)
  • FreeBSD系統:

  編輯/boot/loader.conf 文件,增長這一行:

set kern.maxfiles=XXXX
  這裏 XXXX 是所指望的文件描述符的系統限制,而後重啓。 感謝一位匿名讀者,回覆說他在 FreeBSD 4.3 上已經作到設置超過10000的鏈接數:
FWIW:實際上你不能經過sysctl等隨意地在 FreeBSD裏調節最大鏈接數,你必須在 /boot/loader.conf 文件裏作。
理由是 在系統啓動早期,初始化socket和 tcpcn結構體區域時調用  zalloci() 調用,以便該區是鍵入穩定的和熱拔插的。
你仍然須要設置較高的 mbun 數,由於你將(在一個未修改過的內核上)讓每個tcptempl結構體鏈接都消耗一個 mbuf,該連接用於實現保持活躍。

  另外一位讀者說:

如在 FreeBSD 4.4裏,tcptempl 結構體再也不被分配內存,你也無需非要擔憂每一個鏈接都吃掉一個 mbuf 。 

  另見:

  • OpenBSD 系統: 一位讀者說
在 OpenBSD裏,須要額外的調整以增長每一個進程可打開的文件句柄數: /etc/login.conf 中的 openfiles-cur 參數須要增大。 你能夠經過 sysctl -w 或在 sysctl.conf 更新 kern.macfiles ,但這並無影響。這個狀況是由於在發佈時,login.conf 對於非受權進程被限制爲較低的64,受權進程限制爲 128。
echo 32768 > /proc/sys/fs/file-max
  增長打開文件數的系統限制,並
ulimit -n 32768
  以增長併發進程數限制。

  在 2.2.x 內核上:

echo 32768 > /proc/sys/fs/file-max 
echo 65536 > /proc/sys/fs/inode-max
  增長打開文件數的系統限制,並
ulimit -n 32768

  以增長併發進程數限制。

  我驗證發現 Red Hat 6.0(2.2.5 或補丁版)上用這種方式能打開至少31000個文件描述符。另外一個哥們也驗證發如今 2.2.12上一個進程用這種方式能夠打開至少90000個文件描述符(適當的限制)。上限彷佛取決於內存。

  Stephen C. Tweedie 發帖講述過如何在系統引導期間使用 initscript和 pam_limit來設置ulimit以限制全局或單個用戶。

  在較舊的 2.2內核上,每一個進程可打開的文件數仍然被限制爲1024,即便有上述的變更。

  參見 Oskar's 1998 post ,探討了在2.0.36內核裏每一個進程以及系統範圍內的文件描述符限制。

線程使用的限制

  無論是何種體系架構,你都應該在每個線程裏儘量的減小棧空間的使用,這樣以防止耗光虛擬內存。若是你用pthreads,你能夠在運行時調用pthread_attr_init函數進行設置。

  • Solaris:據我所知,它根據內存大小能夠建立很是多的線程。
  • Linux2.6內核上的NPTL:在/proc/sys/vm/max_map_count須要設置最多增長到32000個線程。(除非你在64位處理器上工做,在大量線程工做時,你必須用棧空間小的線程)。看看NPTL的郵件列表,如,有個關於線程主題的「不能建立超過32K的線程?」,以此你能夠得到更多的信息。
  • Linux2.4:/proc/sys/kernel/threads-max 是建立線程數的最大值,在個人Red Hat8系統中默認是2047。你能夠用echo命令來增長數目,如:「echo 4000 > /proc/sys/kernel/threads-max」
  • Linux2.2:2.2.13內核至少在Intel平臺上是限制線程數目的,在其餘平臺上的狀況我就不知道了。Mingo在Intel上的補丁版本2.1.131中取消了線程數的限制。正式版會出如今2.3.20版本上.你能夠參考Volano中有關文件,線程和FD_SET限制的詳細介紹。哦,這個文檔講了不少對你來講很難的東西,但有些是過期了。
  • Java:看看Volano詳細的介紹,裏面講到Java是如何適應不少不一樣的系統,但卻能處理不少的線程。

Java 相關問題

  在JDK1.3及之前,標準的Java網絡庫主要提供每一個鏈接單獨線程處理的模型。這是一種非阻塞讀的工做方式,但並不支持非阻塞寫。

  2001年5月, JDK 1.4 引入了 java.nio 包以支持完整的非阻塞I/O操做(以及其餘優勢)。詳情請見發行說明。請嘗試使用並向Sun提交反饋。

  惠普(HP)的Java庫也包含了線程輪詢API。

  2000年,Matt Welsh在Java上實現了非阻塞網絡接口(socket); 對這個實現的負載測試代表在服務端處理大量(達到10000)鏈接時,非阻塞的方式比阻塞更具優點。這個庫叫作java-nbio: Sandstorm 項目的一部分。負載測試報告可參見10000鏈接的性能 。

  另請參考Dean Gaudet論文中關於Java、網絡I/O以及線程部分;Matt Welsh的論文:事件驅動vs工做線程

  在NIO以前,改進Java網絡API主要有如下幾種建議:

  • Matt Welsh的捷豹系統建議預先序列化對象、使用新的Java字節碼以及改造內存管理機制從而使Java支持異步I/O。
  • C-C. Chang和T. von Eicken提出將Java抽象成虛擬接口架構(Virtual Interface Architecture)。他們建議改造內存管理機制從而使Java支持異步I/O。
  • JSR-51是Sun的一個項目,它引入了java.noi包。Matt Welsh也參與其中。(誰說Sun不聽他人意見?)

其餘提示

  • 零拷貝
    一般,數據在傳輸的過程當中會被拷貝好屢次。一些消除這些拷貝直到達到絕對最小值的方案被稱爲「零拷貝」。
    • Thomas Ogrisegg's zero-copy send patch ,用於Linux 2.4.17-2.4.20 下的 mmaped 文件。它被號稱快於 sendfile()。
    • IO-Lite 是一組去掉了屢次沒必要要拷貝的 I/O 基本元素提案。
    • 早在1999年, Alan Cox 提出零拷貝有時不值得去費心 。(儘管他也喜歡 sendfile()。)
    • 2000 年七月,在 TUX 1.0 的 2.4 內核上,Ingo 實現了TCP零拷貝的一種形式,並稱他會很快在用戶空間上實現這一功能。
    • Drew Gallatin 和 Robert Picco 爲 FreeBSD 增添了一些零拷貝特性;這主意看來就像:若是你在一個 socket 中調用 write() 或 read(),指針是按頁對齊,同時要傳輸的數據量至少是一頁,*同時*你不當即重用緩衝,使用內存管理訣竅來避免拷貝。可是看一看 linux-kernel 上這個消息的跟貼 ,人們對這些內存管理訣竅的速度的擔心。

      根據來自 Noriyuki Soda 的說明:

      自 NetBSD-1.6 發佈,經過指定 "SOSEND_LOAN"  內核選項,來支持發送端零拷貝。如今這個選項在 NetBSD-current 中是默認的(你能夠經過在 NetBSD_current 的內核選項中指定 "SOSEND_NO_LOAN"  來禁用這項特性)。使用這個特性,若是要發送的數據超過 4096 字節,零拷貝自動啓用。
    • sendfile() 系統調用可以實現零拷貝的網絡工做。
      Linux 和 FreeBSD 中的 sendfile() 函數讓你告訴內核去發送一個文件的部分或所有。這讓操做系統儘量高效地去作。它也能夠一樣用在使用線程或非阻塞 I/O 的服務器上。 (在 Linux 上,目前缺少文檔;使用 _syscall4  調用它。 Andi Kleen 正在寫一個關於這個的新手冊頁。參閱在in Linux Gazette issue 91上,Jeff Tranter 的 探索 sendfile 系統調用 。)有傳言稱,ftp.cdrom.com 從 sendfile() 中顯著獲益。

      一個2.4內核上的 sendfile() 零拷貝實現正處於進程之中。參見 LWN Jan 25 2001

      一個在 Freebsd 上使用 sendfile() 的開發者報告說用 POLLWRBAND 取代 POLLOUT 會有大改觀。

      Solaris 8 (截至 2001 年 7 月的更新)有一個新的系統調用 'sendfilev'。 這裏有一個手冊頁的副本。Solaris 8 7/01 發佈說明 也提到了它。我懷疑這將會在阻塞模式下發送到一個 socket 時很是有用;而在非阻塞 socket 下使用時會有點痛苦。

  • 經過使用 writev (或 TCP_CORK)避免小幀
    Linux 下一個新的 socket 選項,TCP_CORK,告訴內核避免發送並不徹底的幀,這有些幫助,好比出於某些緣由,你不能將許多小的 write() 調用匯集在一塊兒時。去掉這個選項刷新緩衝。儘管用 writev() 更好……

    參閱 LWN Jan 25 2001,在 linux-kernel 上關於 TCP_CORK 和一個可能的替代者 MSG_MORE 的一些很是有趣的討論的總結。

  • 對過載切合實際地作出反應。
    [Provos, Lever, and Tweedie 2000] 記錄了當服務器過載時,丟棄傳入的鏈接,改善了性能曲線的形狀,同時減小了總體錯誤率。 他們使用了一個「I/O 就緒的客戶端的數目」的一個平滑描述做爲過載的一個尺度。這種技術應該能夠很容易地應用於使用 select,poll,或每次調用返回一個就緒事件計數的其餘系統調用(如 /dev/poll 或 sigtimedwait4())編寫的服務器上。 
  • 一些程序能夠從使用非Posix線程中獲益。
    並不是全部的線程生來相同。Linux 中的 clone()(和其餘操做系統中它的朋友們)讓你建立一個擁有它本身當前工做目錄的線程,例如,當實現一個  ftp 服務器時,這將很是有用。參看 Hoser FTPd,它是一個使用本地線程而非 pthreads 的例子。
  • 緩存本身的數據有時能夠取得共贏。
    5月9號, new-httpd 上,Vivek Sadananda Pai (vivek@cs.rice.edu) 在 "Re: fix for hybrid server problems"(回覆:hybrid服務器問題的修復) 中陳述:

    「在 FreeBSD 和 Solaris/x86 上,我都比較了一個基於 select 的服務器和一個多處理器服務器的原始(raw)性能。在微型基準(microbenchmarks)方面,僅有一些來源於軟件架構的細微性能差異。基於select的服務器的性能大獲全勝源於作了一些應用程序級別的緩存。同時多處理器服務器能夠用更高的代價作這件事,在實際的工做負擔上很難得到同等收益(較之微型基準)。我要將這些測量做爲下一期的 Usenix 會議上出現的論文的一部分。若是你有 postscript,可在 http://www.cs.rice.edu/~vivek/flash99/ 上找到這篇論文。」

Other limits其它限制
  • 老的系統庫使用16位的變量來保存文件句柄,當有超過32767個句柄時,這就會引發麻煩。glibc2.1應該沒有這個問題.
  • 許多系統使用16位變量來保存進程或線程ID。It would be interesting to port the Volano scalability benchmark to C, and see what the upper limit on number of threads is for the various operating systems.
  • 太多的線程局部內存被某些操做系統事件分配好,若是每一個線程分配1MB,而總共的虛擬內存空間才2GB,這會形成只能生成2000個線程的上限。
  • 參看這個頁面最後的性能比較圖。http://www.acme.com/software/thttpd/benchmarks.html. Notice how various servers have trouble above 128 connections, even on Solaris 2.6? 若是有人想出爲何,請告訴我。
  • 注意 :若是TCP棧存在一個bug,而引發在SYN或FIN時間上的小小的延時(200ms),這在Linux 2.2.0-2.2.6  中存在的,操做系統或http後臺程序在打開的鏈接數上有一個硬性限制,if the TCP stack has a bug that causes a short (200ms) delay at SYN or FIN time, as Linux 2.2.0-2.2.6 had, and the OS or http daemon has a hard limit on the number of connections open, you would expect exactly this behavior. There may be other causes.
核心問題
  對Linux來講,核心的瓶頸正不斷的被突破。能夠查看  Linux Weekly News,   Kernel Traffic,   the Linux-Kernel mailing list, 和   my Mindcraft Redux page.

  1999年3月,微軟主辦了一次基準測試來比較NT和Linux,比較他們在可服務的http和smb客戶的最大數量上面的性能。結果顯示 Linux性能不佳。更多的信息能夠參考:

  個人文章:my article on Mindcraft's April 1999 Benchmarks 
   The Linux Scalability Project. They're doing interesting work, including Niels Provos' hinting poll patch, and some work on the thundering herd problem.

  Mike Jagdis' work on improving select() and poll(); here's Mike's post about it.

  Mohit Aron (aron@cs.rice.edu) writes that rate-based clocking in TCP can improve HTTP response time over 'slow' connections by 80%.

測試服務器性能

  兩種測試很簡單、也有趣但同時也很難。
  1. 每秒鐘原始鏈接數。 (你能夠在一秒鐘內處理多少個512字節的文件呢?)
  2. 有不少慢速客戶端時在大文件上的傳輸速率(能夠支持多少個28.8k的調制解調器類型的客戶端同時從你的服務器下載,在你的性能急劇降低前?)
  Jef Poskanzer發表了許多關於比較web服務器性能的基準測試。 
   參看  http://www.acme.com/software/thttpd/benchmarks.html 他的結果. 

  個人筆記  關於 thttpd 和 Apache的對比 可能適合初學者查看.

  Chuck Lever  一直提醒咱們  Banga and Druschel的 "關於web服務器基準測試"論文 值得一讀
  IBM 的精彩論文 Java 服務器基準測試 [Baylor et al, 2000]. 也值得一看.

示例

Nginx是一個基於目標系統的高效率網絡事件機制的 Web 服務器。它愈發受歡迎起來;甚至有兩本相關相關書籍

有趣的基於 select() 服務器

有趣的基於 /dev/poll 的服務器

  • 2000年五月,N. Provos, C. Lever"Linux 平臺可擴展網絡 I/O," 「2000年6月,加利福尼亞州聖地亞哥,FREENIX track, Proc。USENIX 2000」描述了一個支持 /dev/poll 的 thttpd 修改版。同 phhttpd 進行了性能比較。

有趣的基於kqueue()的服務器

有趣的基於實時信號的服務器

  • Chromium's X15. 使用了2.4 內核的SIGIO特性加上sendfile()和TCP_CORK,其宣稱擁有比TUX更快的速度. 基於社區源碼許可下(非開源)的 源碼已經發布。查看Fabio Riccardi發佈的原始公告.
  • Zach Brown's phhttpd - "爲了展現sigio/siginfo事件模型而編寫的快速web服務器。考慮它的嗲嗎是一個高實驗性的,若是你要將它使用到生產環境,那一將要花費不少的腦力"。要使用siginfo特性你須要2.3.21 或之後的版本,它們包含了針對早期內核的補丁。其宣傳比khttpd更快。查看 1999.5.31號發佈的郵件 獲取更多信息。
值得關注的基於線程的服務器
值得關注的基於內核中的服務器
其它值得關注的連接

參考文獻:

英文版原文:http://www.kegel.com/c10k.html

中文翻譯參考自:http://www.oschina.net/translate/c10k

相關文章
相關標籤/搜索