1. 程式人生 > >Nginx - upstream 模塊及參數測試

Nginx - upstream 模塊及參數測試

逗號 sleep 算法 不同的 ont time_c cache har 怎麽

目錄

- 1. 前言
- 2. 配置示例及指令說明
- 2.1 配置示例
- 2.2 指令
- 2.3 upstream相關變量
- 3. 參數配置及測試
- 3.1 max_fails 和 fail_timeout
- 3.2 proxy_next_upstream
- 3.3 nginx 與後端web連接時間的三個參數

1. 前言

  當 Nginx 作為反向代理使用的時候,upstream模塊有著舉足輕重的地位,官方解釋:

  技術分享圖片

2. 配置示例及指令說明

2.1 配置示例

技術分享圖片

2.2 指令

指令名稱: upstream

語法:upstream name { … }
默認值:none
使用環境:http
功能:該指令是一個組合型指令它描述了一組服務器,這組服務器將會被指令 proxy_pass 和 fastcgi_pass 作為一個單獨的實體使用,它們可以將 server 監聽在不同的端口,而且還可以同時使用TCP和UNIX套接字監聽。服務器可以設置不同的權重,如果沒有設置權重,那麽默認會將其設置為 1 。

指令名稱: ip_hash
語法:ip_hash
默認值:none
使用環境:upstream
功能:如果使用了該指令,那麽將會導致客戶端的請求以用戶端IP地址分布在 upstream 中的 server 之間。它的關鍵技術在於對這個請求客戶端IP地址進行哈希計算,這種方法保證了客戶端請求總是能夠傳遞到同一臺後臺服務器,但是如果該服務器被認定為無效,那麽這個客戶端的請求將會被傳遞到其他服務器,因此,這種機制是一個高概率將客戶端請求總是連接到同一臺服務器。

Nginx 的 upstream 支持 5 種分配方式,其中有三種為 Nginx 原生支持的分配方式,後兩種為第三方支持的分配方式。

  1. 輪詢。upstream默認采用的就是輪詢方式.
  2. 權重(weight)輪詢模式的加強版,每個後端server 默認 weight=1
  3. ip_hash 每個請求按照訪問IP的hash結果分配這樣每個訪客會固定訪問一個後端服務器,可以解決session 一致問題
  4. fair 第三方分配方式。平地按照後端服務器的響應時間(rt)來分配請求,響應時間短即rt小的後端服務器優先分配請求。如果需要使用這種調度算法,必須下載Nginx的upstr_fair模塊。
  5. url_hash 平地按照後端服務器的響應時間(rt)來分配請求,響應時間短即rt小的後端服務器優先分配請求。如果需要使用這種調度算法,必須下載Nginx的upstr_fair模塊。

指令名稱: server
語法:server name [parameters]
默認值:none
使用環境:upstream
功能:該指令用於設置服務器的 name,對於 name,可以使用域名、ip地址、端口或是 UNIX 套接字,如果一個域名被解析到多個 IP 地址,那麽所有的 IP 地址都將會被使用。
可選的 parameters 如下:

  • weight=NUMBER 用於設置服務器的權重。如果沒有設置,那麽它將會等於 1
  • max_fails=NUMBER 該參數用於對後端服務器進行檢測,如果達到 NUMBER 次數依然失敗,則該 server 會被暫停 fail_timeout 秒,如果沒有設置該參數,那麽嘗試的次數為1,如果設置為 0 則關閉檢測。失敗的依據是根據 proxy_next_upstream 提供的。
  • fail_timeout=TIME 該參數用於設置客戶端到達 max_fails 次數後,該server 被暫停的時間。如果沒有設置該參數,那麽默認為 10秒。
  • down:如果為某一個 server 設置了該參數,那麽標記了這臺 server 將永久離線。通常這個參數與 ip_hash 一同使用。
  • backup:該參數在 0.6.7 版本中提供,它是一個備用標識,如果出現所有的非備份服務器全部宕機或繁忙無法接受連接時,那麽才會使用本服務器,該參數無法和 ip_hash 指令一起使用。

2.3 upstream相關變量

變量名:$upstream_addr
功能:該變量表示了處理該請求的 upstream 中 server 的地址

變量名:$upstream_cache_status
功能:該變量出現在 Nginx 0.8.3 版本中, 可能的值如下:

  • MISS - 緩存中未被命中
  • EXPIRED - 生存期期滿,請求被傳遞到後端服務器
  • UPDATING - 生存期滿,陳舊的響應被使用,因為proxy/fastcgi_cache_use_stale 升級
  • STALE - 生存期期滿,陳舊的響應被使用,因為 proxy/fastcgi_cache_use_stale
  • HIT - 緩存命中

變量名:$upstream_status
功能:該變量為 upstream 中 server 的響應狀態

變量名:$upstream_response_time
功能:upstream server 響應的時間,單位為秒,能夠精準到毫秒。如果有多個 server 響應回答,那麽會用逗號和冒號分隔開

變量名:$upstream_http_$HEADER
功能:HTTP 協議頭。例如:$upstream_http_host

3. 參數配置及測試

參數相關說明介紹完畢,接下來重點測試部分參數:

max_fails 、fail_timeout 、proxy_next_status

1臺反向代理(nginx/1.14.2)
2臺後端web(apache+php)

技術分享圖片

首先,查看客戶端 發起一次 連接請求的過程:

技術分享圖片

通過抓包,可以看到 瀏覽器 請求一次 nginx 反向代理:

  • (9、10、11) 客戶端 -> nginx TCP 三次握手成功
  • (12、13)12. 瀏覽器發起 GET 請求 13. 回復 ACK
  • (14、15、16)nginx -> 後端web服務 三次握手成功
  • (17、18) nginx 向後端web服務發起 get 請求, web服務ACK回復nginx
  • (19、20) 後端web服務返回請求數據給 nginx (這裏返回HTTP狀態為 304 Not Modified)
  • (21、22)nginx 連接後端服務采用的是HTTP1.0 ,後端服務主動發送FIN主動斷開連接,後端web服務器從ESTABLISHED轉為 TIME_WAIT
  • (23)nginx 將後端返回的結果,再返回給客戶端瀏覽器

3.1 max_fails 和 fail_timeout

max_fails - 檢測出錯的次數。
fail_timeout - 出錯後,暫停server的時間。

配置如下圖:

技術分享圖片

主機信息:

nginx: 192.168.118.15
web1: 192.168.118.16
web2: 192.168.118.17

(1)當 max_fails 為 0 , fail_timeout 為 0

已知,upstream默認采用輪詢的方式,web2服務關閉

技術分享圖片

通過瀏覽器快速刷新4次,分析如下:

首先查看 nginx 日誌:

技術分享圖片

一共發起了 4 次連接請求,根據 upstream默認輪詢方式,有兩次都輪詢到了 192.168.118.17 (服務關閉)上。

查看 web1(192.168.118.16)日誌:

技術分享圖片

一共發起了 4 次請求,而 web1 接收到了 4 次,也就是這 4 次請求,都是 web1 來響應的。

為什麽 4 次請求都是 web1 響應的呢?

技術分享圖片

通過上圖,當 nginx 首次輪詢到 web2 時,連接失敗,web2 返回 RST,nginx會再次發起請求到 web1 。

總結:
max_fails = 0 and fail_timeout = 0 時,後端服務故障時,依然會輪詢到故障主機,且沒有暫停服務時間的限制。

(2) max_fails = 0 and fail_timeout = 5

已知,upstream默認采用輪詢的方式,web2服務關閉, 配置如下:

技術分享圖片

通過瀏覽器快速刷新,分析如下:

nginx 日誌

技術分享圖片

通過錯誤日誌可以看出,當 upstream 沒有設置 最大錯誤數(max_fails),無論後端server是否有效,都會輪詢到該server上,fail_timeout 設置任何值都是無效的。

(3) max_fails = 3 and fail_timeout = 5

已知,upstream默認采用輪詢的方式,web2服務關閉, 配置如下:

技術分享圖片

通過瀏覽器快速刷新,分析如下:

nginx 日誌

技術分享圖片

通過配置最大失敗連接數為 3 時,當後端web2服務關閉後,nginx首次會嘗試 max_fails 次,如果仍然沒響應,則暫停該server fail_timeout 秒,然後每隔 fail_timeout 時間後嘗試一次,失敗則繼續暫停 fail_timeout 秒。

(4) max_fails = 3 and fail_timeout = 0

這種方式和 max_fails = 0 and fail_timeout = 3 測試結果一致,不在舉例。

通過上面 max_fails 和 fail_timeout 測試,當要實現失敗後暫停服務時,max_fails 和 fail_timeout 任何一項都不能為 0 。

在測試中,無論怎麽刷新,nginx總是能夠返回正常服務的server 數據,這是為什麽?明明已經輪詢到服務失效的節點,這裏並沒有定義任何的 proxy_next_upstream

解釋:

針對nginx負載均衡upstream容錯機制的使用說明

(1)nginx 的 upstream 容錯

Nginx默認判斷失敗節點狀態是以 和 timeout (上面的例子就為web2-timeout)狀態為準,不以HTTP錯誤狀態進行判斷失敗,因為HTTP只要能返回狀態說明該節點還可以正常連接,除非添加了proxy_next_upstream指令設置對404、502、503、504、500和time out等錯誤進行轉到備機處理。在next_upstream過程中,會對fails進行累加,如果備用機處理還是錯誤則直接返回錯誤信息(但404不進行記錄到錯誤數,如果不配置錯誤狀態也不對其進行錯誤狀態記錄)綜述,nginx記錄錯誤數量只記錄timeout 、connect refuse、502、500、503、504這6種狀態,timeout和connect refuse是永遠被記錄錯誤狀態,而502、500、503、504只有在配置proxy_next_upstream後nginx才會記錄這4種HTTP錯誤到fails中,當fails大於等於max_fails時,則該節點失效;

(2)nginx 處理節點失效和恢復的觸發條件

nginx可以通過設置max_fails(最大嘗試失敗次數)和fail_timeout(失效時間,在到達最大嘗試失敗次數後,在fail_timeout的時間範圍內節點被置為失效,除非所有節點都失效,否則該時間內,節點不進行恢復)對節點失敗的嘗試次數和失效時間進行設置,當超過最大嘗試次數,則失效fail_timeout 時間,nginx每隔 fail_timeout時間嘗試一次後端server 有沒有恢復,直到所有後端服務失效,則返回錯誤頁面給客戶端;

(3)所有節點失效後 nginx 將重新恢復所有節點進行探測

如果探測所有節點均失效,備機也為失效時,那麽nginx會對所有節點恢復為有效,重新嘗試探測有效節點,如果探測到有效節點則返回正確節點內容,如果還是全部錯誤,那麽繼續探測下去,當沒有正確信息時,節點失效時默認返回狀態為502,但是下次訪問節點時會繼續探測正確節點,直到找到正確的為止。

(4)通過proxy_next_upstream實現容災和重復處理問題

ngx_http_proxy_module 模塊中包括proxy_next_upstream指令
語法: proxy_next_upstream error | timeout | invalid_header | http_500 | http_502 | http_503 | http_504 |http_404 | off ...;
默認值: proxy_next_upstream error timeout;
上下文: http, server, location

error                   表示和後端服務器建立連接時,或者向後端服務器發送請求時,或者從後端服務器接收響應頭時,出現錯誤
timeout                 表示和後端服務器建立連接時,或者向後端服務器發送請求時,或者從後端服務器接收響應頭時,出現超時
invalid_header          表示後端服務器返回空響應或者非法響應頭
http_500                表示後端服務器返回的響應狀態碼為500
http_502                表示後端服務器返回的響應狀態碼為502
http_503                表示後端服務器返回的響應狀態碼為503
http_504                表示後端服務器返回的響應狀態碼為504
http_404                表示後端服務器返回的響應狀態碼為404
off                     表示停止將請求發送給下一臺後端服務器


運用場景:

1)proxy_next_upstream http_500 | http_502 | http_503 | http_504 |http_404;

當其中一臺返回錯誤碼404,500...等錯誤時,可以分配到下一臺服務器程序繼續處理,提高平臺訪問成功率,多可運用於前臺程序負載設置

2)proxy_next_upstream off

因為proxy_next_upstream 默認值: proxy_next_upstream error timeout;

場景:

當訪問A時,A返回error timeout時,訪問會繼續分配到下一臺服務器處理,就等於一個請求分發到多臺服務器,就可能出現多次處理的情況,如果涉及到充值,就有可能充值多次的情況,這種情況下就要把proxy_next_upstream關掉即可
proxy_next_upstream off

案例分析(nginx proxy_next_upstream導致的一個重復提交錯誤):
一個請求被重復提交,原因是nginx代理後面掛著2個服務器,請求超時的時候(其實已經處理了),結果nigix發現超時,有把請求轉給另外臺服務器又做了次處理。

解決辦法:

proxy_next_upstream:off

3.2 proxy_next_upstream

語法: proxy_next_upstream error | timeout | invalid_header | http_500 | http_502 | http_503 | http_504 |http_404 | off ...;
默認值: proxy_next_upstream error timeout;
上下文: http, server, location

接下來,測試 proxy_next_upstream 是否能夠定義失敗的標準:

技術分享圖片

技術分享圖片
<?php
header(‘RS:Web1‘);
$t = 1;
sleep($t);
echo "sleep {$t}s<br>";
echo "web-1<br>";
?>
web1 - sleep 1秒 技術分享圖片
<?php
header(‘RS:Web2‘);
header(‘http/1.1 500 Internal Server Error ‘);
#$t = 5;
#sleep($t);
echo "sleep {$t}s<br>";
echo "web-2<br>";
?>
web2 - 返回 500 狀態碼

nginx配置如下:

技術分享圖片

upstream 默認後端server失效標準: timeout 和 Connect refuse,在這裏例子中,使用

proxy_next_upstream http_500 http_502 http_504
[root@localhost ~]# curl -I -w %{time_total}:%{time_connect}:%{time_starttransfer} http://192.168.118.15/test.php
HTTP/1.1 200 OK
Server: nginx/1.14.2
Date: Thu, 14 Mar 2019 10:53:51 GMT
Content-Type: text/html; charset=UTF-8
Connection: keep-alive
X-Powered-By: PHP/5.4.16
RS: Web1

1.006:0.000:1.006

三次都是返回 200 狀態,說明 proxy_next_upstream 已經將後端server 返回 500 狀態的主機攔截為失效。

3.3 nginx 與後端web連接時間的三個參數

proxy_connect_timeout :後端服務器連接的超時時間_發起握手等候響應超時時間
proxy_read_timeout:連接成功後,等候後端服務器響應時間_其實已經進入後端的排隊之中等候處理(也可以說是後端服務器處理請求的時間)
proxy_send_timeout :後端服務器數據回傳時間_就是在規定時間之內後端服務器必須傳完所有的數據

這裏對 proxy_read_timeout 進行測試:

nginx 配置:

技術分享圖片

技術分享圖片
<?php
header(‘RS:Web1‘);
$t = 3;
sleep($t);
echo "sleep {$t}s<br>";
echo "web-1<br>";
?>
web1 - test.php - sleep 3 技術分享圖片
<?php
header(‘RS:Web1‘);
$t = 5;
sleep($t);
echo "sleep {$t}s<br>";
echo "web-1<br>";
?>
web2 - test.php - sleep 5

測試結果:

[root@localhost ~]# curl -I -w %{time_total}:%{time_connect}:%{time_starttransfer} http://192.168.118.15/test.php
HTTP/1.1 504 Gateway Time-out
Server: nginx/1.14.2
Date: Thu, 14 Mar 2019 11:27:59 GMT
Content-Type: text/html
Content-Length: 537
Connection: keep-alive
ETag: "5c89b5df-219"

2.004:0.001:2.004

三次返回結果一致,每次請求均耗時 2秒,這是因為 proxy_read_timeout 設置為 2s ,而後端的程序: web1-sleep 3 、web2-sleep 5,都無法及時響應。

修改 proxy_read_time 為 3 秒,測試如下:

[root@localhost ~]# curl -I -w %{time_total}:%{time_connect}:%{time_starttransfer} http://192.168.118.15/test.php
HTTP/1.1 200 OK
Server: nginx/1.14.2
Date: Thu, 14 Mar 2019 11:33:30 GMT
Content-Type: text/html; charset=UTF-8
Connection: keep-alive
X-Powered-By: PHP/5.4.16
RS: Web1

3.004:0.001:3.004

[root@localhost ~]# curl -I -w %{time_total}:%{time_connect}:%{time_starttransfer} http://192.168.118.15/test.php
HTTP/1.1 504 Gateway Time-out
Server: nginx/1.14.2
Date: Thu, 14 Mar 2019 11:33:35 GMT
Content-Type: text/html
Content-Length: 537
Connection: keep-alive
ETag: "5c89b5df-219"

3.005:0.001:3.005

當輪詢到 web1 -sleep 3秒時,滿足 proxy_read_timeout 返回 200 狀態,當輪詢到 web2 -sleep 5秒時,超過 proxy_read_timeout 返回 504 狀態。

總結:

對於 max_fails 和 fail_timeout 必須連用,但是都不能為 0 ,否則失效檢查被禁止,每次都會輪詢到失敗的節點

proxy_next_upstream 的使用一定要謹慎,有時候程序員會通過 HTTP 狀態碼來傳遞信息,如果不小心禁止了會造成不必要的麻煩。

proxy_read_timeout 參數根據業務場景需要進行設定,不宜過長,也不宜過短。

Nginx - upstream 模塊及參數測試