NGINX 作為網頁伺服器和反向代理伺服器,其負載平衡和流量管理能力是建構高用性、高效能網路架構的關鍵。本文除了介紹基本的負載平衡方法,更探討了 NGINX Plus 提供的 Sticky Cookie、Sticky Learn 和連線耗盡等進階功能,讓讀者能更精細地控制流量分配。同時,文章也詳細說明瞭如何組態被動式和主動式健康檢查,確保後端伺服器的穩定性。此外,本文也介紹瞭如何利用 NGINX 進行 A/B 測試和使用 GeoIP 模組根據地理位置進行流量控制,提升網站的使用者經驗和營運效率。
NGINX 進階負載平衡技術解析
NGINX 提供多種負載平衡方法,能夠滿足不同場景下的需求。以下將探討 NGINX 的隨機負載平衡、IP Hash、以及 NGINX Plus 提供的 Sticky Cookie、Sticky Learn 和 Sticky Routing 等進階功能。
隨機負載平衡(Random Load Balancing)
隨機負載平衡是一種簡單有效的負載分配方法。NGINX 可以根據伺服器的權重隨機選擇一台伺服器來處理請求。此外,還可以指定隨機選擇兩台伺服器,然後使用指定的負載平衡方法在這兩台伺服器之間進行平衡。
upstream backend {
server backend1.example.com weight=3;
server backend2.example.com;
server backend3.example.com backup;
random two least_conn;
}
內容解密:
upstream backend定義了一個名為backend的伺服器群組。server指令定義了群組中的伺服器及其權重。random two least_conn指定了隨機選擇兩台伺服器,並使用最少連線數的負載平衡方法。
IP Hash 負載平衡
IP Hash 方法根據客戶端的 IP 地址進行雜湊計算,將請求分配到特定的伺服器。這種方法確保了來自同一客戶端的請求始終被分配到同一台伺服器,對於需要保持會話狀態的應用非常有用。
upstream backend {
ip_hash;
server backend1.example.com;
server backend2.example.com;
}
內容解密:
ip_hash指令啟用了 IP Hash 負載平衡方法。- 該方法根據客戶端 IP 地址的前三個八位位組(IPv4)或整個地址(IPv6)進行雜湊計算。
Sticky Cookie 與 NGINX Plus
NGINX Plus 提供了 Sticky Cookie 功能,可以建立並跟蹤一個 Cookie,將客戶端與特定的伺服器繫結。
upstream backend {
server backend1.example.com;
server backend2.example.com;
sticky cookie affinity expires=1h domain=.example.com httponly secure path=/;
}
內容解密:
sticky cookie指令建立並跟蹤一個名為affinity的 Cookie。expires=1h指定了 Cookie 的有效期為一小時。domain=.example.com指定了 Cookie 的作用域。httponly和secure屬性增強了 Cookie 的安全性。
Sticky Learn 與 NGINX Plus
Sticky Learn 功能允許 NGINX Plus 發現並跟蹤由上游應用建立的 Cookie,從而實作會話粘性。
upstream backend {
server backend1.example.com:8080;
server backend2.example.com:8081;
sticky learn create=$upstream_cookie_jsessionid lookup=$cookie_jsessionid zone=client_sessions:1m;
}
內容解密:
sticky learn指令啟用了 Sticky Learn 功能。create=$upstream_cookie_jsessionid指定了在上游伺服器的回應中查詢的 Cookie 名稱。lookup=$cookie_jsessionid指定了在客戶端請求中查詢的 Cookie 名稱。
連線耗盡(Connection Draining)與 NGINX Plus
連線耗盡功能允許 NGINX Plus 在維護或移除伺服器之前,停止向該伺服器傳送新的請求,同時允許現有的會話繼續完成。
$ curl -X POST -d '{"drain":true}' 'http://nginx.local/api/9/http/upstreams/backend/servers/0'
內容解密:
- 該命令透過 NGINX Plus API 將指定伺服器的
drain引數設為true,啟用連線耗盡功能。
被動式健康檢查(Passive Health Checks)
NGINX 可以透過被動式健康檢查來監控上游伺服器的健康狀態,確保只有健康的伺服器接收請求。
upstream backend {
server backend1.example.com:1234 max_fails=3 fail_timeout=3s;
}
內容解密:
max_fails=3指定了在將伺服器標記為不可用之前,允許的最大失敗次數。fail_timeout=3s指定了伺服器被標記為不可用後,多久後再次嘗試連線。
NGINX 健康檢查與負載平衡組態詳解
NGINX 是一款高效能的網頁伺服器與反向代理伺服器,廣泛應用於現代網路架構中。其強大的負載平衡功能使得多台伺服器能夠有效地分擔流量,從而提升系統的可靠性和效能。在負載平衡的組態中,健康檢查(Health Check)是確保後端伺服器健康狀態的重要機制。本文將探討 NGINX 中的健康檢查組態,包括被動式和主動式健康檢查,以及慢啟動(Slow Start)功能的應用。
被動式健康檢查(Passive Health Check)
被動式健康檢查是 NGINX 開源版本中預設的健康檢查方式,它透過監控客戶端請求的回應來評估後端伺服器的健康狀態。以下是一個範例組態:
upstream backend {
server backend1.example.com;
server backend2.example.com:1234 max_fails=3 fail_timeout=3s;
}
在這個組態中,max_fails 引數定義了在 fail_timeout 時間內允許的最大失敗次數。如果後端伺服器在 fail_timeout 時間內連續失敗 max_fails 次,則 NGINX 將該伺服器標記為不可用。
內容解密:
- max_fails=3:設定最大失敗次數為3次。
- fail_timeout=3s:設定失敗超時時間為3秒。 此組態能夠動態調整後端伺服器的狀態,確保客戶端請求不會被轉發到故障的伺服器上。
主動式健康檢查(Active Health Check)
主動式健康檢查是 NGINX Plus 的特色功能,能夠主動向後端伺服器傳送特定的請求,以檢查其健康狀態。對於 HTTP 服務,可以使用 health_check 指令進行組態:
http {
server {
location / {
proxy_pass http://backend;
health_check interval=2s fails=2 passes=5 uri=/ match=welcome;
}
}
match welcome {
status 200;
header Content-Type = text/html;
body ~ "Welcome to nginx!";
}
}
在這個例子中,NGINX 每2秒向後端伺服器的根 URI(/)傳送一次 GET 請求。如果連續5次檢查成功,則認為伺服器是健康的;如果連續2次檢查失敗,則認為伺服器不可用。
內容解密:
- interval=2s:每2秒進行一次健康檢查。
- fails=2:連續2次失敗則認為伺服器不可用。
- passes=5:連續5次成功則認為伺服器還原正常。
- uri=/ match=welcome:指定檢查的 URI 和匹配規則。
- match welcome:定義匹配規則,包括 HTTP 狀態碼、回應頭和回應體內容。
對於 TCP/UDP 服務,主動式健康檢查的組態類別似,但需要使用 stream 模組:
stream {
server {
listen 1234;
proxy_pass stream_backend;
health_check interval=10s passes=2 fails=3;
health_check_timeout 5s;
}
}
內容解密:
- interval=10s:每10秒進行一次健康檢查。
- passes=2:連續2次成功則認為伺服器健康。
- fails=3:連續3次失敗則認為伺服器不可用。
- health_check_timeout 5s:設定健康檢查的超時時間為5秒。
慢啟動(Slow Start)
慢啟動功能允許 NGINX 在將剛還原正常的後端伺服器重新加入負載平衡池時,逐漸增加其接收的請求數量。這樣可以避免伺服器突然接收大量請求而導致過載。以下是一個範例組態:
upstream backend {
zone backend 64k;
server server1.example.com slow_start=20s;
server server2.example.com slow_start=15s;
}
內容解密:
- slow_start=20s:server1.example.com 將在20秒內逐漸增加其接收的請求。
- slow_start=15s:server2.example.com 將在15秒內逐漸增加其接收的請求。
慢啟動功能僅在 NGINX Plus 中可用,並且不能與 hash、ip_hash 或 random 負載平衡方法一起使用。
流量管理
簡介
NGINX 也被歸類別為網路流量控制器。您可以利用 NGINX 根據多種屬性智慧地路由流量和控制流動。本章涵蓋了 NGINX 能夠根據百分比分割客戶端請求、利用客戶端的地理位置以及以速率、連線和頻寬限制的形式控制流量。在閱讀本章時,請記住您可以混合和匹配這些功能以實作無數可能性。
A/B 測試
問題
您需要在兩個或多個版本的檔案或應用程式之間分割客戶端,以測試接受度或參與度。
解決方案
使用 split_clients 模組將一定比例的客戶端導向不同的上游伺服器池:
split_clients "${remote_addr}AAA" $variant {
20.0% "backendv2";
* "backendv1";
}
split_clients 指令會對您提供的第一個引數進行雜湊處理,並根據提供的百分比對第二個引數所代表的變數進行對映。新增 “AAA” 到第一個引數是為了演示這是一個可以包含多個變數的串接字串。第三個引數是一個包含鍵值對的物件,其中鍵是百分比權重,值是要賦予的值。鍵可以是百分比或星號,星號表示在取所有百分比之後的剩餘部分。對於 20% 的客戶端 IP 位址,$variant 變數的值將是 “backendv2”,而對於剩餘的 80%,則是 “backendv1”。
在此範例中,“backendv1” 和 “backendv2” 代表上游伺服器池,可以與 proxy_pass 指令一起使用,如下所示:
location / {
proxy_pass http://$variant;
}
使用 $variant 變數,我們的流量將在兩個不同的應用伺服器池之間分割。
討論
這種 A/B 測試在測試不同型別的行銷和前端功能對於電子商務網站的轉換率時非常有用。應用程式通常使用一種稱為“金絲雀發布”的佈署方式,在這種方式中,流量會慢慢地切換到新版本,方法是逐漸增加被路由到新版本的使用者比例。在推出新版本的程式碼時,將客戶端分割到不同版本的應用程式之間,可以限制錯誤時的影響範圍。更常見的是藍綠佈署方式,使用者被切換到新版本,而舊版本仍然可用,以驗證佈署的有效性。無論是什麼原因,NGINX 都能讓您輕鬆地在兩個不同的應用程式集之間分割客戶端。
使用 GeoIP 模組和資料函式庫
問題
您需要安裝 GeoIP 資料函式庫並在其內嵌變數中使用於 NGINX,以便在 NGINX 日誌、代理請求或請求路由中使用客戶端的實際位置。
解決方案
官方的 NGINX Open Source 軟體套件儲存函式庫提供了名為 nginx-module-geoip 的套件。使用 NGINX Plus 軟體套件儲存函式庫時,此套件被命名為 nginx-plus-module-geoip。NGINX Plus 提供了一個適用於 GeoIP2 的動態模組,這是一個更新的模組,可以與 NGINX 的 stream 和 HTTP 一起使用。
以下範例顯示瞭如何安裝動態 NGINX GeoIP 模組套件,以及如何下載 GeoIP 國家和城市資料函式庫:
# 使用 YUM 安裝 NGINX Open Source 的 GeoIP 模組
$ yum install nginx-module-geoip
# 使用 APT 安裝 NGINX Open Source 的 GeoIP 模組
$ apt install nginx-module-geoip
# 使用 YUM 安裝 NGINX Plus 的 GeoIP 模組
$ yum install nginx-plus-module-geoip
# 使用 APT 安裝 NGINX Plus 的 GeoIP 模組
$ apt install nginx-plus-module-geoip
# 下載並解壓縮 GeoIP 資料函式庫
$ mkdir /etc/nginx/geoip
$ cd /etc/nginx/geoip
$ wget "http://geolite.maxmind.com/download/geoip/database/GeoLiteCountry/GeoIP.dat.gz"
$ gunzip GeoIP.dat.gz
$ wget "http://geolite.maxmind.com/download/geoip/database/GeoLiteCity.dat.gz"
$ gunzip GeoLiteCity.dat.gz
有了國家和城市的 GeoIP 資料函式庫儲存在本地磁碟上,您現在可以指示 NGINX GeoIP 模組使用它們來根據客戶端 IP 位址公開內嵌變數:
load_module modules/ngx_http_geoip_module.so;
http {
geoip_country /etc/nginx/geoip/GeoIP.dat;
geoip_city /etc/nginx/geoip/GeoLiteCity.dat;
# ...
}
load_module 指令從檔案系統上的路徑動態載入模組。geoip_country 指令接受一個指向包含將 IP 位址對映到國家程式碼的資料函式庫的 GeoIP.dat 檔案的路徑,並且僅在 http 上下文中有效。
詳細說明:GeoIP2 模組的使用
GeoIP2 模組可作為動態模組使用,並且可以在編譯 NGINX Open Source 時編譯進去。使用 NGINX Plus 時,可以安裝 nginx-plus-module-geoip2 模組來使用 GeoIP2 功能。
下載免費的 MaxMind GeoLite2 資料函式庫(需要註冊)。然後組態 NGINX 使用這些資料函式庫,並透過變數公開地理資訊。
load_module modules/ngx_http_geoip2_module.so;
load_module modules/ngx_stream_geoip2_module.so;
http {
# ...
}
NGINX GeoIP2 模組應用
NGINX 的 GeoIP2 模組提供了強大的地理位置資訊功能,能夠根據客戶端的 IP 地址判斷其來源國家、城市等資訊,並根據這些資訊進行流量控制、存取限制等操作。
GeoIP2 模組設定
要使用 GeoIP2 模組,首先需要安裝該模組並下載 MaxMind 的 GeoIP2 資料函式庫。以下是一個基本的設定範例:
http {
geoip2 /etc/maxmind-country.mmdb {
auto_reload 5m;
$geoip2_metadata_country_build metadata build_epoch;
$geoip2_data_country_code default=US source=$variable_with_ip country iso_code;
$geoip2_data_country_name country names en;
}
geoip2 /etc/maxmind-city.mmdb {
$geoip2_data_city_name default=London city names en;
}
fastcgi_param COUNTRY_CODE $geoip2_data_country_code;
fastcgi_param COUNTRY_NAME $geoip2_data_country_name;
fastcgi_param CITY_NAME $geoip2_data_city_name;
}
內容解密:
geoip2指令用於設定 MaxMind 資料函式庫的路徑。auto_reload 5m表示每 5 分鐘重新載入資料函式庫,以保持資料的新鮮度。$geoip2_data_country_code和$geoip2_data_country_name等變數用於儲存客戶端的國家程式碼和名稱等資訊。fastcgi_param指令將這些變數傳遞給後端應用程式。
根據國家限制存取
可以根據客戶端的國家程式碼來限制或允許存取。以下是一個範例:
http {
geoip2 /etc/maxmind-country.mmdb {
auto_reload 5m;
$geoip2_metadata_country_build metadata build_epoch;
$geoip2_data_country_code default=US source=$variable_with_ip country iso_code;
$geoip2_data_country_name country names en;
}
map $geoip2_data_country_code $country_access {
"US" 0;
default 1;
}
server {
if ($country_access = '1') {
return 403;
}
# 其他設定
}
}
內容解密:
map指令根據$geoip2_data_country_code的值設定$country_access變數。如果客戶端來自美國,則$country_access為 0,否則為 1。- 在
server區塊中,使用if指令檢查$country_access的值。如果為 1,則傳回 403 Forbidden 狀態碼,拒絕存取。
處理代理伺服器後的真實客戶端 IP
當 NGINX 後面有多層代理伺服器時,可以使用 geoip2_proxy 和 geoip2_proxy_recursive 指令來取得真實的客戶端 IP 地址。
http {
geoip2 /etc/maxmind-country.mmdb {
auto_reload 5m;
$geoip2_metadata_country_build metadata build_epoch;
$geoip2_data_country_code default=US source=$variable_with_ip country iso_code;
$geoip2_data_country_name country names en;
}
geoip2_proxy 10.0.16.0/26;
geoip2_proxy_recursive on;
# 其他設定
}
內容解密:
geoip2_proxy指令定義了代理伺服器的 IP 地址範圍,NGINX 將從X-Forwarded-For頭部中取得客戶端的真實 IP。geoip2_proxy_recursive on表示 NGINX 將遞迴地從X-Forwarded-For頭部中查詢最後一個客戶端 IP 地址。