目前所在的文章分類 ◊ 代理伺服器 ◊

作者: 丫忠
• 星期五, 六月 04th, 2010

丫忠最近在修改一些 Nginx 的設定,也看到了一篇關於 Nginx 不錯的文章,是一篇關於Nginx代理Web伺服器設定的測試文章,順便轉貼過來作為以後參考用。

測試目的

(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次訪問實際上和第一次情況是一樣的。

結論:

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

原創文章,轉載請註明:   轉自http://salogs.com

文章分類: apache, 代理伺服器  | 相關標籤:  | 留下對這篇文章的想法
作者: 丫忠
• 星期五, 五月 21st, 2010

如果你還不知道什麼是Nginx,那你可以先參考 Nginx安裝及說明

Nginx 的 location指令語法

location [=|~|~*|^~] /uri/ {….}

location 指令會因為不同的URL符合不同的規則,一般而言 location 可以設定 常規字符 或 正規表示式。正規表示式會依照設定的順序決定符合的規則,當找到第一個符合的正規表示式時就會停止往下尋找,如果沒有找到符合的正規表示式,則使用常規字符。

說明1:location = /uri/ {…}
尋找只符合/uri/的規則,如果找到後即停止搜尋。

說明2:location ~ /uri/ {…}
尋找區分大小寫的正規表示式。

說明3:location ~* /uri/ {…}
尋找不區分大小寫的正規表示式。

說明4:location ^~ /uri/ {…}
用於 常規字符,符合常規字符後不再使用正常表示式。

Nginx Location設定範例

範例:假設設定如下4筆

location = / {
#只搜尋符合 /
#set1
}

location / {
#符合所有的查詢,如果沒有符合任何的規則, 則會套用此規則
#set2
}

location ^~ /images/ {
#開頭為/images/的uri都會套用此規則,並且不會尋找其他的正規表示式
#set3
}

location ~* \.(gif|jpg|jpeg|png)$ {
#gif、jpg、jpeg或是png結尾的uri都會套用此規則;但是,/images/abc.jpg則會套用set3
#set4
}

uri: /
套用set1

uri:/category/location-example.html
套用set2

uri:/images/location-example.jpg
套用set3

uri:/category/location-example.jpg
套用set4

文章分類: 代理伺服器  | 相關標籤: ,  | 留下對這篇文章的想法
作者: 丫忠
• 星期一, 二月 01st, 2010

HAProxy負載平衡器介紹

HAProxy 是一款基於 TCP 和 HTTP 協定的高效能負載平衡器,也是一款 Open Source 的 GPL 免費軟體,可以為企業帶來負載平衡需求的解決方案,HAProxy 適應於負載較大的 web伺服器,HAProxy 的高效能得以應付同時上萬個連結的session,HAProxy的高安全性得以保護 web伺服器 在防火牆內,並且很簡單地架設在現有的網路架構,以下為官網提供 HAProxy的架構:

圖片來源:http://haproxy.1wt.eu/

HAProxy負載平衡器-版本比較

目前 HAProxy 的版本有3個版本,有2個版本(1.1跟1.2)為目前較穩定的版本,1.3的版本為目前正在發展的版本,較不穩定;但是,相對提供較多元功能,HAProxy 詳細版本介紹如下:

版本 1.1 – 此版本最目前最穩定(stable)的版本,目前已經不再更新功能。

版本 1.2 – 此版本為以 1.1版本為基礎,加上新功能的版本,新功能如下:

  • 支援 poll/epoll ,用來支援大量的session
  • IPV6
  • 應用程式 cookie
  • hot-reconfiguration
  • 高級的動態流量管理
  • TCP keep alive
  • source hash
  • 加權負載平衡演算法
  • rbtree 算法的調整器
  • web 狀態表介面

以上一些專有名稱 丫忠 是直接翻譯過來,請原諒 丫忠 並沒有詳細介紹^^

版本 1.3 – 此版本為目前正在開發的版本,支援的功能也比較多元,基本上 丫忠 認為此版本的功能較能符合使用者對於 web伺服器 上應用的需求,例如:內容交換功能、全透代理功能等,可以分別依據 來源內容 及 來源IP 分配到後端不同的伺服器,詳細功能介紹如下所示:

  • 內容交換:可以根據來源端的請求(request)分配到不同的 伺服器 ,來源端請求 如:URI , heade , cookie …等,丫忠認為此功能非常實用,就等丫忠有空時再實做出此功能的應用囉
  • 全透明代理:可以根據 來源端IP 分配到後端不同的伺服器(此功能在 kernel Linux 2.4/2.6 時,需要補丁 cttproxy 才可以使用)
  • 與核心(kernel)串接:與 kernel 的串接提高了 HAProxy最大承載量,同時也降低了 CPU 的使用率,此版本也支援 Linux L7SW 以滿足商用對於 最大承載量的需求。
  • 拒絕連接:DDos攻擊是網路駭客最常見的攻擊方式之一,然而此功能可以有效阻擋DDos攻擊。
  • 快速可靠的標頭(header)處理:基於 RFC2616 規格相容的標頭(header)處理,對於請求(request)進行完整性分析和索引,只需要不到 2ms的時間
  • 模組化設計:模組化設計可以很方便讓有興趣的人一同加入開發,HTTP 已經從 TCP協定 中分離出來,使得 HTTP模組 的開發更加方便快速
  • ACLs
  • TCP過濾檢查:結合 ACL 來針對請求(request)進行過濾檢查,如此就可以進行條件式檢查,例如:只允許SSL 但是不允許SSH
  • 加權負載平衡演算法

HAProxy負載平衡器-支援平台

HAProxy 目前支援的平台如下:

HAProxy負載平衡器-高效能說明

  • 單一程序:事件驅動 模組大大的降低了 內容交換 的消耗 和 記憶體 的使用率。每毫秒(ms)可以處理幾百個任務,每個 session 僅消耗幾 KB的記憶體,然而類似的情況在 Apache中,卻需要消耗幾MB的記憶體。
  • 事件檢查器:可以在上萬個連接中及時檢查各種事件,目前僅支援運作在 Linux平台上的HAProxy 1.2的版本
  • 單一緩衝區:儘可能避免在I/O之間的任何資料拷貝動作,以節省CPU及記憶體的使用
  • MRU記憶體配置(memory allocator)
  • work factoring
  • event aggregation
  • two FSMs
  • reduced footprint
  • 優化HTTP標頭(header)分析
  • 減少系統調用次數

HAProxy負載平衡器-下載

請至 HAProxy官網下載

相似於 HAProxy 的負載平衡器

  • Linux Virtual Servers (LVS) :丫忠有列出 LVS vs HAProxy 優缺點比較,網友可以比較看看,LVS 整合於Linux 2.4 和 2.6 kernel的非常快速的 3/4層負載平衡器,需要結合使用 keep-alived 才能夠使用 後端伺服器狀態檢查功能,這通常對於有需求於 基於IP負載平衡器 的網友來說,是一個解決方案。
  • Pure 負載均衡器(PLB) :Pure 負載平衡器 使用了和 HAProxy一樣的事件驅動模組,但是其目的僅為了提升高效能和可用性,並且 沒有任何HTTP處理和session keep-alived.
  • Pound:Pound 可以把它當作 HAProxy 的一個擴充,Pound 支援 SSL,可以根據請求的URL進行分配,設定檔也很尐;但是 Pound 不支援 session keep-alived,適用於一般中小型企業
  • Pen :Pen 是一款很簡單的 TCP負載平衡器,支援 高達2048個客戶端IP(Client IP)的session keep-alived,支援 基於IP的ACL;但是,缺點是當同時 session數達到幾千個後就達到最高效能了

寫完了 HAProxy負載平衡器的介紹 後,丫忠是有股衝動想要安裝HAProxy來試看看,丫忠已經有下載後並且安裝了,安裝方式很簡單,只要 make TARGET=xxxx 就完成了,接下來就是 HAProxy負載平衡器的安裝方式及實例架構了,等完成後再將文件分享出來給大家參考看看!!

參考資料:http://cn.haproxy.org/


作者: 丫忠
• 星期六, 一月 30th, 2010

在這3款負載平衡伺服器中,丫忠比較有接觸的是Nginx,直到最近才對HAProxy比較有接觸,LVS則是完全沒印象,不過既然找到了負載平衡伺服器的比較資料,丫忠就順便做個筆本,再找個時候來研究看看,甚至寫個安裝心得筆記囉!

Nginx的優點

1.效能不錯,同時負載效能可以達到1萬
2.功能較齊全,除了當負載平衡伺服器外,還可以像apache一樣當Web伺服器,且可以透過Geo模式(註1)來達到流量分配功能。
3.支援的模組比較多
4.支援Gzip proxy.

Nginx的缺點

1.不支援session keep alive
2.對於檢查後端伺服器狀態的支援度不夠好。只支援透過埠號(port)來檢查,無法透過url檢查
3.對big request header的支援不是很好,如果 client_header_buffer_size 的設定值比較小,就會返回400 bad request的頁面

也許您對 Nginx V1.5 中文技術手冊 有興趣。

HAProxy的優點

1.支援session keep alive
2.透過指定的url檢查後端伺服器的狀態
3.支援tcp協定的負載平衡,譬如:可以給mysql伺服器mail server郵件伺服器負載平衡

HAProxy的缺點

1.不支援虛擬主機  (更改為支援虛擬主機)
2.目前沒有支援 nagios(註2) 和 cacti (註3)的網路監控功能

LVS的優點

1.效能好,接近硬體式負載平衡設備的效能和連接負載效能
2.LVS的DR模式支援透過廣域網路進行負載平衡,這是個相當大的功能特性,因為其他2款負載平衡器不具備此功能

LVS的缺點

1.比較複雜,模組支援度不如 Nginx

註1:所謂Geo模式是指全域的負載模式,根據不同客戶端(Client)的ip分配到不同的伺服器(Server)。譬如:將特定客戶端的IP分配到特定的伺服器,一般網路使用者則分配到一般Web伺服器

註2:Nagios 為提高效能和準確性的網路監控軟體(詳細)

註3:Cacti 是一套類似 MRTG 的snmp流量監控跟系統資訊監控軟體,除此 Cacti 還可以外掛 Script 及 Templates作出各種的監控圖 ,有興趣的網友可以參考 CaCti官網 的說明

幸運的是有一套軟體 cacti 的發展就是基於讓 RRDTool 使用者更方便使用該軟體,
除了基本的 Snmp 流量跟系統資訊監控外,cacti 也可外掛 Scripts 及加上 Templates 來作出各式各樣的監控圖