我已經談過一些關於Nginx的常見問題; 其中有一些是關於如何優化Nginx. 很多Nginx新用戶是從Apache遷移過來的,因些他們過去常常調整配置和執行魔術操作來確保服務器高效運行.
我有一些壞消息要告訴你, 你不能像Apache一樣優化Nginx.它沒有魔術配置來減半負載或是讓PHP運行速度加快一倍. 高興的是, Nginx已經優化的非常好了. 當你決定使用Nginx並用apt-get,yum或是make命令安裝的時候它就已經進行了最佳優化. (注意那些庫經常過期,Wiki的安裝頁面上通常有最新的庫)
就是說,很多影響Nginx行為的參數其默認值並不是完全適合高並發的情況. 我們也要考慮Nginx運行所在的平台,優化我們的操作系統當有一些限制的時候.
總的來說,我們無法優化單個連接的負載時間,但是我們可以確保Nginx的高並發處理環境.當然, 對於高並發我指的是每秒數百個請求連接,大多數人不需要了解這些.假如你太好奇或是想知道那就繼續讀吧.
首先,我們需要認識到Nginx幾乎可能需要在所有的平台上使用,MacOS,Linux,FreeBSD,Solaris,Windows甚至一些更深 奧的系統。他們大部分(這麼翻譯好些)實現了高性能的基於事件的polling方法,不幸的是Nginx的只支持其中4個系統。在四個系統中我傾向於 FreeBSD,但你不會看到太大的性能差異,所以選擇的操作系統讓你用起來順手,比選擇最優化的操作系統更重要
我想你一定猜到了windows不在其中. Windows上的nginx確實沒有什麼理由讓你值得使用. Windows有自己的一套處理事件polling. 所以nginx的作者選擇了不支持. 因此默認的還是使用select() 這種不是很高效而且性能會下降很多的方式.(初次翻譯不是很好希望多多指教)
第二個最大的限制, 也是大多數人會遇到的問題是和操作系統相關的. 打開一個shell窗口, 使用su命令切換到Nginx的運行用戶, 運行命令`ulimit -a`. 這些值也會在Nginx在運行中對它進行限制. 在許多操作系統中, "open files"的值是相當有限的, 在我使用的操作系統中, 它的值是 1024. 如果Nginx在運行中操作了這個限制他會記錄error log(24: Too many open files) 接著返回一個操作給客戶端. 當然Nginx可以處理的文件數可以更大你也可以針對操作系統做一些改動, 你可以放心的去增加這個值.
兩種方式可以實現, 你可以通過ulimit設置os的:"open files", 你還可以通過(nginx)配置 worker_rlimit_nofile 來申明你期望的值.
當你正在處理下面這種情況, 你有很多的阻塞(blocking)磁盤IO,這是你可以適當增加worker_process的值. 你需要針您的配置進行測試,檢查靜態文件的等待時間(waiting time), 如果值比較大,可以適當的增加worker_process.
默認的值是1024. 我們假設一個李蘭奇一般情況下打開2個連接來通過管道獲取網站資源,也就是最多可以同時處理512個用戶的請求.聽起來實在是太少了,但是我們在想一下默 認的keepalive-timeout是65(在默認配置文件裡面提供了65這個值, 如果沒有設置該值,默認值是75,請參考wiki keepalive_timeout),也就是說我們實際上每秒只能處理8個連接. 顯然這個值高於許多人期望的(我沒覺得高呵呵), 尤其是考慮到我們通常會設置2-4個workers. 但是對於流量較大的網站 使用keep-alive是值得的.
此外,我們還必須考慮反向代理, 這將打開一個額外的連接到後台,但是,自Nginx的不支持持久連接到後台,這不是太大的問題,除非你有長時間運行的後台進程.
所有關於worker連接的配置應該是相當清楚的,如果你流量增加了,你要相應的增加worker連接的數量。 2048對於大多數人來說應該是滿足了,但老實說,如果你的流量增長了,那麼對於workers的數量值應該是多少應該是很清楚的.
我在這篇性能文章裡面提到這個原因非常簡單. 對於最終用戶來說keep alive對加載時間有著巨大的影響. 這是最重要的指標之一也是我們不斷優化的原因.如果你的網站對用戶來說感覺加載起來很快,他們就會很開心. Amazon和一些其他的大型在線零售商做過許多類似的研究表明, 網站的加載時間和網站訂單的完成有著直接的關系.
為什麼keep alive有著如此巨大的影響, 應該是顯而易見的, 那就是你避免為所有的HTTP請求創建各自的連接, 這是非常低效的. 也許你不需要把keepalive-timeout設置為65, 但是10-20應該是比較通用的選擇,正如上面一段所說, Nginx會很好的處理這方面.
一般服務器主要還有3個方面的瓶頸. CPU,內存和IO. Nginx在CPU的利用方面是非常高效的, 所以我會坦白的告訴你這不會成為瓶頸. 同樣nginx在使用內存方面也是很高效的,這也不會成為瓶頸. 現在只剩下IO這個服務器瓶頸的罪魁禍首了.
如果你經常使用服務器,那麼你可能經歷過這樣認識。硬盤驅動器是真的,真的很慢。從硬盤驅動器讀取可能是對服務器最昂貴的操作. 所以自然得出的結論是,為了避免IO瓶頸, 我們需要大量的減少nginx對硬盤驅動器的讀寫.
要做到這一點,我們可以通過修改Nginx的行為,以減少磁盤寫操作,以及確保對nginx的內存限制,允許它避免磁盤訪問。
Access Logs
默認情況下,Nginx的每個請求都會記錄在磁盤上的日志文件中,你可以使用這個方法進行統計,安全問題檢查等, 帶著這會在一定程度上帶來IO使用成本. 如果你不打算用這些訪問日志來做一些檢查或其他用途, 你可以直接關閉它以避免對磁盤寫操作, 但是如果你需要訪問日志,你可以考慮保存日志到內存中.這將會比直接寫到磁盤上快很多,並且明顯減少IO的使用.
如果你只打算使用訪問日志進行統計,你可以考慮使用其他的比如google analytics來取代(ga和access log還是有區別的 不能簡單的取代哦),或者你只記錄訪問請求的部分信息而不是全部.
Error Logs
我內心小小的掙扎了一把,我是否要在這裡闡述這個error log 指令呢,因為也許你根本不希望關閉error log, 特別是考慮到實際應用中錯誤日志的量會很少. 但是考慮到這裡指令有一個小小的地方需要引起大家注意, 錯誤日志的等級參數你是可以指定的, 如果你指定的太低了他會記錄404錯誤甚至是debug信息. 在實際的應用中可以將它設置為warn級別,將會是綽綽有余的並且能降低IO.
Open File Cache
從文件系統中讀取文件由2部分組成,打開和關閉文件. 考慮到這是一個有阻塞的操作,因此不要忽略這部分. 因此, 對於我們來說緩存打開文件的描述符是非常好的,這就是open_file_cache指令的由來. 鏈接的wiki地址裡對於使用和配置它有著非常好的說明, 所以我建議你去拜讀一下.
Buffers
配置Nginx緩存的大小是一個非常重要的事情. 如果緩存大小設置的太小, Nginx將不得不把上游(用英文upsteams會更好)的相應結果存放到臨時的緩存文件裡面,這將會同時增加IO的讀寫操作, 而且流量越大問題越多.
client_body_buffer_size指令用來指定處理客戶端請求的緩沖區大小, 這個代表了訪問請求的body. 這是用來處理POST的數據,也就是通過提交表單,文件上傳等請求的數據. 如果你需要處理很多大的POST請求的,你必須確保緩存區要設置的足夠大.
fastcgi_buffers 和 proxy_buffers 指 令用來處理上流(upstream)的響應結果, 也就是PHP Apache等.它的概念其實和上面提到的差不多, 如果緩沖區不足夠大數據將在返回給用戶使用之前被保存到磁盤上. 注意Nginx將這個buffer數據同步的傳輸給客戶端之前,有一個緩存上限, 保存到磁盤也同樣受限. 這個上線是通過fastcgi_max_temp_file_size和proxy_max_temp_file_size來設置的. 另外對於代理的連接你也可以通過把proxy_buffering設置成off來徹底的關閉緩存.
最好的減少磁盤IO的方法無疑是不使用磁盤, 如果你的的應用只有少量的數據傳輸,你可以將數據都放入內存,這樣就可以徹底不用考慮磁盤IO的阻塞了. 當然默認情況下你的操作系統也會緩存頻繁訪問的磁盤扇區, 所以內存越大磁盤的IO就會用到的越少. 這就意味著你可以通過增加內存來解決IO的瓶頸. 數據量越多,需要的內存越大.
網絡IO
為了好玩,我們假設你有了足夠大的內存來緩存你的所有數據. 這意味著理論上你的IO讀速度達到了3-6gbps. 但是你沒有那麼快的網絡通道. 不幸的是,我們可以優化的網絡IO是有限的,我們要通過網絡傳輸數據,所以還將受制於網絡IO. 唯一真正有效的方法是盡量減少數據量或壓縮。
幸運的是Nginx提供了gzip模塊, 它可以使我們在將數據傳輸給客戶端之前壓縮它, 這將大大減少數據的大小. 一般來說 gzip_comp_level的值不會在性能方面有多大的差別,設為為4-5即可. 一味的增加它是沒有意義的只是浪費的CPU的周期.