歡迎光臨
每天分享高質量文章

秒懂!四步16點高效搞定高性能web服務器nginx

Nginx(讀音engine x)服務器由於性能優秀穩定、配置簡單以及跨平臺,被越來越多的公司和個人所採用,現已成為市場份額繼Apache之後的第二大Web服務器。各大小網站論壇博客也介紹說明瞭Nginx從安裝到優化的各種配置。

不過看了很多這些相關Nginx的文件之後,發現一個比較大的問題,就是這些文件基本也就從兩個方面著手,一是修改Nginx的配置檔案,二是調整操作系統的相關內核引數;而且文件說明也不夠明瞭,缺乏比較系統級別的優化。

本文將從Nginx原始碼編譯安裝開始,到修改配置檔案,調整系統內核引數以及架構四個方面著手分別介紹如何優化。

一.     安裝


(1)  精簡模塊

Nginx由於不斷添加新的功能,附帶的模塊也越來越多。很多操作系統廠商為了用戶方便安裝管理,都增加了rpm、deb或者其他自有格式軟體包,可以本地甚至在線安裝。不過我不太建議使用這種安裝方式。這雖然簡化了安裝,在線安裝甚至可以自動解決軟體依賴關係,但是安裝後軟體的檔案佈局過於分散,不便管理維護;同時也正是由於存在軟體包之間的依賴關係,導致當有安全漏洞、或者其它問題,想要通過更新升級Nginx新版本時卻發現yum、deb源還未發佈新版本(一般都落後於官網發佈的軟體版本)。最重要的是採用非原始碼編譯安裝的方式,預設會添加入許多模塊,比如郵件相關、uwsgi、memcache等等,很多網站運行時這些模塊根本未用到,雖然平時占用的資源很小,但是仍然可能是壓彎駱駝的一根稻草。各種非必需模塊預設安裝運行的同時,也給Web系統帶來了安全隱患。儘量保持軟體的輕裝上陣,是每個運維應當儘力做到的,所以我建議一般常用的服務器軟體使用原始碼編譯安裝管理。。我一般使用的編譯引數如下,PHP相關模塊fastcgi被保留用作後文優化說明,:

./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編譯引數優化 [可選項】

GCC總共提供了5級編譯優化級別:

-O0:無優化。

-O和-O1:使用能減少標的代碼尺寸以及執行時間並且不會使編譯時間明顯增加的優化。在編譯大型程式的時候會顯著增加編譯時記憶體的使用。

-O2:包含-O1的優化並增加了不需要在標的檔案大小和執行速度上進行折衷的優化。編譯器不執行迴圈展開以及函式行內。此選項將增加編譯時間和標的檔案的執行性能。

-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 提高性能和吞吐量,但這樣也會帶來背景關係切換增多或者負載升高等等其它資源更多消耗的後果。

(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_logoff。如必須儲存日誌,可以按每日或者每時或者其它時間段對日誌做切割,這也可以減小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模板,大家根據情況做適當修改:

[plain]view plaincopy

user  nginx nginx;

worker_processes  auto;

error_log  logs/error.log error;

pid        logs/nginx.pid;

worker_rlimit_nofile    65536;

events

{

use epoll;

accept_mutex off;

worker_connections  65536;

}

http

{

include       mime.types;

default_type  text/html;

charset UTF-8;

server_names_hash_bucket_size   128;

client_essay-header_buffer_size       4k;

large_client_essay-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  $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_essay-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 <

########################################

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

四.架構


Nginx的最大優勢在於處理靜態檔案和代理轉發功能,支持7層負載均衡和故障隔離。 動靜分離是每個網站發展到一定規模之後必然的結果。靜態請求則應當最好將其拆分,並啟用獨立的域名,既便於管理的需要,也便於今後能夠快速支持CDN。如果一臺Nginx性能無法滿足,則可以考慮在Nginx前端添加LVS負載均衡,或者F5等硬體負載均衡(費用昂貴,適合土豪公司單位),由多台Nginx共同分擔網站請求。還可以考慮結合Varnish或者Squid快取靜態檔案實現類似CDN功能。

新版Nginx目前已經支持直接讀寫Memcache,可以編譯安裝時候選擇添加此類模塊,從而節省了轉交給PHP或者JPS等動態程式服務器處理時間,提高效率的同時,減小了動態服務器的負載。

        

《Linux雲計算及運維架構師高薪實戰班》2018年11月26日即將開課中,120天衝擊Linux運維年薪30萬,改變速約~~~~

    *宣告:推送內容及圖片來源於網絡,部分內容會有所改動,版權歸原作者所有,如來源信息有誤或侵犯權益,請聯繫我們刪除或授權事宜。

    – END –


    赞(0)

    分享創造快樂