NGINX基本配置

xinyuan_java發表於2020-11-04

負載均衡是一種優化資源利用率、提升最大吞吐量、減少延遲、提高系統容錯率的常用技術。

要使用Nginx對一組伺服器的HTTP流量進行負載均衡,首先需要使用upstream定義一組後端伺服器(配置於http欄位中),然後使用server對upstream組中的服務進行配置(同樣配置於http欄位中,注意與定義虛服務的server欄位區分開)。

例如,如下配置定義了一組由3臺伺服器組成的名為backend的資源組:

 
  1. http {

  2. upstream backend {

  3. server backend1.example.com weight=5;

  4. server backend2.example.com;

  5. server 192.168.0.1 backup;

  6. }

  7. }

接下來可以使用proxy_pass指令(或者fastcgi_pass、memcached_pass、scgi_pass、uwsgi_pass,取決於所使用的協議)將http請求傳遞給後端服務組backend,配置如下:

 
  1. http {

  2. upstream backend {

  3. server backend1.example.com weight=5;

  4. server backend2.example.com;

  5. server 192.168.0.1 backup;

  6. }

  7. server {

  8. location / {

  9. proxy_pass http://backend;

  10. }

  11. }

  12. }

此配置即為一標準的反向代理,使用者向nginx傳送的http請求將被代理到backend中的三臺伺服器上,其中192.168.0.1為備用伺服器。因為upstream塊中未指定負載均衡演算法,所以將採用預設演算法:輪詢排程法。

負載均衡演算法的選擇

Nginx開源版本支援4種演算法,PLUS版又額外新增了兩種演算法。

1、輪詢法

請求按照權重平均分發給各個伺服器,這種演算法為預設演算法,無需額外定義:

 
  1. upstream backend {

  2. server backend1.example.com;

  3. server backend2.example.com;

  4. }

2、最小連線法

請求將被分發到當前活躍連線數最小的伺服器,同時將權重考慮在內:

 
  1. upstream backend {

  2. least_conn;

  3. server backend1.example.com;

  4. server backend2.example.com;

  5. }

3、IP雜湊法

根據IP地址來決定將請求分發到哪臺伺服器。此演算法將根據IPv4的前三個8位或者整個IPv6地址計算雜湊值,可確保來自同一IP的請求被分發到同一伺服器上(除非該伺服器不可用),可用於session保持。

 
  1. upstream backend {

  2. ip_hash;

  3. server backend1.example.com;

  4. server backend2.example.com;

  5. }

如果其中一臺伺服器需要臨時從負載均衡迴圈中刪除,可以使用down引數對其進行標記以保留客戶端IP地址的當前雜湊值。該伺服器的處理的請求將自動切換到組中下一臺伺服器:

 
  1. upstream backend {

  2. server backend1.example.com;

  3. server backend2.example.com;

  4. server backend3.example.com down;

  5. }

4、一般雜湊法

處理請求的伺服器由自定義key決定,該key可以是文字字串,也可以是變數或者兩者的組合,例如成對的IP地址和埠,或者是如下示例中的URI:

 
  1. upstream backend {

  2. hash $request_uri consistent;

  3. server backend1.example.com;

  4. server backend2.example.com;

  5. }

使用consistent引數將啟用ketama一致性負載均衡。根據使用者定義的雜湊鍵值,將請求平均分配到所有伺服器上。如果在upstream中新增或者刪減伺服器,則只會有少數鍵值會被重新對映,從而在負載均衡快取伺服器或其他狀態累計應用程式中最大程度地減少快取未命中。

5、最小延遲演算法(僅PLUS版支援)

對於每個請求,Nginx將選擇擁有最小平均延遲和最少活躍連線的伺服器進行處理。最低平均延遲將根據如下引數進行計算:

  • header——從伺服器接收到第一個位元組的時間
  • last_byte——從伺服器接收到完整響應的時間
  • last_byte inflight——從伺服器接收到完整響應的時間,將不完整請求考慮在內
 
  1. upstream backend {

  2. least_time header;

  3. server backend1.example.com;

  4. server backend2.example.com;

  5. }

6、隨機演算法(僅NGINX PLUS支援)

每個請求將被隨機傳遞給各個伺服器。two參數列示Nginx將在考慮權重的情況下隨機先擇兩臺伺服器,然後根據two後面指定的演算法從兩臺伺服器中選定一臺伺服器,支援的演算法如下:

  • least_conn
  • least_time=header
  • least_time=last_byte

上述三種演算法的含義已在上文解釋,不再贅述。

 
  1. upstream backend {

  2. random two least_time=last_byte;

  3. server backend1.example.com;

  4. server backend2.example.com;

  5. server backend3.example.com;

  6. server backend4.example.com;

  7. }

該演算法適用於多個負載均衡器共用一組後端伺服器的分散式環境中。對於負載均衡器擁有全量請求檢視的一般情景,請使用其他5種負載均衡演算法。

注意:upstream塊中指定負載時要放在server之前。

權重的含義

Nginx給每臺伺服器分配的預設權重為1,即在輪詢演算法排程下,請求將被平均分配給各個伺服器。而在下面的配置中:

 
  1. upstream backend {

  2. server backend1.example.com weight=5;

  3. server backend2.example.com;

  4. server 192.0.0.1 backup;

  5. }

backend1.example.com的權重被設定為5,這意味著,對於每6個請求,5個將被髮送給backend1.example.com,1個將被髮送給backend2.example.com。而192.168.0.1因為被指定為backup,將不參與排程,除非backend1.example.com和backend2.example.com均不可用。

慢啟動

“慢啟動(slow_start)”引數可以給從故障中恢復的節點加入排程佇列一個緩衝時間,防止剛恢復的節點因訪問超時而再次被標記為故障。此特性適用於Nginx PLUS版。

在Nginx PLUS版中,慢啟動可以讓upstream中的節點權重在其恢復後逐漸從0恢復到正常權重,此功能通過為server新增slow_start引數實現:

 
  1. upstream backend {

  2. server backend1.example.com slow_start=30s;

  3. server backend2.example.com;

  4. server 192.168.0.1 backup;

  5. }

引數30s表示backend1.example.com在恢復可用的30秒後,接收的連線數達到正常值。

注意:如果upstream中只有一臺伺服器,那麼max_fails、fail_timeout、slow_start這些引數都會被忽略,即Nginx將這臺唯一的伺服器視為可用的。

啟用會話保持

此功能僅適用於Nginx PLUS。會話保持意味著Nginx可以識別使用者會話,並將該會話的所有請求路由到一臺指定伺服器上。

Nginx PLUS支援3種會話保持方法,可通過sticky引數進行指定。(如果使用的是開源版Nginx,可以使用IP雜湊或一般雜湊法實現會話保持)

1、sticky cookie

Nginx PLUS為來自upstream組的第一個響應新增一個會話cookie,並標記傳送該響應的伺服器。攜帶此cookie值的下一客戶端響應將被Nginx PLUS路由到這個被標記的伺服器。

 
  1. upstream backend {

  2. server backend1.example.com;

  3. server backend2.example.com;

  4. sticky cookie srv_id expires=1h domain=.example.com path=/;

  5. }

上例中,srv_id設定了cookie的名稱,expires設定cookie了過期時間(即經過多久後瀏覽器就不再將此cookie傳送給伺服器),domain設定了cookie的作用域,path設定了cookie的作用路徑。sticky cookie是最簡單的會話保持方法。

2、sticky route

Nginx PLUS在收到第一個請求時為此客戶端分配一個“路由”,所有後續的請求將與server指令的route引數進行比較,來決定將請求代理到哪臺伺服器。路由資訊取自cookie或者請求URI。

 
  1. upstream backend {

  2. server backend1.example.com route=a;

  3. server backend2.example.com route=b;

  4. sticky route $route_cookie $route_uri;

  5. }

3、sticky learn

Nginx PLUS首先通過分析server的響應來找到會話識別符號,然後學習哪個server對應哪個會話識別符號。通常,這些識別符號通過HTTP cookie進行傳遞。如果請求包含的會話識別符號已經被學習了,那麼Nginx就會將請求轉發給相應的伺服器:

 
  1. upstream backend {

  2. server backend1.example.com;

  3. server backend2.example.com;

  4. sticky learn

  5. create=$upstream_cookie_examplecookie

  6. lookup=$cookie_examplecookie

  7. zone=client_sessions:1m

  8. timeout=1h;

  9. }

上例中,upstream的一個節點通過在響應中設定“EXAMPLECOOKIE” cookie建立一個會話,帶有此cookie的後續請求將被轉發給該節點,如果該節點無法處理請求,則視為客戶端尚未進行繫結,Nginx將重新選擇一個節點來處理請求。

create引數(不可預設)定義一個變數來指定如何建立新會話。在上例中,新會話是根據upstream中server傳送的“EXAMPLECOOKIE” cookie建立。

lookup引數(不可預設)定義如何搜尋已經存在的會話。在上例中,已經存在的會話是根據客戶端傳送的“EXAMPLECOOKIE”cookie進行搜尋的。

zone引數(不可預設)定義一塊儲存所有會話資訊的記憶體區域(在Nginx側)。在上例中,此記憶體區域名為client_sessions,大小為1MB(在64位系統中,1MB大約可以儲存4000個會話資訊)。

timeout引數定義多長時間內未被訪問的會話將從zone中刪除,該值預設為10分鐘。上例中,此時間為1小時。

這種會話保持方法相比前兩種更為複雜,它不在客戶端側儲存任何cookie,所有的資訊都被儲存在服務側的共享記憶體區域中。

如果叢集中有多個Nginx例項使用了sticky learn方法,可以將其共享記憶體區域的內容進行同步,條件是:

  • 1、zone名稱相同
  • 2、每個例項都配置了zone_sync功能
  • 3、sticky learn中指定了sync引數
 
  1. upstream backend {

  2. server backend1.example.com;

  3. server backend2.example.com;

  4. sticky learn

  5. create=$upstream_cookie_examplecookie

  6. lookup=$cookie_examplecookie

  7. zone=client_sessions:1m

  8. timeout=1h;

  9. sync;

  10. }

限制連線數

Nginx PLUS中,可以使用max_conns引數來限制server的連線數量。如果server的連線數量達到了限制值,則請求將被置於佇列中以等待進一步處理。

 
  1. upstream backend {

  2. server backend1.example.com max_conn=3;

  3. server backend2.example.com;

  4. queue 100 timeout=70;

  5. }

如果佇列也滿了(上例中佇列可存放100個請求),或者timeout指定的時間內Nginx仍未能選擇到可用的server,那麼客戶端就會收到報錯。

多個worker process共享資料

如果upstream塊中未包含zone指令,則每個worker process都會儲存自己的伺服器組配置副本,並維護自己的一組計數器。計數器包括與upstream組中每個伺服器的當前連線數以及請求傳遞給伺服器的失敗嘗試次數。那麼,伺服器組的配置將無法動態更新。

如果upstream塊中定義了zone,那麼伺服器組的配置將被儲存在多個worker process共享的一個記憶體區域中。此方案是可動態配置的,因為每個worker process訪問的是同一個組配置副本,並且使用的是相同的計數器。

zone引數對於主動健康檢查和upstream組的動態配置更新是必須的,而且upstream組的其他功能也可從中受益。

例如,如果一個組的配置不是共享的,每個worker process都維護自己的嘗試請求失敗計數器(通過max_fails引數設定)。在這種情況下,每個請求僅達到一個worker process,當被選擇用來處理此請求的worker process無法將請求給後端的某個伺服器時,其他的worker process對此一無所知。這就造成儘管部分worker process認為一個server不可用,其他worker process仍然會向該server傳送請求。server確定不可用的條件是在fail_timeout定義的時間內請求失敗的次數必須達到max_fails*worker process的數量。如果我們配置了zone,server確定不可用的條件才會變成在fail_timeout定義的時間內請求失敗次數達到max_fails,這才是我們想要的效果。

相似的,如果不設定zone,至少在低負載情況下,基於最小連線的負載均衡方法將不按預期工作。此種負載均衡將請求傳送給當前活躍連線數最小的伺服器,如果組配置不是共享的,每個worker process使用的都是自己的連線數計數器,那個很可能會把請求傳送給另一個worker process剛剛發過請求的伺服器上。在高負載情況下,請求在work process見均勻分配,最小連線負載均衡法就可以按預期工作。

設定zone的大小

由於使用模式差異巨大,因此不可能推薦一個通用的理想值。所需的記憶體大小取決於啟用了那些功能(例如會話保持、健康檢查、DNS重解析)以及upstream的定義方式。

例如,在一個使用了sticky_route會話保持且啟用了健康檢查的案例中,一個256KB的zone可以維護如下數量的server資訊:

  • 128個節點(每個以IP:port形式定義)
  • 或者88個節點(每個以hostname:port形式定義,且每個域名解析到單個IP地址)
  • 或者12個節點(每個以hostname:port形式定義,且每個域名解析到多個IP地址)

使用DNS配置HTTP負載均衡

server組的配置可以使用DNS在執行時進行修改。

對於upstream中使用域名標識的server,Nginx PLUS可以監控DNS解析記錄的變化,並自動將變化應用到負載均衡排程組中,而無需重啟。實現方式是在http塊中引入resolver指令,並在server後面新增resolve引數。

 
  1. http {

  2. resolver 10.0.1 valid=300s ipv6=off;

  3. resolver_timeout 10s;

  4. server {

  5. location / {

  6. proxy_pass http://backend;

  7. }

  8. upstream backend {

  9. zone backend 32k;

  10. least_conn;

  11. # ...

  12. server backend1.example.com resolve;

  13. server backend2.example.com resolve;

  14. }

  15. }

上例中,server後的resolve引數指示Nginx PLUS週期性地重解析backend1.example.com和backend2.example.com為IP地址。

resolver指令定義了DNS伺服器地址(10.0.0.1),Nginx PLUS預設以TTL(生存時間值)指定的頻率重解析DNS記錄,我們可以使用valid引數指定TTL值,上例中該值為300s。
ipv6=off表示負載均衡僅使用IPv4地址。Nginx預設是既支援IPv4也支援IPv6的。

如果一個域名被解析為多個IP地址,地址將會被儲存到upstream配置中並進行負載均衡。如果IP列表發生了變更,則Nginx PLUS會立即基於新的地址列表進行負載均衡。

Microsoft Exchange Server的負載均衡

在Nginx PLUS R7或更高版本中,Nginx PLUS還可以代理Microsoft Exchange Server的流量,並進行負載均衡。

配置步驟如下:

1、location塊中配置proxy_pass,代理到Microsoft Exchange Server服務組:

 
  1. location / {

  2. proxy_pass https://exchange;

  3. # ...

  4. }

2、location塊中配置proxy_http_version為1.1,配置proxy_set_header為Connection “”:

 
  1. location / {

  2. # ...

  3. proxy_http_version 1.1;

  4. proxy_set_header Connection "";

  5. # ...

  6. }

3、在upstream塊中新增ntml指令,以使組中伺服器接受帶有NTML驗證的請求:

 
  1. http {

  2. # ...

  3. upstream exchange {

  4. zone exchange 64k;

  5. ntml;

  6. # ...

  7. }

  8. }

4、新增server組:

 
  1. http {

  2. #...

  3. upstream exchange {

  4. zone exchange 64k;

  5. ntml;

  6. server exchange1.example.com;

  7. server exchange2.example.com;

  8. # ...

  9. }

  10. }

完整配置如下:

 
  1. http {

  2. # ...

  3. upstream exchange {

  4. zone exchange 64k;

  5. ntml;

  6. server exchange1.example.com;

  7. server exchange1.example.com;

  8. }

  9. server {

  10. listen 443 ssl;

  11. ssl_certificate /etc/nginx/ssl/company.com.crt;

  12. ssl_certificate_key /etc/nginx/ssl/company.com.key;

  13. ssl_protocols TLSv1 TLSv1.1 TLSv1.2;

  14.  
  15. location / {

  16. proxy_pass https://exchange;

  17. proxy_http_version 1.1;

  18. proxy_set_header Connection "";

  19. }

  20. }

  21. }