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

秒懂!四步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)

    分享創造快樂