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
網絡軟件設計者每每有不少種選擇,如下列出一些:git
下面的五種組合應該是最經常使用的了:web
... 將全部網絡處理單元設置爲非阻塞狀態,並使用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了:
參照 Poller_select (cc,h) 作爲一個如何使用select()替代其它就緒通知場景例子。
參照 Poller_poll (cc,h,benchmarks) 作爲一個如何使用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上多是沒法工做的。)
變動就緒通知(或邊緣觸發就緒通知)意味着你給內核一個文件描述符,這以後,當描述符從未就緒變換到就緒時,內核就以某種方式通知你。而後假設你知道文件描述符是就緒的,直到你作一些事情使得文件描述符再也不是就緒的時纔不會繼續發送更多該類型的文件描述符的就緒通知(例如:直到在一次發送,接收或接受調用,或一次發送或接收傳輸小於請求的字節數的時候你收到 EWOULDBLOCK 錯誤)。
當你使用變動就緒通知時,你必須準備好僞事件,由於一個共同的信號就緒實現時,任何接收數據包,不管是文件描述符都已是就緒的。
這是「水平觸發」就緒通知的對立面。這是有點不寬容的編程錯誤,由於若是你錯過了惟一的事件,鏈接事件就將永遠的卡住。不過,我發現邊沿觸發就緒通知使使用 OpenSSL 編程非阻塞客戶端更容易,因此是值得嘗試的。
[Banga, Mogul, Drusha '99] 在1999年描述了這種方案。
有幾種APIs能夠使得應用程序得到「文件描述符已就緒」的通知:
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 (cc, h, benchmarks) for an example of how to use kqueue() interchangeably with many other readiness notification schemes.
使用kqueue()的例程和庫:
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.
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 (cc, h) 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()也提供了一樣的系統負載 測量)。
Vitaly Luban在2001.5.18公佈了一個實現Signal-per-fd的補丁; 受權見www.luban.org/GPL/gpl.html. (到2001.9,在很重的負載狀況下仍然存在穩定性問題,利用dkftpbench測試在4500個用戶時將引起問題.
如何使用signal-per-fd互換及通知計劃請參考參考 Poller_sigfd (cc, h)
在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" (Amazon, MSPress), U.S. patent #06223207, or MSDN.
... 讓read()和write()阻塞. 這樣很差的地方在於須要爲每一個客戶端使用一個完整的棧,從而比較浪費內存。許多操做系統在處理數百個線程時仍存在必定的問題。若是每一個線程使用2MB的棧,那麼當你在32位的機器上運行 512(2^30 / 2^21=512)個線程時,你就會用光全部的1GB的用戶可訪問虛擬內存(Linux也是同樣運行在x86上的)。你能夠減少每一個線程所擁有的棧內存大小,可是因爲大部分線程庫在一旦線程建立後就不能增大線程棧大小,因此這樣作就意味着你必須使你的程序最小程度地使用內存。固然你也能夠把你的程序運行在64位的處理器上去。
那些厚着臉皮同意使用線程的觀點,如加州大學伯克利分校的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是由 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支持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上的默認線程庫。
根據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的線程支持還在進一步提升evolving... 從Solaris 2到Solaris 8,默認的線程庫使用的都是M:N模型, 可是Solaris 9卻默認使用了1:1線程模型. 查看Sun多線程編程指南 和Sun的關於Java和Solaris線程的note.
你們都知道,Java一直到JDK1.3.x都沒有支持任何處理網絡鏈接的方法,除了一個線程服務一個客戶端的模型以外。 Volanomark是一個不錯的微型測試程序,能夠用來測量在 某個時候不一樣數目的網絡鏈接時每秒鐘的信息吞吐量。在2003.5, JDK 1.3的實現實際上能夠同時處理10000個鏈接,可是性能卻嚴重降低了。 從Table 4 能夠看出JVMs能夠處理10000個鏈接,可是隨着鏈接數目的增加性能也逐步降低。
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下載, 而且介紹瞭如何加入其郵件列表來獲取更多信息。
早在1999年, Dean Gaudet就表示:
我一直在問「爲何大家不使用基於select/event像Zeus的模型,它明顯是最快的。」...
Mark Russinovich寫了 一篇評論和 文章討論了在2.2的linux內核只可以I/O策略問題。 儘管某些地方彷佛有點錯誤,不過仍是值得去看。特別是他認爲Linux2.2的異步I/O (請看上面的F_SETSIG) 並無在數據準備好時通知用戶進程,而只有在新的鏈接到達時纔有。 這看起來是一個奇怪的誤解。 還能夠看看 早期的一些comments, Ingo 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).
在1999年9月,有一場頗有趣的關於linux內核的討論,它叫作 "> 15,000個併發鏈接" (主題的第二週 ). 重點以下:
感謝閱讀!
編輯/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裏,須要額外的調整以增長每一個進程可打開的文件句柄數: /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函數進行設置。
在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主要有如下幾種建議:
根據來自 Noriyuki Soda 的說明:
自 NetBSD-1.6 發佈,經過指定 "SOSEND_LOAN" 內核選項,來支持發送端零拷貝。如今這個選項在 NetBSD-current 中是默認的(你能夠經過在 NetBSD_current 的內核選項中指定 "SOSEND_NO_LOAN" 來禁用這項特性)。使用這個特性,若是要發送的數據超過 4096 字節,零拷貝自動啓用。
一個2.4內核上的 sendfile() 零拷貝實現正處於進程之中。參見 LWN Jan 25 2001。
一個在 Freebsd 上使用 sendfile() 的開發者報告說用 POLLWRBAND 取代 POLLOUT 會有大改觀。
Solaris 8 (截至 2001 年 7 月的更新)有一個新的系統調用 'sendfilev'。 這裏有一個手冊頁的副本。Solaris 8 7/01 發佈說明 也提到了它。我懷疑這將會在阻塞模式下發送到一個 socket 時很是有用;而在非阻塞 socket 下使用時會有點痛苦。
參閱 LWN Jan 25 2001,在 linux-kernel 上關於 TCP_CORK 和一個可能的替代者 MSG_MORE 的一些很是有趣的討論的總結。
「在 FreeBSD 和 Solaris/x86 上,我都比較了一個基於 select 的服務器和一個多處理器服務器的原始(raw)性能。在微型基準(microbenchmarks)方面,僅有一些來源於軟件架構的細微性能差異。基於select的服務器的性能大獲全勝源於作了一些應用程序級別的緩存。同時多處理器服務器能夠用更高的代價作這件事,在實際的工做負擔上很難得到同等收益(較之微型基準)。我要將這些測量做爲下一期的 Usenix 會議上出現的論文的一部分。若是你有 postscript,可在 http://www.cs.rice.edu/~vivek/flash99/ 上找到這篇論文。」
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.
個人筆記 關於 thttpd 和 Apache的對比 可能適合初學者查看.
Chuck Lever 一直提醒咱們 Banga and Druschel的 "關於web服務器基準測試"論文 值得一讀
IBM 的精彩論文 Java 服務器基準測試 [Baylor et al, 2000]. 也值得一看.
Nginx是一個基於目標系統的高效率網絡事件機制的 Web 服務器。它愈發受歡迎起來;甚至有兩本相關相關書籍。
參考文獻: