原文鏈接:http://nolinux.blog.51cto.com/4824967/1594029?utm_source=tuicool&utm_medium=referral
公司前一段對業務線上的nginx做了整理,重點就是對nginx上負載均衡器的后端節點做健康檢查。目前,nginx對后端節點健康檢查的方式主要有3種,這里列出:
1
2
3
4
5
6
|
1、ngx_http_proxy_module 模塊和ngx_http_upstream_module模塊(自帶)
官網地址:http:
//nginx
.org
/cn/docs/http/ngx_http_proxy_module
.html
#proxy_next_upstream
2、nginx_upstream_check_module模塊
官網網址:https:
//github
.com
/yaoweibin/nginx_upstream_check_module
3、ngx_http_healthcheck_module模塊
官網網址:http:
//wiki
.nginx.org
/NginxHttpHealthcheckModule
|
公司業務線上對后端節點的健康檢查是通過nginx_upstream_check_module模塊做的,這里我將分別介紹這三種實現方式以及之間的差異性。
一、ngx_http_proxy_module 模塊和ngx_http_upstream_module模塊(自帶)
嚴格來說,nginx自帶是沒有針對負載均衡后端節點的健康檢查的,但是可以通過默認自帶的ngx_http_proxy_module 模塊和ngx_http_upstream_module模塊中的相關指令來完成當后端節點出現故障時,自動切換到健康節點來提供訪問。
這里列出這兩個模塊中相關的指令:
ngx_http_proxy_module 模塊中的 proxy_connect_timeout 指令、proxy_read_timeout指令和proxy_next_upstream指令
1
2
3
|
語法: proxy_connect_timeout
time
;
默認值: proxy_connect_timeout 60s;
上下文: http, server, location
|
設置與后端服務器建立連接的超時時間。應該注意這個超時一般不可能大於75秒。
1
2
3
|
語法: proxy_read_timeout
time
;
默認值: proxy_read_timeout 60s;
上下文: http, server, location
|
定義從后端服務器讀取響應的超時。此超時是指相鄰兩次讀操作之間的最長時間間隔,而不是整個響應傳輸完成的最長時間。如果后端服務器在超時時間段內沒有傳輸任何數據,連接將被關閉。
1
2
3
|
語法: 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
|
指定在何種情況下一個失敗的請求應該被發送到下一台后端服務器:
1
2
3
4
5
6
7
8
9
|
error
# 和后端服務器建立連接時,或者向后端服務器發送請求時,或者從后端服務器接收響應頭時,出現錯誤
timeout
# 和后端服務器建立連接時,或者向后端服務器發送請求時,或者從后端服務器接收響應頭時,出現超時
invalid_header
# 后端服務器返回空響應或者非法響應頭
http_500
# 后端服務器返回的響應狀態碼為500
http_502
# 后端服務器返回的響應狀態碼為502
http_503
# 后端服務器返回的響應狀態碼為503
http_504
# 后端服務器返回的響應狀態碼為504
http_404
# 后端服務器返回的響應狀態碼為404
off
# 停止將請求發送給下一台后端服務器
|
需要理解一點的是,只有在沒有向客戶端發送任何數據以前,將請求轉給下一台后端服務器才是可行的。也就是說,如果在傳輸響應到客戶端時出現錯誤或者超時,這類錯誤是不可能恢復的。
范例如下:
1
2
3
|
http {
proxy_next_upstream http_502 http_504 http_404 error timeout invalid_header;
}
|
ngx_http_upstream_module模塊中的server指令
1
2
3
|
語法: server address [parameters];
默認值: —
上下文: upstream
|
范例如下:
1
2
3
4
|
upstream name {
server 10.1.1.110:8080 max_fails=1 fail_timeout=10s;
server 10.1.1.122:8080 max_fails=1 fail_timeout=10s;
}
|
下面是每個指令的介紹:
1
2
3
4
5
6
|
max_fails=number
# 設定Nginx與服務器通信的嘗試失敗的次數。在fail_timeout參數定義的時間段內,如果失敗的次數達到此值,Nginx就認為服務器不可用。在下一個fail_timeout時間段,服務器不會再被嘗試。 失敗的嘗試次數默認是1。設為0就會停止統計嘗試次數,認為服務器是一直可用的。 你可以通過指令proxy_next_upstream、fastcgi_next_upstream和 memcached_next_upstream來配置什么是失敗的嘗試。 默認配置時,http_404狀態不被認為是失敗的嘗試。
fail_timeout=
time
# 設定服務器被認為不可用的時間段以及統計失敗嘗試次數的時間段。在這段時間中,服務器失敗次數達到指定的嘗試次數,服務器就被認為不可用。默認情況下,該超時時間是10秒。
在實際應用當中,如果你后端應用是能夠快速重啟的應用,比如nginx的話,自帶的模塊是可以滿足需求的。但是需要注意。如果后端有不健康節點,負載均衡器依然會先把該請求轉發給該不健康節點,然后再轉發給別的節點,這樣就會浪費一次轉發。
可是,如果當后端應用重啟時,重啟操作需要很久才能完成的時候就會有可能拖死整個負載均衡器。此時,由於無法准確判斷節點健康狀態,導致請求handle住,出現假死狀態,最終整個負載均衡器上的所有節點都無法正常響應請求。由於公司的業務程序都是java開發的,因此后端主要是nginx集群和tomcat集群。由於tomcat重啟應部署上面的業務不同,有些業務啟動初始化時間過長,就會導致上述現象的發生,因此不是很建議使用該模式。
並且ngx_http_upstream_module模塊中的server指令中的max_fails參數設置值,也會和ngx_http_proxy_module 模塊中的的proxy_next_upstream指令設置起沖突。比如如果將max_fails設置為0,則代表不對后端服務器進行健康檢查,這樣還會使fail_timeout參數失效(即不起作用)。此時,其實我們可以通過調節ngx_http_proxy_module 模塊中的 proxy_connect_timeout 指令、proxy_read_timeout指令,通過將他們的值調低來發現不健康節點,進而將請求往健康節點轉移。
以上就是nginx自帶的兩個和后端健康檢查相關的模塊。
|
二、nginx_upstream_check_module模塊
除了自帶的上述模塊,還有一個更專業的模塊,來專門提供負載均衡器內節點的健康檢查的。這個就是淘寶技術團隊開發的 nginx 模塊 nginx_upstream_check_module,通過它可以用來檢測后端 realserver 的健康狀態。如果后端 realserver 不可用,則所以的請求就不會轉發到該節點上。
在淘寶自己的 tengine 上是自帶了該模塊的,大家可以訪問淘寶tengine的官網來獲取該版本的nginx,官方地址:http://tengine.taobao.org/。
如果我們沒有使用淘寶的 tengine 的話,可以通過補丁的方式來添加該模塊到我們自己的 nginx 中。我們業務線上就是采用該方式進行添加的。
下面是部署流程!
1、下載nginx_upstream_check_module模塊
1
2
3
4
5
|
[root@localhost ~]
# cd /usr/local/src
wget https:
//codeload
.github.com
/yaoweibin/nginx_upstream_check_module/zip/master
unzip master
[root@localhost
/usr/local/src
]
# ll -d nginx_upstream_check_module-master
drwxr-xr-x. 6 root root 4096 Dec 1 02:28 nginx_upstream_check_module-master
|
2、為nginx打補丁
1
2
3
4
5
6
7
8
|
[root@localhost
/usr/local/src
]
# cd nginx-1.6.0 # 進入nginx的源碼目錄
給nginx打補丁(根據nginx版本號選擇補丁包)
[root@localhost nginx-1.6.0]
# ./configure --user=nginx --group=nginx --prefix=/usr/local/nginx-1.6.0 --with-http_ssl_module --with-openssl=/usr/local/src/openssl-0.9.8q --with-pcre=/usr/local/src/pcre-8.32 --add-module=/usr/local/src/nginx_concat_module/ --add-module=../nginx_upstream_check_module-master/
make
(注意:此處只
make
,編譯參數需要和之前的一樣)
[root@localhost nginx-1.6.0]
# mv /usr/local/nginx/sbin/nginx /usr/local/nginx/sbin/nginx-1.6.0.bak
[root@localhost nginx-1.6.0]
# cp ./objs/nginx /usr/local/nginx/sbin/
[root@localhost nginx-1.6.0]
# /usr/local/nginx/sbin/nginx -t # 檢查下是否有問題
[root@localhost nginx-1.6.0]
# kill -USR2 `cat /usr/local/nginx/logs/nginx.pid`
|
3、在nginx.conf配置文件里面的upstream加入健康檢查,如下:
1
2
3
4
5
6
|
upstream name {
server 192.168.0.21:80;
server 192.168.0.22:80;
check interval=3000 rise=2 fall=5 timeout=1000
type
=http;
}
|
上面配置的意思是,對name這個負載均衡條目中的所有節點,每個3秒檢測一次,請求2次正常則標記 realserver狀態為up,如果檢測 5 次都失敗,則標記 realserver的狀態為down,超時時間為1秒。
這里列出nginx_upstream_check_module模塊所支持的指令意思:
1
2
3
|
Syntax: check interval=milliseconds [fall=count] [rise=count] [timeout=milliseconds] [default_down=
true
|
false
] [
type
=tcp|http|ssl_hello|mysql|ajp] [port=check_port]
Default: 如果沒有配置參數,默認值是:interval=30000 fall=5 rise=2 timeout=1000 default_down=
true
type
=tcp
Context: upstream
|
該指令可以打開后端服務器的健康檢查功能。
指令后面的參數意義是:
1
2
3
4
5
6
7
8
9
10
11
12
|
- interval:向后端發送的健康檢查包的間隔。
- fall(fall_count): 如果連續失敗次數達到fall_count,服務器就被認為是down。
- rise(rise_count): 如果連續成功次數達到rise_count,服務器就被認為是up。
- timeout: 后端健康請求的超時時間。
- default_down: 設定初始時服務器的狀態,如果是
true
,就說明默認是down的,如果是
false
,就是up的。默認值是
true
,也就是一開始服務器認為是不可用,要等健康檢查包達到一定成功次數以后才會被認為是健康的。
-
type
:健康檢查包的類型,現在支持以下多種類型
- tcp:簡單的tcp連接,如果連接成功,就說明后端正常。
- ssl_hello:發送一個初始的SSL hello包並接受服務器的SSL hello包。
- http:發送HTTP請求,通過后端的回復包的狀態來判斷后端是否存活。
- mysql: 向mysql服務器連接,通過接收服務器的greeting包來判斷后端是否存活。
- ajp:向后端發送AJP協議的Cping包,通過接收Cpong包來判斷后端是否存活。
- port: 指定后端服務器的檢查端口。你可以指定不同於真實服務的后端服務器的端口,比如后端提供的是443端口的應用,你可以去檢查80端口的狀態來判斷后端健康狀況。默認是0,表示跟后端server提供真實服務的端口一樣。該選項出現於Tengine-1.4.0。
|
1
2
3
|
Syntax: check_keepalive_requests request_num
Default: 1
Context: upstream
|
該指令可以配置一個連接發送的請求數,其默認值為1,表示Tengine完成1次請求后即關閉連接。
1
2
3
|
Syntax: check_http_send http_packet
Default:
"GET / HTTP/1.0\r\n\r\n"
Context: upstream
|
該指令可以配置http健康檢查包發送的請求內容。為了減少傳輸數據量,推薦采用"HEAD"方法。
當采用長連接進行健康檢查時,需在該指令中添加keep-alive請求頭,如:"HEAD / HTTP/1.1\r\nConnection: keep-alive\r\n\r\n"。 同時,在采用"GET"方法的情況下,請求uri的size不宜過大,確保可以在1個interval內傳輸完成,否則會被健康檢查模塊視為后端服務器或網絡異常。
1
2
3
|
Syntax: check_http_expect_alive [ http_2xx | http_3xx | http_4xx | http_5xx ]
Default: http_2xx | http_3xx
Context: upstream
|
該指令指定HTTP回復的成功狀態,默認認為2XX和3XX的狀態是健康的。
1
2
3
|
Syntax: check_shm_size size
Default: 1M
Context: http
|
所有的后端服務器健康檢查狀態都存於共享內存中,該指令可以設置共享內存的大小。默認是1M,如果你有1千台以上的服務器並在配置的時候出現了錯誤,就可能需要擴大該內存的大小。
1
2
3
|
Syntax: check_status [html|csv|json]
Default: check_status html
Context: location
|
顯示服務器的健康狀態頁面。該指令需要在http塊中配置。
在Tengine-1.4.0以后,你可以配置顯示頁面的格式。支持的格式有: html、csv、 json。默認類型是html。
你也可以通過請求的參數來指定格式,假設‘/status’是你狀態頁面的URL, format參數改變頁面的格式,比如:
1
2
3
|
/status
?
format
=html
/status
?
format
=csv
/status
?
format
=json
|
同時你也可以通過status參數來獲取相同服務器狀態的列表,比如:
1
2
|
/status
?
format
=html&status=down
/status
?
format
=csv&status=up
|
下面是一個狀態也配置的范例:
1
2
3
4
5
6
7
8
9
10
|
http {
server {
location
/nstatus
{
check_status;
access_log off;
#allow IP;
#deny all;
}
}
}
|
配置完畢后,重啟nginx。此時通過訪問定義好的路徑,就可以看到當前 realserver 實時的健康狀態啦。效果如下圖:
realserver 都正常的狀態:
一台 realserver 故障的狀態:
OK,以上nginx_upstream_check_module模塊的相關信息,更多的信息大家可以去該模塊的淘寶tengine頁面和github上該項目頁面去查看,下面是訪問地址:
http://tengine.taobao.org/document_cn/http_upstream_check_cn.html
https://github.com/yaoweibin/nginx_upstream_check_module
在生產環境的實施應用中,需要注意的有 2 點:
1、主要定義好type。由於默認的type是tcp類型,因此假設你服務啟動,不管是否初始化完畢,它的端口都會起來,所以此時前段負載均衡器為認為該服務已經可用,其實是不可用狀態。
2、注意check_http_send值的設定。由於它的默認值是"GET / HTTP/1.0\r\n\r\n"。假設你的應用是通過http://ip/name訪問的,那么這里你的check_http_send值就需要更改為"GET /name HTTP/1.0\r\n\r\n"才可以。針對采用長連接進行檢查的,這里增加keep-alive請求頭,即"HEAD /name HTTP/1.1\r\nConnection: keep-alive\r\n\r\n"。如果你后端的tomcat是基於域名的多虛擬機,此時你需要通過check_http_send定義host,不然每次訪問都是失敗,范例:check_http_send "GET /mobileapi HTTP/1.0\r\n HOST www.redhat.sx\r\n\r\n";
三、ngx_http_healthcheck_module模塊
除了上面兩個模塊,nginx官方在早期的時候還提供了一個 ngx_http_healthcheck_module 模塊用來進行nginx后端節點的健康檢查。nginx_upstream_check_module模塊就是參照該模塊的設計理念進行開發的,因此在使用和效果上都大同小異。但是需要注意的是,ngx_http_healthcheck_module 模塊僅僅支持nginx的1.0.0版本,1.1.0版本以后都不支持了!因此,對於目前常見的生產環境上都不會去用了,這里僅僅留個紀念,給大家介紹下這個模塊!
具體的使用方法,這里可以貼出幾篇靠譜的博文地址以及官方地址:
http://wiki.nginx.org/HttpHealthcheckModule
https://github.com/cep21/healthcheck_nginx_upstreams/blob/master/README
四、在nginx_upstream_check_module-master模塊安裝正常的情況下,通過web界面查看后端節點狀態配置方法,有問題請QQ聯系我:405110958
1、配置upstream節點,並將健康監測頁面添加至該節點池內
upstream dvwa {
server 192.168.2.41:9000;
server 192.168.2.42:9000;
server 192.168.2.43:9000;
server 192.168.2.44:9000;
#check interval=5000 rise=1 fall=3 timeout=16000;
#check interval=3000 rise=2 fall=5 timeout=1000 type=ssl_hello;
check interval=3000 rise=2 fall=5 timeout=1000 type=http;
check_keepalive_requests 100;
check_http_send "GET /dvwa/check.html HTTP/1.1\r\nHost:dvwa.manjd.com\r\nConnection: keep-alive\r\n\r\n";
check_http_expect_alive http_2xx http_3xx;
#check_http_send "HEAD / HTTP/1.1\r\nConnection: keep-alive\r\n\r\n";
}
2、新增反向代理健康檢查節點
server
{
listen 80;
server_name dvwa.manjd.com;
index index.html index.htm index.php;
location /status {
check_status;
access_log on;
#allow SOME.IP.ADD.RESS;
allow 10.0.0.0/8;
allow 127.0.0.1/32;
allow 192.168.0.0/16;
#deny all;
}
location /ngx_status {
stub_status on;
allow 10.0.0.0/8;
allow 127.0.0.1;
allow 192.168.0.0/16;
deny all;
}
location / {
proxy_pass http://dvwa;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarder-For @proxy_add_x_forwarded_for;
}
}
3、web界面查看健康狀態