高并發(fā)下的Nginx優(yōu)化
我已經(jīng)談過(guò)一些關(guān)于Nginx的常見問(wèn)題; 其中有一些是關(guān)于如何優(yōu)化Nginx. 很多Nginx新用戶是從Apache遷移過(guò)來(lái)的,因些他們過(guò)去常常調(diào)整配置和執(zhí)行魔術(shù)操作來(lái)確保服務(wù)器高效運(yùn)行.
我有一些壞消息要告訴你, 你不能像Apache一樣優(yōu)化Nginx.它沒(méi)有魔術(shù)配置來(lái)減半負(fù)載或是讓PHP運(yùn)行速度加快一倍. 高興的是, Nginx已經(jīng)優(yōu)化的非常好了. 當(dāng)你決定使用Nginx并用apt-get,yum或是make命令安裝的時(shí)候它就已經(jīng)進(jìn)行了***優(yōu)化. (注意那些庫(kù)經(jīng)常過(guò)期,Wiki的安裝頁(yè)面上通常有***的庫(kù))
就是說(shuō),很多影響Nginx行為的參數(shù)其默認(rèn)值并不是完全適合高并發(fā)的情況. 我們也要考慮Nginx運(yùn)行所在的平臺(tái),優(yōu)化我們的操作系統(tǒng)當(dāng)有一些限制的時(shí)候.
總的來(lái)說(shuō),我們無(wú)法優(yōu)化單個(gè)連接的負(fù)載時(shí)間,但是我們可以確保Nginx的高并發(fā)處理環(huán)境.當(dāng)然, 對(duì)于高并發(fā)我指的是每秒數(shù)百個(gè)請(qǐng)求連接,大多數(shù)人不需要了解這些.假如你太好奇或是想知道那就繼續(xù)讀吧.
首先,我們需要認(rèn)識(shí)到Nginx幾乎可能需要在所有的平臺(tái)上使用,MacOS,Linux,F(xiàn)reeBSD,Solaris,Windows甚至一些更深?yuàn)W的系統(tǒng)。他們大部分(這么翻譯好些)實(shí)現(xiàn)了高性能的基于事件的polling方法,不幸的是Nginx的只支持其中4個(gè)系統(tǒng)。在四個(gè)系統(tǒng)中我傾向于FreeBSD,但你不會(huì)看到太大的性能差異,所以選擇的操作系統(tǒng)讓你用起來(lái)順手,比選擇***化的操作系統(tǒng)更重要(參考舟的***段翻譯的很好)
我想你一定猜到了windows不在其中. Windows上的nginx確實(shí)沒(méi)有什么理由讓你值得使用. Windows有自己的一套處理事件polling. 所以nginx的作者選擇了不支持. 因此默認(rèn)的還是使用select() 這種不是很高效而且性能會(huì)下降很多的方式.(初次翻譯不是很好希望多多指教)
第二個(gè)***的限制, 也是大多數(shù)人會(huì)遇到的問(wèn)題是和操作系統(tǒng)相關(guān)的. 打開一個(gè)shell窗口, 使用su命令切換到Nginx的運(yùn)行用戶, 運(yùn)行命令`ulimit -a`. 這些值也會(huì)在Nginx在運(yùn)行中對(duì)它進(jìn)行限制. 在許多操作系統(tǒng)中, "open files"的值是相當(dāng)有限的, 在我使用的操作系統(tǒng)中, 它的值是 1024. 如果Nginx在運(yùn)行中操作了這個(gè)限制他會(huì)記錄error log(24: Too many open files) 接著返回一個(gè)操作給客戶端. 當(dāng)然Nginx可以處理的文件數(shù)可以更大你也可以針對(duì)操作系統(tǒng)做一些改動(dòng), 你可以放心的去增加這個(gè)值.
兩種方式可以實(shí)現(xiàn), 你可以通過(guò)ulimit設(shè)置os的:"open files", 你還可以通過(guò)(nginx)配置 worker_rlimit_nofile 來(lái)申明你期望的值.
Nginx 限制
除了注意操作系統(tǒng)的限制, 現(xiàn)在我來(lái)深入到Nginx本身,看看一些指令和方法,我們可以用它來(lái)調(diào)整Nginx.
Worker Processes(用英文會(huì)更好一些)
worker_process 是 Nginx的主干, 一旦主進(jìn)程綁定到指定的IP和端口,就會(huì)使用nginx指定的用戶孵化出子進(jìn)程, 之后他們會(huì)處理所有的工作. Workers 不是多線程的, 所以不能擴(kuò)展它超過(guò)CPU的核數(shù). 所以我們應(yīng)該理解設(shè)置多個(gè)(>1)workers的原理, 通常一個(gè)CPU核對(duì)應(yīng)一個(gè)worker. 過(guò)猶不及,2-4個(gè)workers會(huì)傷害CPU, 在CPU成為問(wèn)題之前Nginx會(huì)遇到其他的瓶頸.而通常你只是看到了空閑的進(jìn)程.(這段翻的太爛了希望大家多多改進(jìn))
當(dāng)你正在處理下面這種情況, 你有很多的阻塞(blocking)磁盤IO,這是你可以適當(dāng)增加worker_process的值. 你需要針您的配置進(jìn)行測(cè)試,檢查靜態(tài)文件的等待時(shí)間(waiting time), 如果值比較大,可以適當(dāng)?shù)脑黾觲orker_process.(這段翻譯完有想哭的感覺)
Worker Connections
worker_connections 是個(gè)稍稍有點(diǎn)怪的概念. 我不是很了解這個(gè)指令的目的, 但是它有效的限制了在同一時(shí)間內(nèi)每個(gè)worker可以維護(hù)的連接數(shù). 如果我沒(méi)猜錯(cuò)的話, 這個(gè)配置是為了確保在keep-alive配置不正確的情況下, 當(dāng)你使用的端口將要耗盡之時(shí),增加連接數(shù).(這個(gè)翻譯的好難不知道是否正確因?yàn)樽髡咭彩莊orced to guess 我也只能被逼去猜了望指正)
默認(rèn)的值是1024. 我們假設(shè)一個(gè)李蘭奇一般情況下打開2個(gè)連接來(lái)通過(guò)管道獲取網(wǎng)站資源,也就是最多可以同時(shí)處理512個(gè)用戶的請(qǐng)求.聽起來(lái)實(shí)在是太少了,但是我們?cè)谙胍幌履J(rèn)的keepalive-timeout是65(在默認(rèn)配置文件里面提供了65這個(gè)值, 如果沒(méi)有設(shè)置該值,默認(rèn)值是75,請(qǐng)參考wiki keepalive_timeout),也就是說(shuō)我們實(shí)際上每秒只能處理8個(gè)連接. 顯然這個(gè)值高于許多人期望的(我沒(méi)覺得高呵呵), 尤其是考慮到我們通常會(huì)設(shè)置2-4個(gè)workers. 但是對(duì)于流量較大的網(wǎng)站 使用keep-alive是值得的.(翻譯完了又想哭了)
此外,我們還必須考慮反向代理, 這將打開一個(gè)額外的連接到后臺(tái),但是,自Nginx的不支持持久連接到后臺(tái),這不是太大的問(wèn)題,除非你有長(zhǎng)時(shí)間運(yùn)行的后臺(tái)進(jìn)程.
所有關(guān)于worker連接的配置應(yīng)該是相當(dāng)清楚的,如果你流量增加了,你要相應(yīng)的增加worker連接的數(shù)量。 2048對(duì)于大多數(shù)人來(lái)說(shuō)應(yīng)該是滿足了,但老實(shí)說(shuō),如果你的流量增長(zhǎng)了,那么對(duì)于workers的數(shù)量值應(yīng)該是多少應(yīng)該是很清楚的.
CPU 親和力
設(shè)置CPU的親和力,基本上意味著你告訴每個(gè)程序使用的CPU核心,而他們將只使用這個(gè)CPU核心。關(guān)于這一條,我不想說(shuō)很多,但你要知道,如果你準(zhǔn)備這樣做,則必須非常小心。 要知道,你操作系統(tǒng)的 CPU 調(diào)度器處理負(fù)載均衡的能力要遠(yuǎn)遠(yuǎn)超過(guò)你。當(dāng)然,如果你認(rèn)為你的 CPU 負(fù)載均衡有問(wèn)題,在調(diào)度層面上優(yōu)化它,可能的話找一個(gè)替代的調(diào)度器。除非你知道你在做什么,否則不要碰這個(gè)。
Keep Alive
keep_alive 是 HTTP的一個(gè)特性, 它允許客戶端維護(hù)與服務(wù)器已經(jīng)創(chuàng)建的連接進(jìn)行一批請(qǐng)求的處理直到指定的超時(shí)時(shí)間到達(dá). 這個(gè)實(shí)際上不會(huì)在很大程度上改變我們的Nginxserver的性能, 因?yàn)镹ginx能夠很好的處理空閑的連接. Nginx的作者聲稱10,000個(gè)空閑的連接智慧使用2.5兆內(nèi)存(unbelievable), 我個(gè)人的使用來(lái)說(shuō)這個(gè)值也是靠譜的.
我在這篇性能文章里面提到這個(gè)原因非常簡(jiǎn)單. 對(duì)于最終用戶來(lái)說(shuō)keep alive對(duì)加載時(shí)間有著巨大的影響. 這是最重要的指標(biāo)之一也是我們不斷優(yōu)化的原因.如果你的網(wǎng)站對(duì)用戶來(lái)說(shuō)感覺加載起來(lái)很快,他們就會(huì)很開心. Amazon和一些其他的大型在線零售商做過(guò)許多類似的研究表明, 網(wǎng)站的加載時(shí)間和網(wǎng)站訂單的完成有著直接的關(guān)系.
為什么keep alive有著如此巨大的影響, 應(yīng)該是顯而易見的, 那就是你避免為所有的HTTP請(qǐng)求創(chuàng)建各自的連接, 這是非常低效的. 也許你不需要把keepalive-timeout設(shè)置為65, 但是10-20應(yīng)該是比較通用的選擇,正如上面一段所說(shuō), Nginx會(huì)很好的處理這方面.
tcp_nodelay 和 tcp_nopush
這兩個(gè)指令也許是最難理解的nginx配置, 他們對(duì)于nginx的影響在網(wǎng)絡(luò)的較低層. 你可以簡(jiǎn)單的認(rèn)為這些指令決定了操作系統(tǒng)如何處理網(wǎng)絡(luò)緩存和他們何時(shí)將這些緩存輸出到最終用戶(客戶端). 我只能建議大家如果你之前不了解這些概念你***不要?jiǎng)铀? 他們不會(huì)顯著的改善或者改變性能, 所以***使用他們的默認(rèn)值.
硬件限制
因?yàn)槲覀円幚韓ginx帶來(lái)的所有可能的限制, 所以我們現(xiàn)在需要弄清楚如何有效的利用我們的服務(wù)器.為了做到這點(diǎn)我們需要看一下硬件層面的東西,由于大部分服務(wù)器瓶頸都會(huì)發(fā)生在這里.
一般服務(wù)器主要還有3個(gè)方面的瓶頸. CPU,內(nèi)存和IO. Nginx在CPU的利用方面是非常高效的, 所以我會(huì)坦白的告訴你這不會(huì)成為瓶頸. 同樣nginx在使用內(nèi)存方面也是很高效的,這也不會(huì)成為瓶頸. 現(xiàn)在只剩下IO這個(gè)服務(wù)器瓶頸的罪魁禍?zhǔn)琢?(搞得像找罪犯一樣)
如果你經(jīng)常使用服務(wù)器,那么你可能經(jīng)歷過(guò)這樣認(rèn)識(shí)。硬盤驅(qū)動(dòng)器是真的,真的很慢。從硬盤驅(qū)動(dòng)器讀取可能是對(duì)服務(wù)器最昂貴的操作. 所以自然得出的結(jié)論是,為了避免IO瓶頸, 我們需要大量的減少nginx對(duì)硬盤驅(qū)動(dòng)器的讀寫.
要做到這一點(diǎn),我們可以通過(guò)修改Nginx的行為,以減少磁盤寫操作,以及確保對(duì)nginx的內(nèi)存限制,允許它避免磁盤訪問(wèn)。
Access Logs
默認(rèn)情況下,Nginx的每個(gè)請(qǐng)求都會(huì)記錄在磁盤上的日志文件中,你可以使用這個(gè)方法進(jìn)行統(tǒng)計(jì),安全問(wèn)題檢查等, 帶著這會(huì)在一定程度上帶來(lái)IO使用成本. 如果你不打算用這些訪問(wèn)日志來(lái)做一些檢查或其他用途, 你可以直接關(guān)閉它以避免對(duì)磁盤寫操作, 但是如果你需要訪問(wèn)日志,你可以考慮保存日志到內(nèi)存中.這將會(huì)比直接寫到磁盤上快很多,并且明顯減少IO的使用.
如果你只打算使用訪問(wèn)日志進(jìn)行統(tǒng)計(jì),你可以考慮使用其他的比如google analytics來(lái)取代(ga和access log還是有區(qū)別的 不能簡(jiǎn)單的取代哦),或者你只記錄訪問(wèn)請(qǐng)求的部分信息而不是全部.
Error Logs
我內(nèi)心小小的掙扎了一把,我是否要在這里闡述這個(gè)error log 指令呢,因?yàn)橐苍S你根本不希望關(guān)閉error log, 特別是考慮到實(shí)際應(yīng)用中錯(cuò)誤日志的量會(huì)很少. 但是考慮到這里指令有一個(gè)小小的地方需要引起大家注意, 錯(cuò)誤日志的等級(jí)參數(shù)你是可以指定的, 如果你指定的太低了他會(huì)記錄404錯(cuò)誤甚至是debug信息. 在實(shí)際的應(yīng)用中可以將它設(shè)置為warn級(jí)別,將會(huì)是綽綽有余的并且能降低IO.
Open File Cache
從文件系統(tǒng)中讀取文件由2部分組成,打開和關(guān)閉文件. 考慮到這是一個(gè)有阻塞的操作,因此不要忽略這部分. 因此, 對(duì)于我們來(lái)說(shuō)緩存打開文件的描述符是非常好的,這就是open_file_cache指令的由來(lái). 鏈接的wiki地址里對(duì)于使用和配置它有著非常好的說(shuō)明, 所以我建議你去拜讀一下.
Buffers
配置Nginx緩存的大小是一個(gè)非常重要的事情. 如果緩存大小設(shè)置的太小, Nginx將不得不把上游(用英文upsteams會(huì)更好)的相應(yīng)結(jié)果存放到臨時(shí)的緩存文件里面,這將會(huì)同時(shí)增加IO的讀寫操作, 而且流量越大問(wèn)題越多.
client_body_buffer_size指令用來(lái)指定處理客戶端請(qǐng)求的緩沖區(qū)大小, 這個(gè)代表了訪問(wèn)請(qǐng)求的body. 這是用來(lái)處理POST的數(shù)據(jù),也就是通過(guò)提交表單,文件上傳等請(qǐng)求的數(shù)據(jù). 如果你需要處理很多大的POST請(qǐng)求的,你必須確保緩存區(qū)要設(shè)置的足夠大.
fastcgi_buffers 和 proxy_buffers 指令用來(lái)處理上流(upstream)的響應(yīng)結(jié)果, 也就是PHP Apache等.它的概念其實(shí)和上面提到的差不多, 如果緩沖區(qū)不足夠大數(shù)據(jù)將在返回給用戶使用之前被保存到磁盤上. 注意Nginx將這個(gè)buffer數(shù)據(jù)同步的傳輸給客戶端之前,有一個(gè)緩存上限, 保存到磁盤也同樣受限. 這個(gè)上線是通過(guò)fastcgi_max_temp_file_size和proxy_max_temp_file_size來(lái)設(shè)置的. 另外對(duì)于代理的連接你也可以通過(guò)把proxy_buffering設(shè)置成off來(lái)徹底的關(guān)閉緩存.(通常這不是一個(gè)好辦法).
徹底移除磁盤IO
***的減少磁盤IO的方法無(wú)疑是不使用磁盤, 如果你的的應(yīng)用只有少量的數(shù)據(jù)傳輸,你可以將數(shù)據(jù)都放入內(nèi)存,這樣就可以徹底不用考慮磁盤IO的阻塞了. 當(dāng)然默認(rèn)情況下你的操作系統(tǒng)也會(huì)緩存頻繁訪問(wèn)的磁盤扇區(qū), 所以內(nèi)存越大磁盤的IO就會(huì)用到的越少. 這就意味著你可以通過(guò)增加內(nèi)存來(lái)解決IO的瓶頸. 數(shù)據(jù)量越多,需要的內(nèi)存越大.
網(wǎng)絡(luò)IO
為了好玩,我們假設(shè)你有了足夠大的內(nèi)存來(lái)緩存你的所有數(shù)據(jù). 這意味著理論上你的IO讀速度達(dá)到了3-6gbps. 但是你沒(méi)有那么快的網(wǎng)絡(luò)通道. 不幸的是,我們可以優(yōu)化的網(wǎng)絡(luò)IO是有限的,我們要通過(guò)網(wǎng)絡(luò)傳輸數(shù)據(jù),所以還將受制于網(wǎng)絡(luò)IO. 唯一真正有效的方法是盡量減少數(shù)據(jù)量或壓縮。
幸運(yùn)的是Nginx提供了gzip模塊, 它可以使我們?cè)趯?shù)據(jù)傳輸給客戶端之前壓縮它, 這將大大減少數(shù)據(jù)的大小. 一般來(lái)說(shuō) gzip_comp_level的值不會(huì)在性能方面有多大的差別,設(shè)為為4-5即可. 一味的增加它是沒(méi)有意義的只是浪費(fèi)的CPU的周期.
你也可以通過(guò)一些javascript和css縮小工具來(lái)減少傳輸文件大小. 但這些不是和Nginx很相關(guān)所以我相信你通過(guò)google可以獲取更多的相關(guān)信息.
唷~
這篇文章已經(jīng)臨近結(jié)尾了。如果你還需要更進(jìn)一步的優(yōu)化,是時(shí)候考慮一下通過(guò)增加服務(wù)器了,沒(méi)有必要繼續(xù)在微優(yōu)化 Nginx 上浪費(fèi)時(shí)間,當(dāng)然,那將是另一個(gè)時(shí)間的另一篇文章中討論的話題。如果你因?yàn)檫@篇文章剛好2400個(gè)字而好奇(原稿),在進(jìn)一步探索我的博客前,請(qǐng)小憩一下。
譯文鏈接:http://www.oschina.net/translate/optimizing-nginx-for-high-traffic-loads




























