Nginx(讀音engine x)服務器因爲性能優秀穩定、配置簡單以及跨平臺,被愈來愈多的公司和我的所採用,現已成爲市場份額繼Apache以後的第二大Web服務器。各大小網站論壇博客也介紹說明了Nginx從安裝到優化的各類配置。不過看了不少這些相關Nginx的文檔以後,發現一個比較大的問題,就是這些文檔基本也就從兩個方面着手,一是修改Nginx的配置文件,二是調整操做系統的相關內核參數;並且文檔說明也不夠明瞭,缺少比較系統級別的優化。本文將從Nginx源碼編譯安裝開始,到修改配置文件,調整系統內核參數以及架構四個方面着手分別介紹如何優化。javascript
一. 安裝php
(1) 精簡模塊css
Nginx因爲不斷添加新的功能,附帶的模塊也愈來愈多。不少操做系統廠商爲了用戶方便安裝管理,都增長了rpm、deb或者其餘自有格式軟件包,能夠本地甚至在線安裝。不過我不太建議使用這種安裝方式。這雖然簡化了安裝,在線安裝甚至能夠自動解決軟件依賴關係,可是安裝後軟件的文件佈局過於分散,不便管理維護;同時也正是因爲存在軟件包之間的依賴關係,致使當有安全漏洞、或者其它問題,想要經過更新升級Nginx新版本時卻發現yum、deb源還未發佈新版本(通常都落後於官網發佈的軟件版本)。最重要的是採用非源碼編譯安裝的方式,默認會添加入許多模塊,好比郵件相關、uwsgi、memcache等等,不少網站運行時這些模塊根本未用到,雖然平時佔用的資源很小,可是仍然多是壓彎駱駝的一根稻草。各類非必需模塊默認安裝運行的同時,也給Web系統帶來了安全隱患。儘可能保持軟件的輕裝上陣,是每一個運維應當盡力作到的,因此我建議通常經常使用的服務器軟件使用源碼編譯安裝管理。。我通常使用的編譯參數以下,PHP相關模塊fastcgi被保留用做後文優化說明,:html
./configure \ "--prefix=/App/nginx" \ "--with-http_stub_status_module" \ "--without-http_auth_basic_module" \ "--without-http_autoindex_module" \ "--without-http_browser_module" \ "--without-http_empty_gif_module" \ "--without-http_geo_module" \ "--without-http_limit_conn_module" \ "--without-http_limit_req_module" \ "--without-http_map_module" \ "--without-http_memcached_module" \ "--without-http_proxy_module" \ "--without-http_referer_module" \ "--without-http_scgi_module" \ "--without-http_split_clients_module" \ "--without-http_ssi_module" \ "--without-http_upstream_ip_hash_module" \ "--without-http_upstream_keepalive_module" \ "--without-http_upstream_least_conn_module" \ "--without-http_userid_module" \ "--without-http_uwsgi_module" \ "--without-mail_imap_module" \ "--without-mail_pop3_module" \ "--without-mail_smtp_module" \ "--without-poll_module" \ "--without-select_module" \ "--with-cc-opt='-O2'"
編譯參數根據網站是否真正用到的原則增添或者減小,好比咱們公司若是須要用到ssi模塊,從而可以實現訪問shtml頁面,能夠將第17行刪除,那麼Nginx將默認安裝。你們能夠經過運行 "./configure --help" 查看編譯幫助,決定是否須要安裝哪些模塊。前端
(2) GCC編譯參數優化 [可選項】java
GCC總共提供了5級編譯優化級別:nginx
-O0: 無優化。git
-O和-O1: 使用能減小目標代碼尺寸以及執行時間而且不會使編譯時間明顯增長的優化。在編譯大型程序的時候會顯著增長編譯時內存的使用。github
-O2: 包含-O1的優化並增長了不須要在目標文件大小和執行速度上進行折衷的優化。編譯器不執行循環展開以及函數內聯。此選項將增長編譯時間和目標文件的執行性能。web
-Os: 能夠當作 -O2.5,專門優化目標文件大小,執行全部的不增長目標文件大小的-O2優化選項,而且執行專門減少目標文件大小的優化選項。適用於磁盤空間緊張時使用。但有可能有未知的問題發生,何況目前硬盤容量很大,經常使用程序無必要使用。
-O3: 打開全部 -O2 的優化選項外增長 -finline-functions、-funswitch-loops、-fgcse-after-reload 優化選項。相對於 -O2 性能並未有較多提升,編譯時間也最長,生成的目標文件也更大更佔內存,有時性能不增反而下降,甚至產生不可預知的問題(包括錯誤),因此並不被大多數軟件安裝推薦,除非有絕對把握方可以使用此優化級別。
修改GCC編譯參數,提升編譯優化級別,此方法適用於全部經過GCC編譯安裝的程序,不止Nginx。穩妥起見用 -O2,這也是大多數軟件編譯推薦的優化級別。查看Nginx源碼文件 auto/cc/gcc,搜索NGX_GCC_OPT,默認GCC編譯參數爲-O,能夠直接修改內容爲NGX_GCC_OPT="-O2"或者在 ./configure配置時添加--with-cc-opt='-O2'選項。
二. 配置
應用服務器的性能優化主要在合理使用CPU、內存、磁盤IO和網絡IO四個方面,如今咱們從Nginx配置文件 nginx.conf 入手進行優化:
(1) 工做進程數的選擇
指令:worker_processes
定義了Nginx對外提供web服務時的工做進程數。最優值取決於許多因素,包括(但不限於)CPU核心的數量、存儲數據的硬盤數量及負載模式。不能肯定的時候,將其設置爲可用的CPU內核數將是一個好的開始(設置爲「auto」將嘗試自動檢測它)。Shell執行命令 ps ax | grep "nginx: worker process" | grep -v "grep" 能夠看到運行中的Nginx工做進程數,通常建議設置成服務器邏輯核心數,Shell執行命令 cat /proc/cpuinfo | grep processor | wc -l 能夠檢測出服務器邏輯核心總數,偷懶能夠直接寫auto,Nginx自適應。
(2) 是否綁定CPU
指令:worker_cpu_affinity
綁定工做進程到對應CPU核心,Nginx默認未開啓CPU綁定。目前的服務器通常爲多核CPU,當併發很大時,服務器各個CPU的使用率可能出現嚴重不均衡的局面,這時候能夠考慮使用CPU綁定,以達到CPU使用率相對均勻的狀態,充分發揮多核CPU的優點。top、htop等程序能夠查看全部CPU核心的使用率情況。綁定樣例:
worker_processes 4; worker_cpu_affinity 0001 0010 0100 1000;
(3) 打開文件數限制
指令:worker_rlimit_nofile
設定了每一個Nginx工做進程打開的最大文件數,受限於系統的用戶進程打開文件數限制,未設置則使用系統默認值。理論上應該設置爲當前Shell啓動進程的最大打開文件數除以Nginx的工做進程數。因爲Nginx的工做進程打開文件數並不一徹底均勻,因此能夠將其設置成Shell啓動進程的最大打開文件數。Shell執行命令 ulimit -n 能夠查看當前登陸Shell會話最大打開文件數數限制。Linux系統用戶進程默認同時打開文件最大數爲1024,這個值過小,訪問量稍大就報「too many open files"。Shell執行命令先修改用戶打開文件數限制:
echo "* - nofile 65536" >> /etc/security/limits.conf
而後添加入/etc/profile以下兩行內容,修改全部Shell和經過Shell啓動的進程打開文件數限制:
echo "ulimit -n 65536" >> /etc/profile
Shell執行命令使當前Shell臨時會話當即生效:
ulimit -n 65536
(4) 驚羣問題
指令:accept_mutex
若是 accept_mutex 指令值爲 on 啓用,那麼將輪流喚醒一個工做進程接收處理新的鏈接,其他工做進程繼續保持睡眠;若是值爲 off 關閉,那麼將喚醒全部工做進程,由系統經過use指令指定的網絡IO模型調度決定由哪一個工做進程處理,未接收到鏈接請求的工做進程繼續保持睡眠,這就是所謂的「驚羣問題」。Web服務器Apache的進程數不少,成百上千也是時有的事,「驚羣問題」也尤其明顯。Nginx爲了穩定,參數值保守的設置爲 on 開啓狀態。能夠將其設置成Off 提升性能和吞吐量,但這樣也會帶來上下文切換增多或者負載升高等等其它資源更多消耗的後果,反而性能下降,最好仍是壓力測試以後決定是否開啓,通常使用默認值on便可。
(5) 網絡IO模型
指令:use
定義了Nginx設置用於複用客戶端線程的輪詢方法(也可稱多路複用網絡IO模型)。這天然是選擇效率更高的優先,Linux 2.6+內核推薦使用epoll,FreeBSD推薦使用kqueue,安裝時Nginx會自動選擇。
(6) 鏈接數
指令:worker_connections
定義了Nginx一個工做進程的最大同時鏈接數,不只限於客戶端鏈接,包括了和後端被代理服務器等其餘的鏈接。官網文檔還指出了該參數值不能超過 worker_rlimit_nofile 值,因此建議設置成和 worker_rlimit_nofile 值相等。
(7) 打開文件緩存
指令:open_file_cache
開啓關閉打開文件緩存,默認值 off 關閉,強烈建議開啓,能夠避免從新打開同一文件帶來的系統開銷,節省響應時間。如需開啓必須後接參數 max=數字,設置緩存元素的最大數量。當緩存溢出時,使用LRU(最近最少使用)算法刪除緩存中的元素;可選參數 inactive=時間 設置超時,在這段時間內緩存元素若是沒有被訪問,將從緩存中刪除。示例:open_file_cache max=65536 inactive=60s。
指令:open_file_cache_valid
設置檢查open_file_cache緩存的元素的時間間隔。
指令:open_file_cache_min_uses
設置在由open_file_cache指令的inactive參數配置的超時時間內, 文件應該被訪問的最小次數。若是訪問次數大於等於此值,文件描述符會保留在緩存中,不然從緩存中刪除。
(8) 日誌相關
指令:access_log 和 error_log
當併發很大時,Nginx的訪問日誌和錯誤日誌的保存確定會形成對磁盤的大量讀寫,也將影響Nginx的性能。併發量越大,IO越高。這時候能夠考慮關閉訪問日誌和錯誤日誌,或者將日誌保存到tmpfs文件系統裏,或者減小保存的訪問日誌條目和錯誤日誌的級別,從而避免磁盤IO的影響。關閉日誌使用 access_log off。如必須保存日誌,能夠按每日或者每時或者其它時間段對日誌作切割,這也能夠減少IO,雖然可能效果不是特別大,不過由於日誌文件尺寸變小了不少,也方便查閱或歸檔分析日誌。通常線上環境建議錯誤日誌設置爲 error 或者 crit。自定義訪問日誌的條目和錯誤日誌的級別,詳細信息能夠參閱官網或者網上其它文檔,按需修改。
(9) 隱藏Nginx版本號
指令:server_tokens
開啓或關閉「Server」響應頭中輸出的Nginx版本號。推介設置爲 off,關閉顯示響應頭的版本號,對性能的提升有小小的裨益,主要仍是爲了安全起見,不被駭客找到版本號對應的漏洞,從而被***。
(10) 壓縮相關
指令:gzip
Nginx默認開啓了gzip壓縮功能。有可能不少人認爲,開啓gzip壓縮會增長CPU的處理時間和負載。可是通過咱們網站的測試發現,關閉了gzip壓縮功能的Nginx雖然減小了CPU計算,節省了服務器的響應時間,但網站頁面整體響應時間反而加長了,緣由在於js和css、xml、json、html等等這些靜態文件的數據傳輸時間的增加大大超過了服務器節省出來的響應時間,得不償失。gzip on 開啓壓縮後,大約能夠減小75%的文件尺寸,不但節省了比較多的帶寬流量,也提升了頁面的總體響應時間。全部建議仍是開啓。固然也不是全部的靜態文件都須要壓縮,好比靜態圖片和PDF、視頻,文件自己就應當作壓縮處理後保存到服務器。這些文件再次使用gzip壓縮,壓縮的比例並不高,甚至拔苗助長,壓縮後文件尺寸增大了。CPU壓縮處理這些靜態文件增長佔用的服務器響應時間絕大部分時候會超過了被壓縮減少的文件尺寸減小的數據傳輸時間,不划算。是否須要對Web網站開啓壓縮,以及對哪些文件過濾壓縮,你們能夠經過使用HttpWatch、Firebug等等網絡分析工具對比測試。
指令:gzip_comp_level
指定壓縮等級,其值從1到9,數字越大,壓縮率越高,越消耗CPU,負載也越高。9等級無疑壓縮率最高,壓縮後的文件尺寸也最小,但也是最耗CPU資源,負載最高,速度最慢的,這對於用戶訪問有時是沒法忍受的。通常推薦使用1-4等級,比較折衷的方案。咱們公司網站使用等級2。
指令:gzip_min_length
指定壓縮的文件最小尺寸,單位 bytes 字節,低於該值的不壓縮,超過該值的將被壓縮。咱們網站設置爲1k,過小的文件不必壓縮,壓縮太小尺寸文件帶來增長的CPU消耗時間和壓縮減小的文件尺寸下降的數據下載時間互相抵消,並有可能增長整體的響應時間。
指令:gzip_types
指定容許壓縮的文件類型,Nginx配置目錄 conf 下的 mime.types 文件存放了Nginx支持的文件類型,text/html類型文件,文件後綴爲html htm shtml默認壓縮。推薦配置:gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript。
(11) 瀏覽器緩存
指令:expires
設置HTTP應答中的「Expires」和「Cache-Control」頭標。"Expires"通常結合"Last-Modified"使用。當設置了合理的expires配置時,瀏覽器第一次訪問Web頁面元素,會下載頁面中的的靜態文件到本機臨時緩存目錄下。第二次及以後再次訪問相同URL時將發送帶頭標識"If-Modified-Since"和本地緩存文件時間屬性值的請求給服務器,服務器比對服務器本地文件時間屬性值,若是未修改,服務器直接返回http 304狀態碼,瀏覽器直接調用本地已緩存的文件;若是時間屬性值修改了,從新發送新文件。這樣就避免了從服務器再次傳送文件內容,減少了服務器壓力,節省了帶寬,同時也提升了用戶訪問速度,一舉三得。指令後接數字加時間單位,即爲緩存過時時間;-1 表示永遠過時,不緩存。強烈建議添加expires配置,過時時間的選擇具體分析。咱們公司的部分Nginx配置以下:
location ~ .+\.(gif|jpg|jpeg|png|bmp|swf)$ { expires 30d; } location ~ .+\.(js|css|xml|javascript|txt|csv)$ { expires 30d; }
或者統一將靜態文件放在固定目錄下再對目錄作location和expires,示例:
location /static/ { expires 30d; }
(12) 持久鏈接
指令:keepalive_timeout
啓用Http的持久鏈接Keepalive屬性,複用以前已創建的TCP鏈接接收請求、發送迴應,減小從新創建TCP鏈接的資源時間開銷。在此的建議是當網站頁面內容以靜態爲主時,開啓持久鏈接;若主要是動態網頁,且不能被轉化爲靜態頁面,則關閉持久鏈接。後接數字和時間單位符號。正數爲開啓持久鏈接,0關閉。
(13) 減小HTTP請求次數
網站頁面中存在大量的圖片、腳本、樣式表、Flash等靜態元素,減小訪問請求次數最大的優勢就是減小用戶首次訪問頁面的加載時間。能夠採用合併相同類型文件爲一個文件的辦法減小請求次數。這其實屬於Web前端優化範疇,應當由Web前段工程師作好相關靜態文件的規劃管理,而不是由運維來作。不過Nginx也能夠經過安裝阿里巴巴提供的Concat或者Google的PageSpeed模塊實現這個合併文件的功能。咱們公司並未使用合併功能,具體安裝配置信息請查詢網上相關文檔,這裏再也不累述。Concat源代碼網址:https://github.com/alibaba/nginx-http-concat/,PageSpeed源代碼網址:https://github.com/pagespeed/ngx_pagespeed。
(14) PHP相關
Nginx不能直接解析PHP代碼文件,須要調用FastCGI接口轉給PHP解釋器執行,而後將結果返回給Nginx。PHP優化本文暫不介紹。Nginx能夠開啓FastCGI的緩存功能,從而提升性能。
指令:fastcgi_temp_path
定義FastCGI緩存文件保存臨時路徑。
指令:fastcgi_cache_path
定義FastCGI緩存文件保存路徑和緩存的其它參數。緩存數據以二進制數據文件形式存儲,緩存文件名和key都是經過對訪問URL使用MD5計算得到的結果。緩存文件先保存至fastcgi_temp_path指定的臨時目錄下,而後經過重命名操做移至fastcgi_cache_path指定的緩存目錄。levels指定了目錄結構,子目錄數以16爲基數;keys_zone指定了共享內存區名和大小,用於保存緩存key和數據信息;inactive指定了緩存數據保存的時間,當這段時間內未被訪問,將被移出;max_size指定了緩存使用的最大磁盤空間,超過容量時將最近最少使用數據刪除。建議fastcgi_temp_path和fastcgi_cache_path設爲同一分區,同分區移動操做效率更高。示例:
fastcgi_temp_path /tmp/fastcgi_temp; fastcgi_cache_path /tmp/fastcgi_cache levels=1:2 keys_zone=cache_fastcgi:16m inactive=30m max_size=1g;
示例中使用/tmp/fastcgi_temp做爲FastCGI緩存的臨時目錄;/tmp/fastcgi_cache做爲FastCGI緩存保存的最終目錄;一級子目錄爲16的一次方16個,二級子目錄爲16的2次方256個;共享內存區名爲cache_fastcgi,佔用內存128MB;緩存過時時間爲30分鐘;緩存數據保存於磁盤的最大空間大小爲1GB。
指令:fastcgi_cache_key
定義FastCGI緩存關鍵字。啓用FastCGI緩存必須加上這個配置,否則訪問全部PHP的請求都爲訪問第一個PHP文件URL的結果。
指令:fastcgi_cache_valid
爲指定的Http狀態碼指定緩存時間。
指令:fastcgi_cache_min_uses
指定通過多少次請求相同的URL將被緩存。
指令:fastcgi_cache_use_stale
指定當鏈接FastCGI服務器發生錯誤時,哪些狀況使用過時數據迴應。
指令:fastcgi_cache
緩存使用哪一個共享內存區。
我經常使用nginx.conf模板,你們根據狀況作適當修改:
user nginx nginx; worker_processes auto; error_log logs/error.log error; pid logs/nginx.pid; worker_rlimit_nofile 65536; events { use epoll; worker_connections 65536; } http { include mime.types; default_type text/html; charset UTF-8; server_names_hash_bucket_size 128; client_header_buffer_size 4k; large_client_header_buffers 4 32k; client_max_body_size 8m; open_file_cache max=65536 inactive=60s; open_file_cache_valid 80s; open_file_cache_min_uses 1; log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; access_log logs/access.log main; sendfile on; server_tokens off; fastcgi_temp_path /tmp/fastcgi_temp; fastcgi_cache_path /tmp/fastcgi_cache levels=1:2 keys_zone=cache_fastcgi:128m inactive=30m max_size=1g; fastcgi_cache_key $request_method://$host$request_uri; fastcgi_cache_valid 200 302 1h; fastcgi_cache_valid 301 1d; fastcgi_cache_valid any 1m; fastcgi_cache_min_uses 1; fastcgi_cache_use_stale error timeout http_500 http_503 invalid_header; keepalive_timeout 60; gzip on; gzip_min_length 1k; gzip_buffers 4 64k; gzip_http_version 1.1; gzip_comp_level 2; gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript; server { listen 80; server_name localhost; index index.html; root /App/web; location ~ .+\.(php|php5)$ { fastcgi_pass unix:/tmp/php.sock; fastcgi_index index.php; include fastcgi.conf; fastcgi_cache cache_fastcgi; } location ~ .+\.(gif|jpg|jpeg|png|bmp|swf|txt|csv|doc|docx|xls|xlsx|ppt|pptx|flv)$ { expires 30d; } location ~ .+\.(js|css|html|xml)$ { expires 30d; } location /nginx-status { stub_status on; allow 192.168.1.0/24; allow 127.0.0.1; deny all; } } }
三. 內核
Linux內核參數部分默認值不適合高併發,通常臨時方法能夠經過調整/Proc文件系統,或者直接修改/etc/sysctl.conf配置文件永久保存。調整/Proc文件系統,系統重啓後還原至默認值,因此不推薦。Linux內核調優,主要涉及到網絡和文件系統、內存等的優化,下面是我經常使用的內核調優配置:
grep -q "net.ipv4.tcp_max_tw_buckets" /etc/sysctl.conf || cat >> /etc/sysctl.conf << EOF ######################################## net.core.rmem_default = 262144 net.core.rmem_max = 16777216 net.core.wmem_default = 262144 net.core.wmem_max = 16777216 net.core.somaxconn = 262144 net.core.netdev_max_backlog = 262144 net.ipv4.tcp_max_orphans = 262144 net.ipv4.tcp_max_syn_backlog = 262144 net.ipv4.tcp_max_tw_buckets = 10000 net.ipv4.ip_local_port_range = 1024 65500 net.ipv4.tcp_tw_recycle = 1 net.ipv4.tcp_tw_reuse = 1 net.ipv4.tcp_syncookies = 1 net.ipv4.tcp_synack_retries = 1 net.ipv4.tcp_syn_retries = 1 net.ipv4.tcp_fin_timeout = 30 net.ipv4.tcp_keepalive_time = 600 net.ipv4.tcp_keepalive_intvl = 30 net.ipv4.tcp_keepalive_probes = 3 net.ipv4.tcp_mem = 786432 1048576 1572864 fs.aio-max-nr = 1048576 fs.file-max = 6815744 kernel.sem = 250 32000 100 128 vm.swappiness = 10 EOF sysctl -p
詳細說明你們能夠查看個人Linux內核優化文章:http://dongsong.blog.51cto.com/916653/1631085。
四. 架構
Nginx的最大優點在於處理靜態文件和代理轉發功能,支持7層負載均衡和故障隔離。 動靜分離是每一個網站發展到必定規模以後必然的結果。靜態請求則應當最好將其拆分,並啓用獨立的域名,既便於管理的須要,也便於從此可以快速支持CDN。若是一臺Nginx性能沒法知足,則能夠考慮在Nginx前端添加LVS負載均衡,或者F5等硬件負載均衡(費用昂貴,適合土豪公司單位),由多臺Nginx共同分擔網站請求。還能夠考慮結合Varnish或者Squid緩存靜態文件實現相似CDN功能。新版Nginx目前已經支持直接讀寫Memcache,能夠編譯安裝時候選擇添加此類模塊,從而節省了轉交給PHP或者JPS等動態程序服務器處理時間,提升效率的同時,減少了動態服務器的負載。