歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux基礎 >> Linux教程 >> 高並發下的Nginx優化方案

高並發下的Nginx優化方案

日期:2017/2/27 16:01:58   编辑:Linux教程
我已經談過一些關於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 來申明你期望的值。

Nginx 限制
除了注意操作系統的限制, 現在我來深入到Nginx本身,看看一些指令和方法,我們可以用它來調整Nginx。

Worker Processes(用英文會更好一些)
worker_process 是Nginx的主干, 一旦主進程綁定到指定的IP和端口,就會使用nginx指定的用戶孵化出子進程, 之後他們會處理所有的工作。 Workers 不是多線程的, 所以不能擴展它超過CPU的核數。 所以我們應該理解設置多個(>1)workers的原理, 通常一個CPU核對應一個worker。 過猶不及,2-4個workers會傷害CPU, 在CPU成為問題之前Nginx會遇到其他的瓶頸。而通常你只是看到了空閒的進程。(這段翻的太爛了希望大家多多改進)

當你正在處理下面這種情況, 你有很多的阻塞(blocking)磁盤IO,這是你可以適當增加worker_process的值。 你需要針您的配置進行測試,檢查靜態文件的等待時間(waiting time), 如果值比較大,可以適當的增加worker_process。(這段翻譯完有想哭的感覺)

Worker Connections
worker_connections 是個稍稍有點怪的概念。 我不是很了解這個指令的目的, 但是它有效的限制了在同一時間內每個worker可以維護的連接數。 如果我沒猜錯的話, 這個配置是為了確保在keep-alive配置不正確的情況下, 當你使用的端口將要耗盡之時,增加連接數。(這個翻譯的好難不知道是否正確因為作者也是forced to guess 我也只能被逼去猜了望指正)

默認的值是1024。 我們假設一個李蘭奇一般情況下打開2個連接來通過管道獲取網站資源,也就是最多可以同時處理512個用戶的請求。聽起來實在是太少了,但是我們在想一下默認的keepalive-timeout是65(在默認配置文件裡面提供了65這個值, 如果沒有設置該值,默認值是75,請參考wiki keepalive_timeout),也就是說我們實際上每秒只能處理8個連接。 顯然這個值高於許多人期望的(我沒覺得高呵呵), 尤其是考慮到我們通常會設置2-4個workers。 但是對於流量較大的網站 使用keep-alive是值得的。(翻譯完了又想哭了)

此外,我們還必須考慮反向代理, 這將打開一個額外的連接到後台,但是,自Nginx的不支持持久連接到後台,這不是太大的問題,除非你有長時間運行的後台進程。

所有關於worker連接的配置應該是相當清楚的,如果你流量增加了,你要相應的增加worker連接的數量。 2048對於大多數人來說應該是滿足了,但老實說,如果你的流量增長了,那麼對於workers的數量值應該是多少應該是很清楚的。

CPU 親和力
設置CPU的親和力,基本上意味著你告訴每個程序使用的CPU核心,而他們將只使用這個CPU核心。關於這一條,我不想說很多,但你要知道,如果你准備這樣做,則必須非常小心。 要知道,你操作系統的 CPU 調度器處理負載均衡的能力要遠遠超過你。當然,如果你認為你的 CPU 負載均衡有問題,在調度層面上優化它,可能的話找一個替代的調度器。除非你知道你在做什麼,否則不要碰這個。

Keep Alive
keep_alive 是 HTTP的一個特性, 它允許客戶端維護與服務器已經創建的連接進行一批請求的處理直到指定的超時時間到達。 這個實際上不會在很大程度上改變我們的Nginxserver的性能, 因為Nginx能夠很好的處理空閒的連接。 Nginx的作者聲稱10,000個空閒的連接智慧使用2。5兆內存(unbelievable), 我個人的使用來說這個值也是靠譜的。

我在這篇性能文章裡面提到這個原因非常簡單。 對於最終用戶來說keep alive對加載時間有著巨大的影響。 這是最重要的指標之一也是我們不斷優化的原因。如果你的網站對用戶來說感覺加載起來很快,他們就會很開心。 Amazon和一些其他的大型在線零售商做過許多類似的研究表明, 網站的加載時間和網站訂單的完成有著直接的關系。

為什麼keep alive有著如此巨大的影響, 應該是顯而易見的, 那就是你避免為所有的HTTP請求創建各自的連接, 這是非常低效的。 也許你不需要把keepalive-timeout設置為65, 但是10-20應該是比較通用的選擇,正如上面一段所說, Nginx會很好的處理這方面。

tcp_nodelay 和 tcp_nopush
這兩個指令也許是最難理解的nginx配置, 他們對於nginx的影響在網絡的較低層。 你可以簡單的認為這些指令決定了操作系統如何處理網絡緩存和他們何時將這些緩存輸出到最終用戶(客戶端)。 我只能建議大家如果你之前不了解這些概念你最好不要動它。 他們不會顯著的改善或者改變性能, 所以最好使用他們的默認值。

硬件限制
因為我們要處理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

為了好玩,我們假設你有了足夠大的內存來緩存你的所有數據。 這意味著理論上你的IO讀速度達到了3-6gbps。 但是你沒有那麼快的網絡通道。 不幸的是,我們可以優化的網絡IO是有限的,我們要通過網絡傳輸數據,所以還將受制於網絡IO。 唯一真正有效的方法是盡量減少數據量或壓縮。

幸運的是Nginx提供了gzip模塊, 它可以使我們在將數據傳輸給客戶端之前壓縮它, 這將大大減少數據的大小。 一般來說gzip_comp_level的值不會在性能方面有多大的差別,設為為4-5即可。 一味的增加它是沒有意義的只是浪費的CPU的周期。

你也可以通過一些javascript和css縮小工具來減少傳輸文件大小。 但這些不是和Nginx很相關所以我相信你通過google可以獲取更多的相關信息。
Copyright © Linux教程網 All Rights Reserved