原文:http://dinguangx.iteye.com/blog/1934994
測試目的
(1)弄清楚HTTP Upstream 模塊中Server指令的max_fails與fail_timeout參 數的關係、它們對後端服務器健康情況的檢查起到了什麼作用、它們的取值對Http proxy模塊中的其它指令是否有直接或間接的影響等……
(2)測試HTTP Proxy模塊中proxy_next_upstream、proxy_connect_timeout、proxy_read_timeout、 proxy_send_timeout指令的作用、對nginx性能的影響、對後端服務器響應的處理等……
測試方法
本文測試不會使用壓力測試,所有的測試都是通過瀏覽器手動刷新來實現的。後端服務器使用簡單的php程序來實現。
測試環境
Nginx負載均衡/反向代理服務器
系統:CentOS 5.4 64bit
Nginx:0.7.65
IP:192.168.108.10
後端web服務器
系統:CentOS 5.4 64bit
Web環境:apache+php
Web-1 IP:192.168.108.163
Web-2 IP:192.168.108.164
本次測試主要針對HTTP Upstream和HTTP Proxy模塊進行,下面測試環境中http upstream 和http proxy模塊參數的初始化設置,後文會針對測試的參數進行相應的修改:
…
upstream test {
server 192.168.108.163 ;
server 192.168.108.164:80;
}
server {
listen 80;
server_name .test.com;
index index.php index.html index.htm;
location / {
proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504 http_404;
proxy_connect_timeout 10s;
proxy_read_timeout 2s;
#proxy_send_timeout 10s;
proxy_pass http://test;
}
}
…
提出server指令後面的參數部分,以下摘抄nginx wiki 內容
語法:server name [parameters]
parameters包 含:
·weight = NUMBER - 設置服務器權重,默認爲1。
·max_fails = NUMBER - 在一定時間內(這個時間在fail_timeout參數中設置)檢查這個服務器是否可用時產生的最多失敗請求數,默認爲1,將其設置爲0可以關閉檢查,這 些錯誤在proxy_next_upstream或fastcgi_next_upstream(404錯誤不會使max_fails增加)中定義。
·fail_timeout = TIME - 在這個時間內產生了max_fails所設置大小的失敗嘗試連接請求後這個服務器可能不可用,同樣它指定了服務器不可用的時間(在下一次嘗試連接請求發起 之前),默認爲10秒,fail_timeout與前端響應時間沒有直接關係,不過可以使用proxy_connect_timeout和 proxy_read_timeout來控制。
·down - 標記服務器處於離線狀態,通常和ip_hash一起使用。
·backup - (0.6.7或更高)只用於本服務器,如果所有的非備份服務器都宕機或繁忙。
關於max_fails 參數的理解:根 據上面的解釋,max_fails默認爲1,fail_timeout默 認爲10秒,也就是說,默認情況下後端服務器在10秒鐘之內可以容許有一次的失 敗,如果超過1次則視爲該服務器有問題,將該服務器標記爲不可用。等待10秒後再 將請求發給該服務器,以此類推進行後端服務器的健康檢查。但如果我將max_fails設置爲0, 則代表不對後端服務器進行健康檢查,這樣一來fail_timeout參數也就沒什麼意義了。那若後端服務器真的出現 問題怎麼辦呢?上文也說了,可以藉助proxy_connect_timeout和proxy_read_timeout進 行控制。
下面介紹http proxy模塊中的相關指令:
proxy_next_upstream
語法: proxy_next_upstream [error|timeout|invalid_header|http_500|http_502|http_503|http_504|http_404|off]
確定在何種情況下請求將轉發到下一個服務器。轉發請求只發生在沒有數據傳遞到客戶端的過程中。
proxy_connect_timeout
後端服務器連接的超時時間_發起握手等候響應超時時間
proxy_read_timeout
連接成功後_等候後端服務器響應時間_其實已經進入後端的排隊之中等候處理(也可以說是後端服務器處理請求的時間)
proxy_send_timeout
後端服務器數據回傳時間_就是在規定時間之內後端服務器必須傳完所有的數據
proxy_pass
這個指令設置被代理服務器的地址和被映射的URI
開始測試
情況1:後端程序執行時間超過或等於proxy_read_timeout設 置值,max_fails=0 關閉後端服務器健康檢查。
Nginx配置修改內容 | server 192.168.108.163 max_fails = 0; server 192.168.108.164 max_fails = 0; proxy_next_upstream error timeout proxy_read_timeout 2s |
後端web服務器 | |
Web1 test.php | Web2 test.php |
<?php header('RS:Web1'); $t = 2; sleep($t); echo "sleep {$t}s<br>"; echo "web-1<br>"; ?> |
<?php header('RS:Web2'); $t = 5; sleep($t); echo "sleep {$t}s<br>"; echo "web-2<br>"; ?> |
備註:
我這裏的兩臺後端web服務器,他們的主頁文件均爲一個test.php程序,該程序分別sleep了2秒和5秒,等於和超過了 proxy_read_timeout的時間,[max_fails=0] 即關閉後端服務器健康檢查。[proxy_next_upstream error timeout] 說明碰到錯誤或超時的情況切到下一個後端服務器。如此設置後利用curl命令對nginx發起連接請求,看nginx會作何反應。 |
|
測試開始:
(1)curl -I -w %{time_total}:%{time_connect}:%{time_starttransfer}
www.test.com/test.php 4.008:0.002:4.007 說明: 連續請求3次後得到的http返回結果是一樣的,均爲504 Gateway Time-out 錯誤。這種情況只有在後端服務器都有問題的時纔會出現這個錯誤,很顯然我這裏的proxy_read_timeout設置的時間太短,後端程序還沒來得及 把程序執行完,nginx就迫不及待的將請求甩給upstream定義的另一臺服務器上了,當發現另外一臺服務器同樣2秒沒有返回後,nginx這回沒有 服務器可用,只有返回504 Gateway Time-out 。這也是爲什麼最後的time_total時間是4秒。(經查看兩臺web服務器的訪問日誌得知,均有一條訪問記錄,且返回代碼爲200,說明nginx 確實來過,但沒有等到執行完成就匆匆的離去了)如果我有3臺服務器,在保證任何不變的情況下,time_total時間一定會是6秒,因爲nginx會一 個接一個的將3臺服務器都走一遍。 ----------------------------------------------------------------------------------------------------------------------- 好了,確認是我proxy_read_timeout設置時間太短後,我將它的值設置爲3秒,再通過curl命令訪問: (2)curl -I -w %{time_total}:%{time_connect}:%{time_starttransfer} www.test.com/test.php 5.042:0.005:5.042 說明:通過3次連續請求,得到的結果是一樣的,RS:Web1 也就是說我這三次的請求都甩到了web1上。但我web1中的程序只需要2秒後就可以返回結果,但爲什麼我通過nginx代理後時間總是我的 程序執行時間+proxy_read_timeout時間呢? ----------------------------------------------------------------------------------------------------------------------- 繼續將proxy_read_timeout設置爲4s (3)curl -I -w %{time_total}:%{time_connect}:%{time_starttransfer} www.test.com/test.php 6.004:0.000:6.004 三次請求後結果也是一樣,這次花的時間更長了,但確實是程序執行時 間+proxy_read_timeout 時間。但爲什麼每次都需要6秒呢?按照upstream中定義的權重應該是平分請求的,最起碼 應該有2秒的時候。經過分析得知:最終返回給用戶請求的是web1,那麼當再次請求的時候一定會分給web2,由於web2是sleep 5秒的,因此經過proxy_read_timeout的時間(4s)後會跳到web1,結果還是web1返回的請求,所花時間就是nginx在web2 等待的時間+web1執行的時間,以此類推下一次nginx自然的還會分給web2……。如果有更多的後端web,則判斷下一個請求服務器可以看當前返回 給最終用戶的是那臺服務器,然後根據upstream中定義的順序向下查詢(權重一樣的情況) |
|
結論:
(1)上面的三次測試分別將proxy_read_timeout的值設置爲2s、3s、4s的情況進行的。最終的測試結果也都在後面做了解釋與說 明。由於我關閉了後端服務器的健康檢查(max_fails=0)因此判斷後端服務器情況的唯一依據便是proxy_read_timeout參數,如果 這個參數設置得過小,但後端程序的執行或多或少會超過這個時間的話,這種情況nginx的效率是非常低的。 (2)上面的測試都是後端服務器正常但執行超時的情況下nginx根據proxy_read_timeout和 proxy_next_upstream的值來選擇下一個服務器,那如果我後端服務器直接報錯的情況呢?可以想到如果報錯信息在 proxy_next_upstream 中有定義的話nginx還會跳到下一臺服務器。否則直接將保存信息返回給nginx從而最終呈獻給用戶 |
情況2:打開後端服務器健康檢查,測試程序執行時間超過或等於proxy_read_timeout值或後端服務器直接報錯的情況
Nginx配置修改內容 | server 192.168.108.163 max_fails =
1; server 192.168.108.164 max_fails = 1; proxy_next_upstream error timeout http_500 http_502 http_504 proxy_read_timeout 2s |
|
後端web服務器 | ||
Web1 test.php | Web2 test.php | |
<?php header('RS:Web1'); $t = 2; sleep($t); echo "sleep {$t}s<br>"; echo "web-1<br>"; ?> |
<?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>"; ?> |
|
備註:
開啓了後端服務器健康檢查 |
||
測試開始:
(1)連續測試三次結果如下: curl -I -w %{time_total}:%{time_connect}:%{time_starttransfer} www.test.com/test.php 2.005:0.001:2.005 curl -I -w %{time_total}:%{time_connect}:%{time_starttransfer} www.test.com/test.php 0.001:0.001:0.001 curl -I -w %{time_total}:%{time_connect}:%{time_starttransfer} www.test.com/test.php 2.005:0.001:2.005 說明: 第1次請求所用時間是2秒,web1執行超時,web2返回了500錯誤,upstream沒有更多的後端,因此nginx直接把504扔出來了, 同時標記web2,web1不可用。查看後端2臺web服務器的訪問日誌,均有nginx代理的訪問記錄。 (2)修改 proxy_read_timeout 3s 連續訪問6次後結果以及2臺web服務器的日誌情況 2.003:0.001:2.002 訪問日誌 Web1 Web2 [18/May/2010:15:30:00 說明: 由訪問日誌可知: |
||
結論:
(1)proxy_next_upstream參數很有用,他可以避免很多 錯誤 |