1. 摘要
(1) 結論
較長的描述了nginx記錄失效節點的6種狀态(time out、connect refuse、500、502、503、504,後四項5XX需要配置proxy_next_upstream中的狀态才可以生效)、失效節點的觸發條件和節點的恢複條件、所有節點失效後nginx會進行恢複并進行重新監聽。
(2) Nginx 負載均衡方式介紹
Nginx的負載均衡方式一共有4種:rr(輪詢模式)、ip_hash、fair、url_hash。
(3) Ngxin負載均衡和相關反向代理配置内容
Nginx負載均衡和與容錯相關的反向代理的配置。
(4) 擷取後端流程
後端server的自動容錯流程圖。
(5) 測試環境和測試結果
針對幾種錯誤方式進行自動容錯測試。
2. 結論
(1) nginx 判斷節點失效狀态
Nginx 預設判斷失敗節點狀态以connect refuse和time out狀态為準,不以HTTP錯誤狀态進行判斷失敗,因為HTTP隻要能傳回狀态說明該節點還可以正常連接配接,是以nginx判斷其還是存活狀态;除非添加了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的時間範圍内節點被置為失效,除非所有節點都失效,否則該時間内,節點不進行恢複)對節點失敗的嘗試次數和失效時間進行設定,當超過最大嘗試次數或失效時間未超過配置失效時間,則nginx會對節點狀會置為失效狀态,nginx不對該後端進行連接配接,直到超過失效時間或者所有節點都失效後,該節點重新置為有效,重新探測;
(3) 所有節點失效後nginx将重新恢複所有節點進行探測
如果探測所有節點均失效,備機也為失效時,那麼nginx會對所有節點恢複為有效,重新嘗試探測有效節點,如果探測到有效節點則傳回正确節點内容,如果還是全部錯誤,那麼繼續探測下去,當沒有正确資訊時,節點失效時預設傳回狀态為502,但是下次通路節點時會繼續探測正确節點,直到找到正确的為止。
3. nginx負載均衡
Nginx的負載均衡方式一共有4種:rr(輪詢模式)、ip_hash、fair、url_hash;
Nginx自帶的2種負載均衡為rr和ip_hash,fair和url_hash為第三方的插件,nginx在不配置負載均衡的模式下,預設采用rr負載均衡模式。
l RR負載均衡模式:
每個請求按時間順序逐一配置設定到不同的後端伺服器,如果超過了最大失敗次數後(max_fails,預設1),在失效時間内(fail_timeout,預設10秒),該節點失效權重變為0,超過失效時間後,則恢複正常,或者全部節點都為down後,那麼将所有節點都恢複為有效繼續探測,一般來說rr可以根據權重來進行均勻配置設定。
l Ip_hash負載均衡模式:
每個請求按通路ip的hash結果配置設定,這樣每個訪客固定通路一個後端伺服器,可以解決session的問題,但是ip_hash會造成負載不均,有的服務請求接受多,有的服務請求接受少,是以不建議采用ip_hash模式,session共享問題可用後端服務的session共享代替nginx的ip_hash。
l Fair(第三方)負載均衡模式:
按後端伺服器的響應時間來配置設定請求,響應時間短的優先配置設定。
l url_hash(第三方)負載均衡模式:
和ip_hash算法類似,是對每個請求按url的hash結果配置設定,使每個URL定向到一個同 一個後端伺服器,但是也會造成配置設定不均的問題,這種模式後端伺服器為緩存時比較好。
4. Nginx 負載均衡配置
Nginx的負載均衡采用的是upstream子產品
其中預設的采用的負載均衡模式是輪詢模式rr(round_robin),具體配置如下:
1) 指令:
ip_hash
文法:ip_hash
預設值:none
使用字段:upstream
這個指令将基于用戶端連接配接的IP位址來分發請求。
哈希的關鍵字是用戶端的C類網絡位址,這個功能将保證這個用戶端請求總是被轉發到一台伺服器上,但是如果這台伺服器不可用,那麼請求将轉發到另外的伺服器上,這将保證某個用戶端有很大機率總是連接配接到一台伺服器。
無法将權重(weight)與ip_hash聯合使用來分發連接配接。如果有某台伺服器不可用,你必須标記其為“down”,如下例:
upstream backend {
ip_hash;
server backend1.example.com;
server backend2.example.com;
server backend3.example.com down;
server backend4.example.com;
}
server
文法:server name [parameters]
預設值:none
使用字段:upstream
指定後端伺服器的名稱和一些參數,可以使用域名,IP,端口,或者unix socket。如果指定為域名,則首先将其解析為IP。
l weight = NUMBER - 設定伺服器權重,預設為1。
l max_fails = NUMBER - 在一定時間内(這個時間在fail_timeout參數中設定)檢查這個伺服器是否可用時産生的最多失敗請求數,預設為1,将其設定為0可以關閉檢查,這些錯誤在proxy_next_upstream或fastcgi_next_upstream(404錯誤不會使max_fails增加)中定義。
l fail_timeout = TIME - 在這個時間内産生了max_fails所設定大小的失敗嘗試連接配接請求後這個伺服器可能不可用,同樣它指定了伺服器不可用的時間(在下一次嘗試連接配接請求發起之前),預設為10秒,fail_timeout與前端響應時間沒有直接關系,不過可以使用proxy_connect_timeout和proxy_read_timeout來控制。
l down - 标記伺服器處于離線狀态,通常和ip_hash一起使用。
l backup - (0.6.7或更高)如果所有的非備份伺服器都當機或繁忙,則使用本伺服器(無法和ip_hash指令搭配使用)。
示例配置
upstream backend {
server backend1.example.com weight=5;
server 127.0.0.1:8080 max_fails=3 fail_timeout=30s;
server unix:/tmp/backend3;
}
注意:如果你隻使用一台上遊伺服器,nginx将設定一個内置變量為1,即max_fails和fail_timeout參數不會被處理。
結果:如果nginx不能連接配接到上遊,請求将丢失。
解決:使用多台上遊伺服器。
upstream
文法:upstream name { … }
預設值:none
使用字段:http
這個字段設定一群伺服器,可以将這個字段放在proxy_pass和fastcgi_pass指令中作為一個單獨的實體,它們可以可以是監聽不同端口的伺服器,并且也可以是同時監聽TCP和Unix socket的伺服器。
伺服器可以指定不同的權重,預設為1。
示例配置
upstream backend {
server backend1.example.com weight=5;
server 127.0.0.1:8080 max_fails=3 fail_timeout=30s;
server unix:/tmp/backend3;
}
請求将按照輪詢的方式分發到後端伺服器,但同時也會考慮權重。
在上面的例子中如果每次發生7個請求,5個請求将被發送到backend1.example.com,其他兩台将分别得到一個請求,如果有一台伺服器不可用,那麼請求将被轉發到下一台伺服器,直到所有的伺服器檢查都通過。如果所有的伺服器都無法通過檢查,那麼将傳回給用戶端最後一台工作的伺服器産生的結果。
2) 變量
版本0.5.18以後,可以通過log_module中的變量來記錄日志:
log_format timing '$remote_addr - $remote_user [$time_local] $request '
'upstream_response_time $upstream_response_time '
'msec $msec request_time $request_time';
log_format up_head '$remote_addr - $remote_user [$time_local] $request '
'upstream_http_content_type $upstream_http_content_type';
l $upstream_addr
前端伺服器處理請求的伺服器位址
l $upstream_cache_status
0.8.3版本中其值可能為:
MISS
EXPIRED - expired。請求被傳送到後端。
UPDATING - expired。由于proxy/fastcgi_cache_use_stale正在更新,将使用舊的應答。
STALE - expired。由于proxy/fastcgi_cache_use_stale,後端将得到過期的應答。
HIT
l $upstream_status
前端伺服器的響應狀态。
l $upstream_response_time
前端伺服器的應答時間,精确到毫秒,不同的應答以逗号和冒号分開。
l $upstream_http_$HEADER
随意的HTTP協定頭,如:$upstream_http_host
l $upstream_http_host
3) Proxy指令:
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 - 禁止轉發請求到下一台伺服器。
轉發請求隻發生在沒有資料傳遞到用戶端的過程中。
其中記錄到nginx後端錯誤數量的有500、502、503、504、timeout,404不記錄錯誤。
proxy_connect_timeout
文法:proxy_connect_timeout timeout_in_seconds
預設值:proxy_connect_timeout 60s
使用字段:http, server, location
指定一個連接配接到代理伺服器的逾時時間,機關為秒,需要注意的是這個時間最好不要超過75秒。
這個時間并不是指伺服器傳回頁面的時間(這個時間由proxy_read_timeout聲明)。如果你的前端代理伺服器是正常運作的,但是遇到一些狀況(例如沒有足夠的線程去處理請求,請求将被放在一個連接配接池中延遲處理),那麼這個聲明無助于伺服器去建立連接配接。
可以通過指定時間機關以免引起混亂,支援的時間機關有”s”(秒), “ms”(毫秒), “y”(年), “M”(月), “w”(周), “d”(日), “h”(小時),和 “m”(分鐘)。
這個值不能大于597小時。
proxy_read_timeout
文法:proxy_read_timeout time
預設值:proxy_read_timeout 60s
使用字段:http, server, location
決定讀取後端伺服器應答的逾時時間,機關為秒,它決定nginx将等待多久時間來取得一個請求的應答。逾時時間是指完成了兩次握手後并且狀态為established的逾時時間。
相對于proxy_connect_timeout,這個時間可以撲捉到一台将你的連接配接放入連接配接池延遲處理并且沒有資料傳送的伺服器,注意不要将此值設定太低,某些情況下代理伺服器将花很長的時間來獲得頁面應答(例如如當接收一個需要很多計算的報表時),當然你可以在不同的location裡面設定不同的值。
可以通過指定時間機關以免引起混亂,支援的時間機關有”s”(秒), “ms”(毫秒), “y”(年), “M”(月), “w”(周), “d”(日), “h”(小時),和 “m”(分鐘)。
這個值不能大于597小時。
proxy_send_timeout
文法:proxy_send_timeout seconds
預設值:proxy_send_timeout 60s
使用字段:http, server, location
設定代理伺服器轉發請求的逾時時間,機關為秒,同樣指完成兩次握手後的時間,如果超過這個時間代理伺服器沒有資料轉發到被代理伺服器,nginx将關閉連接配接。
可以通過指定時間機關以免引起混亂,支援的時間機關有”s”(秒), “ms”(毫秒), “y”(年), “M”(月), “w”(周), “d”(日), “h”(小時),和 “m”(分鐘)。
這個值不能大于597小時。
5. 擷取後端流程
GET_RR_PEER: 通過RR算法擷取後端流程
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiInBnaukDO5MzMxAjYzIjN20SNiJTOtMzMkNTLkRjYz0CO1MmYmNmZl9CX0YzN18CX3gDMw8CX05WZth2YhRHdh9CXkF2bsBXdvwVbvNmLllXZ0lmLywGZvw1LcpDc0RHaiojIsJye.jpg)
K:是判斷peer是否當機和判斷失效狀态算法
FAIL:嘗試次數用盡有,跳轉到失敗流程,如果有備機,備機再嘗試監聽,如果監聽失敗則傳回NGX_BUSY,成功則傳回目前狀态。
6. 測試環境
作業系統:centos5.6
Cpu:16核
記憶體:32g
Web 伺服器:nginx
Web 應用伺服器:tomcat(2台)
7. 測試結果
l 設定tomcat1逾時時間,造成逾時狀态(總有一台server為有效狀态):
Tomcat1的connectionTimeout 設定為-1,永遠逾時,nginx設定tomcat1和tomcat2權重為10,tomcat1的max_fails為10,fail_timeout=120;在連接配接tomcat1的10次後,傳回給nginx為10次逾時,ngxin判斷tomcat1為失效,然後将tomcat1逾時時間恢複為1000重新啟動tomcat1,在這段時間内nginx判斷tomcat1還是失效狀态,是以在2分鐘後,nginx繼續監聽到tomcat1正常後,那麼nginx會将tomcat1判斷為有效,将連接配接繼續均勻配置設定到2個tomcat上。
l 設定tomcat1連接配接數量,造成逾時狀态(總有一台server為有效狀态):
Tomcat1的線程數量設定為1,nginx設定tomcat1和tomcat2權重為10,tomcat1的max_fails為10,fail_timeout=120;在連接配接tomcat1超過線程接受數量後,tomcat1會傳回逾時狀态,在傳回給nginx10次逾時狀态後,ngxin判斷tomcat1為失效,然後将tomcat線程數量恢複為700,重新啟動tomcat1,在這段時間内nginx判斷tomcat1還是失效狀态,超過2分鐘失效後,nginx繼續監聽到tomcat1正常後,那麼nginx會将tomcat1判斷為有效,将連接配接繼續均勻配置設定到2個tomcat上。
l 設定tomcat1關閉,造成拒絕狀态(總有一台server為有效狀态):
Tomcat1為關閉,nginx設定tomcat1和tomcat2權重為10,tomcat1的max_fails為10,fail_timeout=120;在連接配接tomcat1的10次後,nginx收到tomcat1傳回connect refuse狀态,ngxin判斷tomcat1為失效,然後重新啟動tomcat1,在這段時間内nginx判斷tomcat1還是失效狀态,超過2分鐘失效後,nginx繼續監聽到tomcat1正常後,那麼nginx會将tomcat1判斷為有效,将連接配接繼續均勻配置設定到2個tomcat上。
l 設定tomcat1在nginx1标記失效,tomcat1恢複正常,在nginx失效範圍内,将全部服務變為失效,然後重新開機:
Tomcat1為關閉,nginx設定tomcat1和tomcat2權重為10,tomcat1的max_fails為10,fail_timeout=120;在連接配接tomcat1的10次後,nginx收到tomcat1傳回connect refuse狀态,ngxin判斷tomcat1為失效,然後重新啟動tomcat1,在這段時間内nginx判斷tomcat1還是失效狀态,然後将tomcat2關閉,然後重新開機tomcat2,由于所有服務均失效,是以nginx 将所有服務重新置為有效進行監聽,然後将2連接配接均勻分布到了tomcat1和tomcat2上。
l http錯誤狀态,nginx是否記錄失效:
nginx設定tomcat1和tomcat2權重為10,tomcat1的max_fails為10,fail_timeout=120;配置proxy_next_upstream 500、404、502、503、504、timeout後,當HTTP狀态為500、502、503、504(timeout和refuse預設是記錄失效的)時,nginx會判斷該次請求為失敗記錄失敗狀态,其他所有HTTP均不記錄失敗。