Nginx
做爲 web 服務器
以低內存,高擴展,而且輕鬆單機支持 1-3w
(聽說能夠單機 10w,但沒有看到具體的機器配置)的併發連接的特性廣受開發人員的青睞。javascript
推薦在 linux
系統上使用 Nginx
,這會充分利用 linux
的特性,性能比在 windows
上會更好。css
本文主要內容:html
後續章節,我會使用 ab
壓測來一步一步優化 Nginx
的配置,Nginx 知道原理,懂得經常使用配置便可。有的性能優化須要瞭解 linux 內核
、http
、tcp
相關的東西,若是你不想了解,能夠記錄一份本身的配置便可,沒必要糾結爲何。java
本文內容在 nginx 1.16.1
上測試,Centos 7
4核 8g 內存的虛擬機。linux
根據 阿里 CentOS 鏡像 配置 yum
源,提升下載速度。webpack
阿里 epel 鏡像 配置咱們經常使用軟件的包,Nginx
也在其中。nginx
# 運行一下命令,更新 yum 源 yum clean all yum makecache
刷新 yum
倉庫信息以後,運行如下命令就能夠找到 nginx
web
yum list | grep nginx
安裝 nginx
正則表達式
sudo yum install nginx
配置 nginx
開機啓動json
sudo systemctl enable nginx
啓動 nginx
sudo systemctl start nginx
檢查 nginx
是否啓動
sudo systemctl status nginx
若是想查看 nginx
包都安裝了哪些文件,可使用
rpm -qvl nginx
# 強制當即關閉,不建議作 nginx -s stop # 正常關閉,會處理已經接到的請求,但不會接受新的請求 nginx -s quit # 從新加載配置文件 nginx -s reload # 從新打開日誌文件 nginx -s reopen # 檢查配置文件是否有誤 nginx -t # 檢查配置文件是否有誤,會將配置文件內容打印 nginx -T # 查看 nginx 版本 nginx -v # 查看 nginx 版本和編譯配置致殘 nginx -V
sudo systemctl enable nginx sudo systemctl start nginx sudo systemctl restart nginx sudo systemctl stop nginx sudo systemctl status nginx
部署的 Nginx
使用一個 master
進程管理多個 worker
進程。master
進程不處理請求,提供管理服務,包括啓動、中止、重載配置文件等服務,一般以 root
用戶啓動, worker
進程進行請求的處理,通常用非管理員帳戶啓用,worker
進程數量和 cpu 核心設置一直,下降進程切換帶來的 cpu
切換。
http
上下文中的配置是咱們重點須要知道的,其他的瞭解會配置便可。
http { include /etc/nginx/mime.types; default_type application/octet-stream; server { listen 80 ; server_name _; root /usr/share/nginx/html; location / { } } }
Server
既配置一個服務。
listen 80
用於配置監聽 80
端口的服務。
root
指定靜態資源存放的位置。
location 進行資源匹配。location / {}
匹配全部的資源。
listen
和 server_name
配置匹配規則:
listen
再匹配 server_name
server_name
匹配請求頭中的 Host
default_server
的處理server { listen 9099 default_server; server_name "localhost"; location / { return 200 "server_name 爲 localhost"; } } server { listen 9099; server_name 127.0.0.1; location / { return 200 "server_name 爲 127.0.0.1"; } } server { listen 9099; server_name "localhost77"; location / { return 200 "server_name 爲 localhost77"; } }
在 Postman
中設置請求頭 Host
模擬訪問。
http://localhost:9099
Host:127.0.0.1
返回 server_name 爲 127.0.0.1
http://localhost:9099
Host:localhost
返回 server_name 爲 localhost
http://localhost:9099
Host:localhost77
返回 server_name 爲 localhost77
http://localhost:9099
Host:localhost779
返回 server_name 爲 localhost
再添加一個配置
server { listen localhost:9099 default_server; server_name "localhost"; location / { return 200 "server_name 爲 localhost:9099"; } }
當 listen
訪問 localhost:9099
的時候,返回 server_name 爲 localhost:9099
,由於只有這一個匹配上了。
若是想禁止沒有 Host
請求頭的訪問。
server { listen 80; server_name ""; # 表示 nginx 會關閉鏈接 return 444; }
return
配置return
用於定義返回的狀態碼,或者內容。
介紹 return
主要是爲了好描述 location
配置
- | 說明 |
---|---|
語法 | return code [text];<br/>return code URL;<br/>return URL ; |
默認 | - |
上下文 | server、location、if |
code
爲狀態碼。text
爲字符串。
location /a { default_type application/json; return 200 "訪問 9088/a"; }
# 重定向 location = /b { return 301 http://www.baidu.com; }
location
配置location
用於匹配資源。
<font color=red>數字越小,優先級越高。</font>
規則符號 | 描述 | 優先級 |
---|---|---|
location = /a{} |
精準徹底匹配,匹配到以後 | 1 |
location ^~ /a{} |
前綴匹配,匹配到以後 | 2 |
location ~ /a.*{} | 正則匹配,區分大小寫,檢查到以後,還會檢查有沒有優先級跟高的 | 3 |
location ~* /a.* | 正則匹配,不區分字母大小寫,檢查到以後,還會檢查有沒有優先級跟高的 | 4 |
location /a {} | 也表示前綴匹配,可是優先級低於 正則匹配。 /a 和 ^~/a 會衝突,報錯 |
5 |
location / {} | 任何沒有匹配成功的,都會匹配這裏處理 | 6 |
server { listen 9088 default_server; server_name _ ; location = /a { default_type application/json; return 200 "= /a,優先級第一"; } location ^~ /a { default_type application/json; return 200 "^~ /a 匹配 /a 開頭的路徑,優先級第二"; } location ~ /a\.* { default_type application/json; return 200 " /a\.* 匹配 /a...路徑,優先級第三"; } location ~* /a\.* { default_type application/json; return 200 "~* /a\.* 匹配 /a...路徑,優先級第四"; } # /a 會和 ^~ /a 衝突 location /a/ { default_type application/json; return 200 "/a/ 匹配 /a/...路徑,優先級第五"; } }
訪問 http://localhost:9088/a
,依次註釋優先級較高的,能夠驗證這個規律。
還有一類特殊的 location
用於配置跳轉的,以 @
開頭
location @pass { }
- | 說明 |
---|---|
語法 | add_header name value [always]; |
默認 | - |
上下文 | http、server、location、location 中的 if |
若是響應代碼等於 200、20一、20四、20六、30一、30二、30三、30四、307或 308,則將指定的字段添加到響應報頭中。
加上 always
無論什麼狀態碼都加上。
location ~ /a\.* { default_type application/json; add_header test1 "asdfasdf" always; return 200 " /a\.* 匹配 /a...路徑,優先級第三"; }
- | 說明 |
---|---|
語法 | error_page code …[=[response code]] uri; |
默認 | - |
上下文 | http、server、location、location 中的 if |
配置錯誤狀態碼跳轉頁面。
error_page 404 /404.html; error_page 500 502 503 504 /50x.html;
以上不會改變響應狀態碼。
# 改變響應狀態嗎。 error_page 404 =200 /404.html;
server { location / { error_page 404 = @ops-coffee; } location @ops-coffee { rewrite .* / permanent; } }
alias
理解爲:路徑替換,location 以 /
結尾,alias 必須以 /
結尾。嚴格匹配。alias
替換掉 location
路徑。
# /bieming/ 替換 /usr/local/var/www/alias2/ # 訪問 /bieming/1.jpg 去尋找 /usr/local/var/www/alias2/1.jpg location /bieming/ { alias /usr/local/var/www/alias2/; }
root
理解爲:root 路徑加上 + location
路徑。會將兩個或更多個 /
壓縮成一個。
# 當 location 和 root 路徑的最後一部分匹配時,更好的方式是使用 root ## 如下配置均可以。 # 訪問 /data2/1.jpg 去尋找 /usr/local/var/www/data2/1.jpg location /data2/ { root /usr/local/var/www; } location /data2/ { root /usr/local/var/www/; } location /data2 { root /usr/local/var/www; } location /data2 { root /usr/local/var/www/; } location /data2/ { root /usr/local/var/www////; }
經過內置變量,咱們能夠經過判斷請求頭、query string
等值來轉發或者拒絕訪問。
$arg_name
獲取請求參數獲取請求query string
中的 name
參數。
location /arg/ { default_type application/json; return 200 "$arg_q1"; }
/arg/a?q1=334
返回的內容爲 334
。
$args
獲取請求 query_string
參數location /arg/ { default_type application/json; return 200 "$arg_q1 _ $args"; }
瀏覽器訪問 /arg/a?q1=3334&aa=2&bb=33
返回的內容爲 3334 _ q1=3334&aa=2&bb=33
$cookie_name
獲取cookie的值獲取請求中的名稱爲 name
的 cookie。
$http_name
獲取請求頭name
爲請求頭中的字段名稱,請求頭名稱所有小寫,並將破折號-
替換爲下劃線 _
$http_user_agent
獲取請求頭中的 User-Agent
字段。
$uri
獲取請求路徑中的 path
path
爲端口後面的路徑,不包括 query string
。優化以後的路徑,特殊字符轉譯及 /
壓縮。
http://localhost:8888/arg/a?q1=q1canshu&bb=2323
中的 path
爲 /arg/a
$host
獲取請求的 ip
首先會獲取請求頭 Host
,若是沒有請求頭中沒有 Host
請求頭,那麼獲取的是 url
中的 ip
。
$request_uri
獲取 path
和 query string
訪問 http://localhost:8888/arg/a/?q1=q1canshu&bb=2323
$request_uri
爲/arg/a/?q1=q1canshu&bb=2323
$scheme
獲取請求協議值爲 http
或 https
$request_method
獲取請求方法得到的值字母全大寫。GET,POST,DELETE,PUT 等
- | 描述 |
---|---|
$content_length |
獲取 Content-Length 請求頭字段。 |
$content_type |
獲取 Content-Type 請求頭字段 |
$https |
若是鏈接以 SSL 模式運行,則爲 on ,不然爲空字符串 |
$is_args |
若是請求行有參數則爲 ? ,不然爲空字符串 |
$pid |
獲取處理當前請求的 worker pid |
$nginx_version |
獲取 nginx 的版本 |
- | 說明 |
---|---|
語法 | if (condition ){} |
默認 | - |
上下文 | server、location |
指定的 condition 求值以後,若是爲 true ,則執行在大括號內指定的該模塊的指令,並在 if 指令內爲該請求分配配置。 if 指令內的配置繼承自上一層的配置級別。
condition 能夠是如下任何一種:
變量名,若是變量的值爲空字符串或 0 ,則爲 false
使用 = 和 != 運算符比較變量和字符串
使用 ~ (區分大小寫的匹配)和 ~* (不區分大小寫的匹配)運算符,變量將與正則表達式進行匹配。正則表達式能夠包含可供之後在 $1
..$9
變量中重用的捕獲。
反操做符 !~ 和 !~* 也可用。若是正則表達式包含 } 或 ; 字符,則整個表達式應使用單引號 或雙引號包圍起來。
使用 -f 和 !-f 運算符檢查文件是否存在
使用 -d 和 !-d 運算符檢查目錄是否存在
使用 -e 和 !-e 運算符檢查文件、目錄或符號連接是否存在
使用 -x 和 !-x 運算符檢查是否爲可執行文件
<font color=red>if
與小括號之間須要有空格</font>
location = /a { default_type application/json; if ($request_uri ~* "/(a).*") { return 200 "正則表達式捕獲的值:$1"; } return 200 "= /a,優先級第一"; }
- | 說明 |
---|---|
語法 | rewrite regex replacement [flag]; |
默認 | - |
上下文 | server、location、if |
flag
可選參數:
中止匹配,發送一個新的請求去匹配 location
。
中止匹配,在當前 location
去搜索資源。
臨時重定向。返回狀態碼 302
。
永久重定向。返回狀態碼 301
。
指定的 regex
能匹配,uri 將根據 replacement
來處理。
如下三張圖片都存在,可是內容不同。
/Users/zhangpanqin/stduy_app/break2/test/1.jpg
/Users/zhangpanqin/stduy_app/last2/test/1.jpg
/Users/zhangpanqin/stduy_app/test/1.jpg
location /break2 { root /Users/zhangpanqin/stduy_app/break2; rewrite /break2/(.*) /test/$1 break; } location /last2 { root /Users/zhangpanqin/stduy_app/last2; rewrite /last2/(.*) /test/$1 last; } location /test/ { root /Users/zhangpanqin/stduy_app; }
當訪問 /break2/1.jpg
實際匹配第一個 location
,而後在當前上下文處理 。
/break2/1.jpg
被替換爲 /test/1.jpg
來處理了,而後和 root
指定的路徑相結合,返回 /Users/zhangpanqin/stduy_app/break2/test/1.jpg
數據。
當訪問 /last2/1.jpg
,uri 被替換爲 /test/1.jpg
去匹配新的 location 進行處理。
返回 /Users/zhangpanqin/stduy_app/test/1.jpg
的內容。
redirect
和 permanent
location /redirect2 { rewrite ^/redirect2 http://www.baidu.com redirect; } location /permanent2 { rewrite ^/permanent2 http://www.baidu.com permanent; }
兩者匹配成功以後,都會改變瀏覽器地址欄地址。瀏覽器根據響應頭 Location
跳轉對應地址。
兩者的區別在於,永久重定向 (permanent
),瀏覽器會保存記錄,當再訪問 http://localhost:9088/permanent2
而不會詢問 nginx
直接跳轉。
臨時重定向,瀏覽器每次都要詢問 nginx
須要跳轉到哪裏。能夠關閉 nginx
就知道驗證結果了。
- | 說明 |
---|---|
語法 | try_files file … uri; <br/>try_files file … =code ; |
默認 | - |
上下文 | server、location |
以指定順序檢查文件是否存在,並使用第一個找到的文件進行請求處理。若是找不到內容內部轉發到最後一個參數 uri
。文件位置爲 root
+ file
。
location /try/ { root /usr/local/var/www/data2/data2/; try_files $uri $uri/ @pass2; } location @pass2 { default_type application/json ; return 200 "沒到到頁面代理的數據" ; }
訪問 /try/1.jpg
時,$uri
爲 /try/1.jpg
。
root
+ $uri
爲 /usr/local/var/www/data2/data2/try/1.jpg
找到返回,沒有找到繼續匹配返回。都沒有匹配內部轉發至 @pass2
。
如想驗證跳轉使用 /try/test
之類的,不要使用後綴名,由於使用後綴名的話,瀏覽器會返回 content-type
,致使內容與解析不一致,圖片出不來。
# 開啓 gzip gzip on; # 在響應頭中增長,Vary: Accept-Encoding gzip_vary on; # gzip壓縮級別1-9,數字越大壓縮效果越好,壓縮所用時間也就越長,佔用CPU越高 gzip_comp_level 6; # 申請內存時大小,若是源文件 9k,超過了 8K,那會申請 16*8K。 gzip_buffers 16 8k; gzip_min_length 2K; gzip_proxied any; gzip_disable "msie6"; gzip_http_version 1.1; # 文本(js、text、css、xml、json)壓縮比較好,圖片已經進行過壓縮,在壓縮,效果不是很明顯,還浪費 cpu gzip_types text/plain text/css text/xml text/javascript application/javascript application/json application/xml+rss application/rss+xml application/atom+xml image/svg+xml;
gzip 壓縮對文本效果比較好,推薦只對文本之類的壓縮。
爲了減輕服務器壓力,節省帶寬,能夠配置緩存。
memory cache
:它是將資源文件緩存到內存中,緩存有效直接從內存加載。
disk cache
: 它是將資源文件緩存到硬盤中,緩存有效直接從硬盤中加載。
先從 memory cache
找,找不到從 disk cache
找,再找不到,請求網絡資源。
緩存分爲 協商緩存
和 強緩存
。
協商緩存
每次都要去服務器詢問緩存是否過時,沒有過時使用本地的緩存。
強緩存
會有緩存過時時間,在有效期內不會去服務端校驗緩存,直接使用本地緩存。
如今的 webpack
能夠根據文件內容的 hash
生產相似 app.asdfa21342.js
這樣的文件。其實就是想使用強緩存,當網站更新,新的頁面會解析加載不同的資源,從而下降緩存校驗對服務器性能的損耗。
協商緩存有:ETag/if-None-Match
和 Last-Modified/if-Modify-Since
兩種。
http 協議規定,當這兩種響應頭都存在的時候,必須都要知足,才能使用緩存。
ETag/if-None-Match
- | 說明 |
---|---|
語法 | etag on|off; |
默認 | etag on; |
上下文 | http、server、location |
nginx
有個 etag 配置屬性,會給每一個靜態資源生成 Etag
響應頭,值爲文件內容 hash
。
當瀏覽器第一次訪問資源的時候,返回的響應頭中攜帶 Etag
。
後續的正常訪問(不強制刷新緩存)相同的資源,都會帶上請求頭 if-None-Match
,值爲 Etag
去 nginx
校驗是否同樣,同樣說明緩存沒有過時,返回狀態碼 304
,直接訪問瀏覽器中的緩存,不然從瀏覽器返回資源,返回狀態碼 200。
Last-Modified/if-Modify-Since
- | 說明 |
---|---|
語法 | if_modified_since off|exact|before; |
默認 | if_modified_since exact; |
上下文 | http、server、location |
指定如何比較文件的修改時間與請求頭 If-Modified-Since 進行比較:
忽略 If-Modified-Since 請求頭字段(0.7.34)
徹底匹配
資源的修改時間小於或等於 If-Modified-Since 請求頭字段中的時間
瀏覽器第一次訪問一個資源的時候,響應頭 Last-Modified
返回,標識文件的最後修改時間。
當瀏覽器再次正常訪問(不強制刷新資源)相同資源,請求頭會加上 If-Modified-Since
,該值爲以前返回的 Last-Modified
。nginx
收到 If-Modified-Since
後,根據配置 if_modified_since
屬性比較資源的最後修改時間(Last-Modified
)和該值If-Modified-Since
進行比較,匹配成功,則命中緩存,返回304,不然返回 資源,狀態碼爲 200,並更新緩存時間。
Expires
是 http1.0
的規範,它的值是一個絕對時間的GMT格式的時間字符串。這個時間表明的該資源的失效時間,若是在該時間以前請求的話,則都是從緩存裏面讀取的。若是服務端和客戶端時區不一致會致使判斷不許確。
Cache-Control
是 http1.1
的規範,它是利用該字段 max-age
值進行判斷的。該值是一個相對時間,好比 Cache-Control: max-age=3600
表明該資源的有效期是3600秒。除了該字段外,咱們還有以下字段能夠設置:
no-cache: 須要進行協商緩存,發送請求到服務器確認是否使用緩存。
**no-store:**禁止使用緩存,每一次都要從新請求數據。
**public:**能夠被全部的用戶緩存,包括終端用戶和 CDN 等中間代理服務器。
**private:**只能被終端用戶的瀏覽器緩存,不容許 CDN 等中繼緩存服務器對其緩存。
location ~* \.(css|js|png|jpg|jpeg|gif|gz|svg|mp4|mp3|ogg|ogv|webm|htc|xml|woff)$ { # 關閉訪問日誌記錄 access_log off; # 強緩存,時間爲一年,瀏覽器和 cdn 中間件能夠緩存 add_header Cache-Control "max-age=31536000"; }
推薦:值組詞