Nginx HTTP負載均衡/反向代理的相關參數測試

原文:http://dinguangx.iteye.com/blog/1934994

測試目的

(1)弄清楚HTTP Upstream 模塊中Server指令的max_failsfail_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
HTTP/1.1 504 Gateway Time-out
Server: nginx/0.7.65
Date: Tue, 18 May 2010 02:43:08 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 183
Connection: keep-alive

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
HTTP/1.1 200 OK
Server: nginx/0.7.65
Date: Tue, 18 May 2010 03:07:58 GMT
Content-Type: text/html; charset=UTF-8
Connection: keep-alive
Vary: Accept-Encoding
X-Powered-By: PHP/5.1.6
RS: Web1

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
HTTP/1.1 200 OK
Server: nginx/0.7.65
Date: Tue, 18 May 2010 03:15:25 GMT
Content-Type: text/html; charset=UTF-8
Connection: keep-alive
Vary: Accept-Encoding
X-Powered-By: PHP/5.1.6
RS: Web1

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>";
?>
備註:

開啓了後端服務器健康檢查
proxy_read_timeout 2s (下面會隨着測試變更)
Web1程序仍然sleep 2s
修改了Web2程序,讓他直接返回500錯誤

測試開始:

(1)連續測試三次結果如下:

curl -I -w %{time_total}:%{time_connect}:%{time_starttransfer} www.test.com/test.php
HTTP/1.1 504 Gateway Time-out
Server: nginx/0.7.65
Date: Tue, 18 May 2010 07:01:48 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 183
Connection: keep-alive

2.005:0.001:2.005

curl -I -w %{time_total}:%{time_connect}:%{time_starttransfer} www.test.com/test.php
HTTP/1.1 502 Bad Gateway
Server: nginx/0.7.65
Date: Tue, 18 May 2010 07:01:50 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 173
Connection: keep-alive

0.001:0.001:0.001

curl -I -w %{time_total}:%{time_connect}:%{time_starttransfer} www.test.com/test.php
HTTP/1.1 504 Gateway Time-out
Server: nginx/0.7.65
Date: Tue, 18 May 2010 07:01:57 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 183
Connection: keep-alive

2.005:0.001:2.005

說明:

第1次請求所用時間是2秒,web1執行超時,web2返回了500錯誤,upstream沒有更多的後端,因此nginx直接把504扔出來了, 同時標記web2,web1不可用。查看後端2臺web服務器的訪問日誌,均有nginx代理的訪問記錄。
第2次請求時間很短,報502錯誤,說明沒有可用的後端服務器接受請求。查看後端兩臺web服務器訪問日誌,沒有任何變化,說明這兩臺服務器被nginx 標記爲不可用,沒有把請求轉向後端,直接返回用戶502錯誤
第3次請求同第1次

(2)修改 proxy_read_timeout 3s 連續訪問6次後結果以及2臺web服務器的日誌情況
curl -I -w %{time_total}:%{time_connect}:%{time_starttransfer} www.test.com/test.php
HTTP/1.1 200 OK
Server: nginx/0.7.65
Date: Tue, 18 May 2010 07:30:15 GMT
Content-Type: text/html; charset=UTF-8
Connection: keep-alive
Vary: Accept-Encoding
X-Powered-By: PHP/5.1.6
RS: Web1

2.003:0.001:2.002

訪問日誌

Web1
[18/May/2010:15:30:00
[18/May/2010:15:30:03
[18/May/2010:15:30:05
[18/May/2010:15:30:08
[18/May/2010:15:30:11
[18/May/2010:15:30:13

Web2

[18/May/2010:15:30:00
[18/May/2010:15:30:11

說明:

由訪問日誌可知:
第1次請求是被分到web2上的,由於它返回了500錯誤,因此請求被轉到web1,並標記web2不可用。
第2次至第4次均將請求給了web1,第四次請求完畢後距第一請求已經過去了8秒。
第5次請求時已經是fail_timeout參數默認的10s也就是標記web2不可用的時間已經過去了,因此在第5 次訪問實際上和第一次情況是一樣的。

結論:

(1)proxy_next_upstream參數很有用,他可以避免很多 錯誤
(2)max_fails 參數在繁忙的大型系統中建議設置爲3,如果沒有幾個後端服務器的話保持默認即可。
(3)proxy_read_timeout要根據自身程序而定,不要過大,也不 要太小。如果是php程序,請參照php.ini中的max_execution_time選項值。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章