在《使用NGINX 和NGINX Plus 實現負載平衡(第1 部分)》中,我們設定了一個簡單的HTTP 代理程式來跨多台Web 伺服器對流量進行負載平衡。 本文將介紹NGINX Plus 具備的一些其他功能:透過keepalive、健康檢查、會話保持、重新導向及內容重寫來優化效能。
編按-NGINX Plus Release 5 及進階版本還可以對基於TCP 的應用進行負載平衡。Release 6 透過增添健康檢查、動態重新配置、SSL 終止等功能,顯著擴展了TCP 負載平衡。在NGINX Plus Release 7 及進階版本中,TCP 負載平衡器具備與HTTP 負載平衡器相同的功能。Release 9 中引入了對UDP 負載平衡的支援。
您可以在stream 上下文(而非http 上下文)中設定TCP 和UDP 負載平衡。 由於HTTP 和TCP/UDP 之間的固有差異,因此可用指令和參數略有不同。
快速回顧
回顧一下,這是我們在上一篇文章中建立的配置:
server {
listen 80;
location / {
proxy_pass http://backend;
# Rewrite the 'Host' header to the value in the client request,
# or primary server name
proxy_set_header Host $host;
# Alternatively, put the value in the config:
# proxy_set_header Host www.example.com;
}
}
upstream backend {
zone backend 64k; # Use NGINX Plus' shared memory
least_conn;
server webserver1 weight=1;
server webserver2 weight=4;
}
本文將介紹一些配置NGINX 和NGINX Plus 的簡單方法,以提高負載平衡效率。
HTTP keepalive
在NGINX 或NGINX Plus 與上游伺服器之間啟用HTTP keepalive 可提高效能(透過減少延遲),並降低NGINX 耗盡臨時連接埠的可能性。
HTTP 協定使用底層TCP 連線來傳送HTTP 請求並接收HTTP 回應。 HTTP keepalive 連接允許重複使用這些TCP 連接,從而避免了為每個請求建立和終止連接的開銷:
NGINX 是一個全代理,可獨立管理客戶端連線(前端keepalive 連線)和伺服器連線(上游keepalive 連線):
NGINX 會維護keepalive 連接的「快取」(一組與上游伺服器的空閒keepalive 連接),當需要將請求轉發到上游伺服器時,它會使用這些快取中已建立的keepalive 連接,而非創建新的TCP 連接。
這可減少NGINX 與上游伺服器之間的事務延遲,並降低臨時連接埠的使用率,因此NGINX 能夠處理大量流量並對其進行負載平衡。當流量激增時,這些快取會被清空,在這種情況下,NGINX 將與上游伺服器建立新的HTTP 連線。
對於其他負載平衡工具,該技術有時稱為「多路復用」、「connection pool」、「連接多工」或「OneConnect」。
您可透過將proxy_http_version、proxy_set_header 及keepalive 指令加入設定中來設定keepalive 連線快取:
server {
listen 80;
location / {
proxy_pass http://backend;
proxy_http_version 1.1;
proxy_set_header Connection "";
}
}
upstream backend {
server webserver1;
server webserver2;
# maintain up to 20 idle connections to the group of upstream servers
keepalive 20;
}
健康檢查
啟用健康檢查不僅能夠提高負載平衡服務的可靠性,降低最終用戶出錯率,而且還便於執行常見維護操作。
NGINX Plus 的健康檢查功能可用於偵測上游伺服器的故障。 NGINX Plus 使用「綜合事務」來偵測每台伺服器,並根據您在health_check 指令中配置的參數(以及新增match 參數的情況下,關聯的match 配置區塊)檢查回應:
server {
listen 80;
location / {
proxy_pass http://backend;
health_check interval=2s fails=1 passes=5 uri=/test.php match=statusok;
# The health checks inherit other proxy settings
proxy_set_header Host www.foo.com;
}
}
match statusok {
# Used for /test.php health check
status 200;
header Content-Type = text/html;
body ~ "Server[0-9]+ is alive";
}
健康檢查從上層location 區塊繼承一些參數。如果在配置中使用運行時變量,這可能會導致出現問題。例如,下列設定適用於實際HTTP 流量,因為它從客戶端請求中提取Host 請求頭的值。但此配置不適用於健康檢查所使用的綜合事務,因為未對這些事務設定Host 請求頭,這表示綜合事務中沒有使用Host 請求頭。
location / {
proxy_pass http://backend;
# This health check might not work...
health_check interval=2s fails=1 passes=5 uri=/test.php match=statusok;
# Extract the 'Host' header from the request
proxy_set_header Host $host;
}
一個好方法是建立一個虛擬location 區塊,以靜態定義健康檢查事務使用的所有參數:
location /internal-health-check1 {
internal; # Prevent external requests from matching this location block
proxy_pass http://backend;
health_check interval=2s fails=1 passes=5 uri=/test.php match=statusok;
# Explicitly set request parameters; don't use run-time variables
proxy_set_header Host www.example.com;
}
會話保持
透過會話保持,可以讓無法部署至叢集的應用也能實現負載平衡和可靠擴展。儲存和複製會話狀態的應用程式可以更有效率地運行,幫助提升最終用戶效能。
某些應用程式有時會將狀態資訊儲存到上游伺服器,例如當使用者將商品放入虛擬購物車或編輯上傳的圖片時。在這些情況下,您可能想要將來自該使用者的所有後續請求都導向到同一台伺服器。
會話保持指定了請求所須路由到的目標位置,而負載平衡則允許NGINX 自由選擇最佳上游伺服器。透過NGINX Plus 的會話保持功能,這兩個進程可以共存:
如果請求符合會話保持規則
那麼使用目標上游伺服器
否則應用負載平衡演算法選擇上游伺服器
如果會話保持決策因目標伺服器不可用而失敗,那麼NGINX Plus 會做出負載平衡決策。
最簡單的會話保持方法是「sticky cookie」方法,其中NGINX Plus 在第一個回應中插入一個cookie,用於識別sticky 上游伺服器:
sticky cookie srv_id expires=1h domain=.example.com path=/;
在另一種「sticky 路由」方法中,NGINX 會根據JSESSIONID cookie 等請求參數選擇上游伺服器:
upstream backend {
server backend1.example.com route=a;
server backend2.example.com route=b;
# select first non-empty variable; it should contain either 'a' or 'b'
sticky route $route_cookie $route_uri;
}
重寫HTTP 重定向
如果某些重定向被破壞,則您需要重寫HTTP 重定向,特別是當您從代理程式被重定向到真正的上游伺服器時。
當您代理到上游伺服器時,伺服器會在本機位址上發布應用,但您透過另一個位址(代理的位址)存取應用程式。這些地址通常解析為域名,如果伺服器和代理的域名不同,就會出現問題。
例如,在測試環境中,您可能直接(透過IP 位址)或按localhost 對代理程式進行尋址。但上游伺服器可能會監聽真實網域(例如www.nginx.com)。當上游伺服器發出重定向訊息(使用3xx 狀態碼和Location 請求頭,或使用Refresh 請求頭)時,訊息中可能包含伺服器的真實網域。
NGINX 會嘗試攔截並修正這種最常見的問題。如果您需要全權控制以執行特定重寫,請使用proxy_redirect 指令,如下所示:
proxy_redirect http://staging.mysite.com/ http://$host/;
重寫HTTP 回應
有時,您需要重寫HTTP 回應中的內容。也許,如上例所示,回應中包含指向代理以外其他伺服器的絕對連結。
您可以使用sub_filter 指令來定義要套用的重寫:
sub_filter /blog/ /blog-staging/;
sub_filter_once off;
一個很常見的問題是HTTP 壓縮的使用。如果客戶端發出訊號表示可以接受壓縮數據,而伺服器隨後壓縮了回應,那麼NGINX 就無法檢查和修改回應。最簡單的方法是將Accept-Encoding 請求頭設定為空字串(“”),從而將其從客戶端請求中刪除:
proxy_set_header Accept-Encoding "";
完整範例
下面是一個負載平衡配置模板,它使用了本文提到的所有方法。
[編者按-以下配置已更新為使用NGINX Plus API 對上游群組進行即時活動監控和動態配置,取代了最初使用的單獨模組。 ]
server {
listen 80;
location / {
proxy_pass http://backend;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_set_header Accept-Encoding "";
proxy_redirect http://staging.example.com/ http://$host/;
# Rewrite the Host header to the value in the client request
proxy_set_header Host $host;
# Replace any references inline to staging.example.com
sub_filter http://staging.example.com/ /;
sub_filter_once off;
}
location /internal-health-check1 {
internal; # Prevent external requests from matching this location block
proxy_pass http://backend;
health_check interval=2s fails=1 passes=5 uri=/test.php match=statusok;
# Explicitly set request parameters; don't use runtime variables
proxy_set_header Host www.example.com;
}
upstream backend {
zone backend 64k; # Use NGINX Plus' shared memory
least_conn;
keepalive 20;
# Apply session persistence for this upstream group
sticky cookie srv_id expires=1h domain=.example.com path=/servlet;
server webserver1 weight=1;
server webserver2 weight=4;
}
match statusok {
# Used for /test.php health check
status 200;
header Content-Type = text/html;
body ~ "Server[0-9]+ is alive";
}
server {
listen 8080;
root /usr/share/nginx/html;
location = /api {
api write=on; # Live activity monitoring and
# dynamic configuration of upstream groups
allow 127.0.0.1; # permit access from localhost
deny all; # deny access from everywhere else
}
}
若要試用NGINX Plus 中所有出色的負載平衡功能,請點擊此處立即下載30 天免費試用版。