寫給開發人員的Nginx秘籍

要問目前哪個Web伺服器最流行,可能大家都會說是Nginx。這個老毛子開發的神器憑藉高效能了、友好的配置、優秀的模組機制,反向代理支援迅速佔領市場並走上Web伺服器市場的No1。 本文我們就來談談對於開發人員來說Nginx的一些妙用方法。

寫給開發人員的Nginx秘籍

從這個簡單的配置,我們可以開始構建必要的複雜性。

主動/被動代理配置

如果服務需要以一臺伺服器為主的主動/被動配置 對於請求處理,將一個後端伺服器做備份,配置方法如下:

。。。

upstream backend {

server job:10000;

server backup:10000

backup

}

。。。

Backup選項指示,表示nginx將使用該伺服器為備用伺服器,只有當主伺服器(job。local:10000)不可用時候,才會代理到backup。local:10000。

預設情況下,伺服器在1次連線錯誤或超時後標記為不可用。但是該閾值可以透過max_fails來配置:

。。。

upstream backend {

# 主伺服器失敗嘗試3次

server job:10000 max_fails=3;

# 備用伺服器嘗試失敗次數10

server backup:10000 backup max_fails=10;

}

。。。

除了連線錯誤和超時,還可以使用HTTP 狀態碼,比如500,502等來定義不可用狀態。該配置,由

proxy_next_upstream

語句定義。

。。。

upstream backend {

server job:10000;

server backup:10000 backup;

}

server {

server_name proxy;

listen 8000;

# 在連線錯誤,超時或者http 429(請求超出)的時候時候,跳轉到下一個pstream。

proxy_next_upstream error timeout

http_429

location / {

proxy_pass http://backend;

}

}

。。。

代理K8s服務

如果要代理K8s叢集服務,由於其自帶負載均衡配置中應該設定max_fails=0,以免踢掉正常的伺服器:

。。。

upstream backend {

server cck8s。svc max_fails=0;

}

。。。

這樣nginx就不會將 K8s服務標記為不可用。即不會去嘗試做被動健康檢查,直接利用的K8s叢集的主動健康檢查。

靈活的路由 map

有時需要根據某些HTTP標頭值路由請求。比如查詢範圍、cookie值或、主機名或者他們的任意組合。這是Nginx最強大的地方,其他同類的代理基本上都做不到這一點。Nginx請求路由的關鍵是ngx_http_map_module。該模組允許從組合中定義變數帶有正則表示式的變數。假設微服務架構中有3個後端服務來處理不同型別的資料:

返回剛剛收集的最新資料的實時資料服務。

返回舊資料的歷史資料服務。

返回預先計算的資料的聚合資料服務。

這些服務透過相同的介面提供使用者服務,介面形式如下

。cc。api/?report=

現在有幾個使用者用例:

2021-04-01。cc。api/?report=list_records 應該提供歷史資料服務。

cc。api/?report=list_records 應該提供實時資料服務。

cc。api/?report=counters提供聚合資料服務。

2018-11-01。cc。api/?report=counters 提供歷史聚合資料服務。

如果自己在程式中自己寫路由則非常複雜,而用Nginx可以幫你透過很少配置就搞定:

首先,定義3個後端伺服器:

upstream live {

server live1:8000;

server live2:8000;

server live3:8000;

}

upstream hist {

server hist1:9999;

server hist2:9999;

}

upstream agg {

server agg1:7100;

server agg2:7100;

server agg3:7100;

}

接下來,定義將偵聽所有請求並以某種方式路由提供服務:

server {

server_name *。cc。api “”;

listen 80;

location / {

proxy_pass http://???;

}

}

問題是我們應該寫什麼proxy_pass指示?

由於nginx配置是宣告性的,可以編寫 proxy_pass http://$destination/並使用map構建目標變數。

示例服務中,根據report請求變數和日期子域名,提取到變數中的內容為:

map $host $date {

“~^((?\d{4}-\d{2}-\d{2})。)?cc。api$” $subdomain;

default “”;

}

Map會透過正則解析$host變數,並將解析結果設定$date。

此處主要使用了有2條map規則 :主要的規則是正則表示式,另一個是後備表示為default關鍵詞。

正則表示式子,我們不在詳細介紹,如果有興趣可以搜尋蟲蟲以前的文章。此處規則為^開頭,提取時間子域名:

\d{4}-\d{2}-\d{2}解析日期格式 2021-06-28。

被稱為捕獲組,它只是為匹配的部分命名正則表示式。然後在對映規則的右側使用捕獲組來分配。$date多變,而且子域是可選的,因此需要 用圓括號括起來(子域分隔符)並在整個組前新增?。

要提取report,無需使用map,nginx的arg_查詢引數的是預定義變數。 可以直接用$arg_report。

好的,有了日期report告。接著構建 $destination變數,用另一個map,訣竅是在後面map中可以利用上面的變數(包括自定義的)建立新變數的變數組合:

map “$arg_report:$date” $destination {

“~counters:。*” agg;

“~。*:。+” hist;

default live;

}

這裡的組合是一個字串,其中2個變數用冒號連線。冒號是個人選擇,用於方便。實際上可以使用任何符號,只要確保正則表示式是明確的。

在map,有3個規則。

首先是設定$destination到gg時report查詢引數是 counters。

二是設定 $destination到 hist時,$date變數不為空。

當沒有其他匹配時設定的預設值是設定$destination至 live。

map中的正則表示式按順序進行評估。

注意 $destinationvalue 是代理後端的名稱。

完整的配置如下:

events {}

http {

upstream live {

server live1:8000;

server live2:8000;

server live3:8000;

}

upstream hist {

server hist1:9999;

server hist2:9999;

}

upstream agg {

server agg1:7100;

server agg2:7100;

server agg3:7100;

}

map $host $date {

“~^((?\d{4}-\d{2}-\d{2})。)?cc。api$” $subdomain;

default “”;

}

map “$arg_report:$date” $destination {

“~counters:。*” agg;

“~。*:。+” hist;

default live;

}

server {

server_name *。cc。api “”;

listen 80;

location / {

proxy_pass http://$destination/;

}

}

}

轉發請求給Consul服務

如果使用Consul進行服務發現,則可以透過以下方式訪DNS。 簡單的

curl myapp。service。consul。

非常方便,但沒有人知道如何解析名稱 。consul zone。

無論如何,要透過 Consul DNS 在 nginx 中路由請求很一件。nginx有一個 resolver模組nginx 中用於使用自定義 DNS 伺服器的指令(注意就是最近爆嚴重漏洞的那個高危寫入漏洞的CVE-2021-23017的模組,記得升級哦)。

以下下面是配置Nginx轉發DNS請求給Consul配置:

。。。

server {

server_name *。cc。api “”;

listen 80;

# 解析使用Consul DNS。 遞迴請求到114和谷歌DNS。

resolver 10。0。0。1:8600 10。0。0。2:8600 10。0。0。3:8600 114。114。114。114 8。8。8。8

location /v1/api {

proxy_pass http://prod。cc。api。consul/;

}

location /v1/rpc {

proxy_pass http://prod。rpc。service。consul/;

}

}

。。。

結論

Nginx 是一個非常通用的工具。 它有豐富的配置語言為開發人員提供不錯的功能。比如具有配置故障轉移的主動/被動負載平衡、靈活的請求路由與Consul DNS 輕鬆整合等。雖然有些配置比較醜,甚至使用了可怕的正則,但是這也許就是他的魅力所在吧。