1. 摘要
本文介紹Nginx的upstream模塊的指令和參數(shù)說(shuō)明丸升。
2. 配置示例及指令說(shuō)明
2.1 配置示例
2.2 指令
2.3 upstream相關(guān)變量
3. 參數(shù)配置及測(cè)試
3.1 max_fails 和 fail_timeout
3.2 proxy_next_upstream
3.3 nginx 與后端web連接時(shí)間的三個(gè)參數(shù)
2. 配置示例及指令說(shuō)明
2.1 配置示例
2.2 指令
指令名稱: upstream
語(yǔ)法:upstream name { … }
默認(rèn)值:none
使用環(huán)境:http
功能:該指令是一個(gè)組合型指令它描述了一組服務(wù)器驹溃,這組服務(wù)器將會(huì)被指令 proxy_pass 和 fastcgi_pass 作為一個(gè)單獨(dú)的實(shí)體使用蒜撮,它們可以將 server 監(jiān)聽(tīng)在不同的端口替蔬,而且還可以同時(shí)使用TCP和UNIX套接字監(jiān)聽(tīng)惭婿。服務(wù)器可以設(shè)置不同的權(quán)重驾诈,如果沒(méi)有設(shè)置權(quán)重凤瘦,那么默認(rèn)會(huì)將其設(shè)置為 1 冤竹。
指令名稱: ip_hash
語(yǔ)法:ip_hash
默認(rèn)值:none
使用環(huán)境:upstream
功能:如果使用了該指令,那么將會(huì)導(dǎo)致客戶端的請(qǐng)求以用戶端IP地址分布在 upstream 中的 server 之間茬射。它的關(guān)鍵技術(shù)在于對(duì)這個(gè)請(qǐng)求客戶端IP地址進(jìn)行哈希計(jì)算鹦蠕,這種方法保證了客戶端請(qǐng)求總是能夠傳遞到同一臺(tái)后臺(tái)服務(wù)器,但是如果該服務(wù)器被認(rèn)定為無(wú)效在抛,那么這個(gè)客戶端的請(qǐng)求將會(huì)被傳遞到其他服務(wù)器钟病,因此,這種機(jī)制是一個(gè)高概率將客戶端請(qǐng)求總是連接到同一臺(tái)服務(wù)器刚梭。
Nginx 的 upstream 支持 5 種分配方式肠阱,其中有三種為 Nginx 原生支持的分配方式,后兩種為第三方支持的分配方式朴读。
- 輪詢屹徘。upstream默認(rèn)采用的就是輪詢方式.
- 權(quán)重(weight)輪詢模式的加強(qiáng)版,每個(gè)后端server 默認(rèn) weight=1
- ip_hash 每個(gè)請(qǐng)求按照訪問(wèn)IP的hash結(jié)果分配這樣每個(gè)訪客會(huì)固定訪問(wèn)一個(gè)后端服務(wù)器衅金,可以解決session 一致問(wèn)題
- fair 第三方分配方式缘回。平地按照后端服務(wù)器的響應(yīng)時(shí)間(rt)來(lái)分配請(qǐng)求,響應(yīng)時(shí)間短即rt小的后端服務(wù)器優(yōu)先分配請(qǐng)求典挑。如果需要使用這種調(diào)度算法,必須下載Nginx的upstr_fair模塊啦吧。
- url_hash 平地按照后端服務(wù)器的響應(yīng)時(shí)間(rt)來(lái)分配請(qǐng)求您觉,響應(yīng)時(shí)間短即rt小的后端服務(wù)器優(yōu)先分配請(qǐng)求。如果需要使用這種調(diào)度算法授滓,必須下載Nginx的upstr_fair模塊琳水。
指令名稱: server
語(yǔ)法:server name [parameters]
默認(rèn)值:none
使用環(huán)境:upstream
功能:該指令用于設(shè)置服務(wù)器的 name,對(duì)于 name般堆,可以使用域名在孝、ip地址、端口或是 UNIX 套接字淮摔,如果一個(gè)域名被解析到多個(gè) IP 地址私沮,那么所有的 IP 地址都將會(huì)被使用。
可選的 parameters 如下:
- weight=NUMBER 用于設(shè)置服務(wù)器的權(quán)重和橙。如果沒(méi)有設(shè)置仔燕,那么它將會(huì)等于 1
- max_fails=NUMBER 該參數(shù)用于對(duì)后端服務(wù)器進(jìn)行檢測(cè),如果達(dá)到 NUMBER 次數(shù)依然失敗魔招,則該 server 會(huì)被暫停 fail_timeout 秒晰搀,如果沒(méi)有設(shè)置該參數(shù),那么嘗試的次數(shù)為1办斑,如果設(shè)置為 0 則關(guān)閉檢測(cè)外恕。失敗的依據(jù)是根據(jù) proxy_next_upstream 提供的。
- fail_timeout=TIME 該參數(shù)用于設(shè)置客戶端到達(dá) max_fails 次數(shù)后,該server 被暫停的時(shí)間鳞疲。如果沒(méi)有設(shè)置該參數(shù)罪郊,那么默認(rèn)為 10秒。
- down:如果為某一個(gè) server 設(shè)置了該參數(shù)建丧,那么標(biāo)記了這臺(tái) server 將永久離線排龄。通常這個(gè)參數(shù)與 ip_hash 一同使用。
- backup:該參數(shù)在 0.6.7 版本中提供翎朱,它是一個(gè)備用標(biāo)識(shí)橄维,如果出現(xiàn)所有的非備份服務(wù)器全部宕機(jī)或繁忙無(wú)法接受連接時(shí),那么才會(huì)使用本服務(wù)器拴曲,該參數(shù)無(wú)法和 ip_hash 指令一起使用争舞。
2.3 upstream相關(guān)變量
變量名:$upstream_addr
功能:該變量表示了處理該請(qǐng)求的 upstream 中 server 的地址
變量名:$upstream_cache_status
功能:該變量出現(xiàn)在 Nginx 0.8.3 版本中, 可能的值如下:
- MISS - 緩存中未被命中
- EXPIRED - 生存期期滿澈灼,請(qǐng)求被傳遞到后端服務(wù)器
- UPDATING - 生存期滿竞川,陳舊的響應(yīng)被使用,因?yàn)閜roxy/fastcgi_cache_use_stale 升級(jí)
- STALE - 生存期期滿叁熔,陳舊的響應(yīng)被使用委乌,因?yàn)?proxy/fastcgi_cache_use_stale
- HIT - 緩存命中
變量名:$upstream_status
功能:該變量為 upstream 中 server 的響應(yīng)狀態(tài)
變量名:$upstream_response_time
功能:upstream server 響應(yīng)的時(shí)間,單位為秒荣回,能夠精準(zhǔn)到毫秒遭贸。如果有多個(gè) server 響應(yīng)回答,那么會(huì)用逗號(hào)和冒號(hào)分隔開(kāi)
變量名:
HEADER
功能:HTTP 協(xié)議頭心软。例如:$upstream_http_host
3. 參數(shù)配置及測(cè)試
參數(shù)相關(guān)說(shuō)明介紹完畢壕吹,接下來(lái)重點(diǎn)測(cè)試部分參數(shù):
1臺(tái)反向代理(nginx/1.14.2)
2臺(tái)后端web(apache+php)
首先,查看客戶端 發(fā)起一次 連接請(qǐng)求的過(guò)程:
通過(guò)抓包删铃,可以看到 瀏覽器 請(qǐng)求一次 nginx 反向代理:
- (9耳贬、10、11) 客戶端 -> nginx TCP 三次握手成功
- (12猎唁、13)12. 瀏覽器發(fā)起 GET 請(qǐng)求 13. 回復(fù) ACK
- (14咒劲、15、16)nginx -> 后端web服務(wù) 三次握手成功
- (17诫隅、18) nginx 向后端web服務(wù)發(fā)起 get 請(qǐng)求缎患, web服務(wù)ACK回復(fù)nginx
- (19、20) 后端web服務(wù)返回請(qǐng)求數(shù)據(jù)給 nginx (這里返回HTTP狀態(tài)為 304 Not Modified)
- (21阎肝、22)nginx 連接后端服務(wù)采用的是HTTP1.0 挤渔,后端服務(wù)主動(dòng)發(fā)送FIN主動(dòng)斷開(kāi)連接,后端web服務(wù)器從ESTABLISHED轉(zhuǎn)為 TIME_WAIT
- (23)nginx 將后端返回的結(jié)果风题,再返回給客戶端瀏覽器
3.1 max_fails 和 fail_timeout
fail_timeout - 出錯(cuò)后判导,暫停server的時(shí)間嫉父。</pre>
主機(jī)信息:
(1)當(dāng) max_fails 為 0 , fail_timeout 為 0
通過(guò)瀏覽器快速刷新4次,分析如下:
一共發(fā)起了 4 次連接請(qǐng)求擂红,根據(jù) upstream默認(rèn)輪詢方式仪际,有兩次都輪詢到了 192.168.118.17 (服務(wù)關(guān)閉)上。
查看 web1(192.168.118.16)日志:一共發(fā)起了 4 次請(qǐng)求昵骤,而 web1 接收到了 4 次树碱,也就是這 4 次請(qǐng)求,都是 web1 來(lái)響應(yīng)的变秦。
為什么 4 次請(qǐng)求都是 web1 響應(yīng)的呢成榜?通過(guò)上圖,當(dāng) nginx 首次輪詢到 web2 時(shí)蹦玫,連接失敗赎婚,web2 返回 RST,nginx會(huì)再次發(fā)起請(qǐng)求到 web1 樱溉。
總結(jié):
(1)max_fails = 0 and fail_timeout = 0 時(shí)挣输,后端服務(wù)故障時(shí),依然會(huì)輪詢到故障主機(jī)福贞,且沒(méi)有暫停服務(wù)時(shí)間的限制撩嚼。
(2) max_fails = 0 and fail_timeout = 5
通過(guò)瀏覽器快速刷新向瓷,分析如下:
通過(guò)錯(cuò)誤日志可以看出肠套,當(dāng) upstream 沒(méi)有設(shè)置 最大錯(cuò)誤數(shù)(max_fails),無(wú)論后端server是否有效猖任,都會(huì)輪詢到該server上你稚,fail_timeout 設(shè)置任何值都是無(wú)效的。
(3) max_fails = 3 and fail_timeout = 5
通過(guò)瀏覽器快速刷新长搀,分析如下:
通過(guò)配置最大失敗連接數(shù)為 3 時(shí)宇弛,當(dāng)后端web2服務(wù)關(guān)閉后,nginx首次會(huì)嘗試 max_fails 次源请,如果仍然沒(méi)響應(yīng)枪芒,則暫停該server fail_timeout 秒彻况,然后每隔 fail_timeout 時(shí)間后嘗試一次,失敗則繼續(xù)暫停 fail_timeout 秒舅踪。
(4) max_fails = 3 and fail_timeout = 0
這種方式和 max_fails = 0 and fail_timeout = 3 測(cè)試結(jié)果一致纽甘,不在舉例。
通過(guò)上面 max_fails 和 fail_timeout 測(cè)試抽碌,當(dāng)要實(shí)現(xiàn)失敗后暫停服務(wù)時(shí)悍赢,max_fails 和 fail_timeout 任何一項(xiàng)都不能為 0 。
在測(cè)試中货徙,無(wú)論怎么刷新左权,nginx總是能夠返回正常服務(wù)的server 數(shù)據(jù),這是為什么破婆?明明已經(jīng)輪詢到服務(wù)失效的節(jié)點(diǎn)涮总,這里并沒(méi)有定義任何的 proxy_next_upstream
解釋:
針對(duì)nginx負(fù)載均衡upstream容錯(cuò)機(jī)制的使用說(shuō)明
(1)nginx 的 upstream 容錯(cuò)
Nginx默認(rèn)判斷失敗節(jié)點(diǎn)狀態(tài)是以 和 timeout (上面的例子就為web2-timeout)狀態(tài)為準(zhǔn),不以HTTP錯(cuò)誤狀態(tài)進(jìn)行判斷失敗祷舀,因?yàn)镠TTP只要能返回狀態(tài)說(shuō)明該節(jié)點(diǎn)還可以正常連接瀑梗,除非添加了proxy_next_upstream指令設(shè)置對(duì)404、502裳扯、503抛丽、504、500和time out等錯(cuò)誤進(jìn)行轉(zhuǎn)到備機(jī)處理饰豺。在next_upstream過(guò)程中亿鲜,會(huì)對(duì)fails進(jìn)行累加,如果備用機(jī)處理還是錯(cuò)誤則直接返回錯(cuò)誤信息(但404不進(jìn)行記錄到錯(cuò)誤數(shù)冤吨,如果不配置錯(cuò)誤狀態(tài)也不對(duì)其進(jìn)行錯(cuò)誤狀態(tài)記錄)綜述蒿柳,nginx記錄錯(cuò)誤數(shù)量只記錄timeout 、connect refuse漩蟆、502垒探、500、503怠李、504這6種狀態(tài)圾叼,timeout和connect refuse是永遠(yuǎn)被記錄錯(cuò)誤狀態(tài),而502捺癞、500夷蚊、503、504只有在配置proxy_next_upstream后nginx才會(huì)記錄這4種HTTP錯(cuò)誤到fails中髓介,當(dāng)fails大于等于max_fails時(shí)惕鼓,則該節(jié)點(diǎn)失效;
(2)nginx 處理節(jié)點(diǎn)失效和恢復(fù)的觸發(fā)條件
nginx可以通過(guò)設(shè)置max_fails(最大嘗試失敗次數(shù))和fail_timeout(失效時(shí)間唐础,在到達(dá)最大嘗試失敗次數(shù)后呜笑,在fail_timeout的時(shí)間范圍內(nèi)節(jié)點(diǎn)被置為失效夫否,除非所有節(jié)點(diǎn)都失效,否則該時(shí)間內(nèi)叫胁,節(jié)點(diǎn)不進(jìn)行恢復(fù))對(duì)節(jié)點(diǎn)失敗的嘗試次數(shù)和失效時(shí)間進(jìn)行設(shè)置凰慈,當(dāng)超過(guò)最大嘗試次數(shù),則失效fail_timeout 時(shí)間驼鹅,nginx每隔 fail_timeout時(shí)間嘗試一次后端server 有沒(méi)有恢復(fù)微谓,直到所有后端服務(wù)失效,則返回錯(cuò)誤頁(yè)面給客戶端输钩;
(3)所有節(jié)點(diǎn)失效后 nginx 將重新恢復(fù)所有節(jié)點(diǎn)進(jìn)行探測(cè)
如果探測(cè)所有節(jié)點(diǎn)均失效豺型,備機(jī)也為失效時(shí),那么nginx會(huì)對(duì)所有節(jié)點(diǎn)恢復(fù)為有效买乃,重新嘗試探測(cè)有效節(jié)點(diǎn)姻氨,如果探測(cè)到有效節(jié)點(diǎn)則返回正確節(jié)點(diǎn)內(nèi)容,如果還是全部錯(cuò)誤剪验,那么繼續(xù)探測(cè)下去肴焊,當(dāng)沒(méi)有正確信息時(shí),節(jié)點(diǎn)失效時(shí)默認(rèn)返回狀態(tài)為502功戚,但是下次訪問(wèn)節(jié)點(diǎn)時(shí)會(huì)繼續(xù)探測(cè)正確節(jié)點(diǎn)娶眷,直到找到正確的為止。
(4)通過(guò)proxy_next_upstream實(shí)現(xiàn)容災(zāi)和重復(fù)處理問(wèn)題
ngx_http_proxy_module 模塊中包括proxy_next_upstream指令
語(yǔ)法: proxy_next_upstream error | timeout | invalid_header | http_500 | http_502 | http_503 | http_504 |http_404 | off ...;
默認(rèn)值: proxy_next_upstream error timeout;
上下文: http, server, location
error 表示和后端服務(wù)器建立連接時(shí)啸臀,或者向后端服務(wù)器發(fā)送請(qǐng)求時(shí)届宠,或者從后端服務(wù)器接收響應(yīng)頭時(shí),出現(xiàn)錯(cuò)誤
timeout 表示和后端服務(wù)器建立連接時(shí)乘粒,或者向后端服務(wù)器發(fā)送請(qǐng)求時(shí)豌注,或者從后端服務(wù)器接收響應(yīng)頭時(shí),出現(xiàn)超時(shí)
invalid_header 表示后端服務(wù)器返回空響應(yīng)或者非法響應(yīng)頭
http_500 表示后端服務(wù)器返回的響應(yīng)狀態(tài)碼為500
http_502 表示后端服務(wù)器返回的響應(yīng)狀態(tài)碼為502
http_503 表示后端服務(wù)器返回的響應(yīng)狀態(tài)碼為503
http_504 表示后端服務(wù)器返回的響應(yīng)狀態(tài)碼為504
http_404 表示后端服務(wù)器返回的響應(yīng)狀態(tài)碼為404
off 表示停止將請(qǐng)求發(fā)送給下一臺(tái)后端服務(wù)器</pre>
運(yùn)用場(chǎng)景:
1)proxy_next_upstream http_500 | http_502 | http_503 | http_504 |http_404;
當(dāng)其中一臺(tái)返回錯(cuò)誤碼404,500...等錯(cuò)誤時(shí)灯萍,可以分配到下一臺(tái)服務(wù)器程序繼續(xù)處理轧铁,提高平臺(tái)訪問(wèn)成功率,多可運(yùn)用于前臺(tái)程序負(fù)載設(shè)置
2)proxy_next_upstream off
因?yàn)閜roxy_next_upstream 默認(rèn)值: proxy_next_upstream error timeout;
場(chǎng)景:
當(dāng)訪問(wèn)A時(shí)竟稳,A返回error timeout時(shí)属桦,訪問(wèn)會(huì)繼續(xù)分配到下一臺(tái)服務(wù)器處理熊痴,就等于一個(gè)請(qǐng)求分發(fā)到多臺(tái)服務(wù)器他爸,就可能出現(xiàn)多次處理的情況,如果涉及到充值果善,就有可能充值多次的情況诊笤,這種情況下就要把proxy_next_upstream關(guān)掉即可
proxy_next_upstream off
案例分析(nginx proxy_next_upstream導(dǎo)致的一個(gè)重復(fù)提交錯(cuò)誤):
一個(gè)請(qǐng)求被重復(fù)提交,原因是nginx代理后面掛著2個(gè)服務(wù)器巾陕,請(qǐng)求超時(shí)的時(shí)候(其實(shí)已經(jīng)處理了)讨跟,結(jié)果nigix發(fā)現(xiàn)超時(shí)纪他,有把請(qǐng)求轉(zhuǎn)給另外臺(tái)服務(wù)器又做了次處理。
解決辦法:
proxy_next_upstream:off
3.2 proxy_next_upstream
語(yǔ)法:
proxy_next_upstream error | timeout | invalid_header | http_500 | http_502 | http_503 | http_504 |http_404 | off ...;
默認(rèn)值: proxy_next_upstream error timeout;
上下文: http, server, location
web1 - sleep 1秒
web2 - 返回 500 狀態(tài)碼
nginx配置如下:upstream 默認(rèn)后端server失效標(biāo)準(zhǔn): timeout 和 Connect refuse茶袒,在這里例子中,使用
proxy_next_upstream http_500 http_502 http_504
[root@localhost ~]# curl -I -w %{time_total}:%{time_connect}:%{time_starttransfer} http://192.168.118.15/test.php
HTTP/1.1 200 OK
Server: nginx/1.14.2
Date: Thu, 14 Mar 2019 10:53:51 GMT
Content-Type: text/html; charset=UTF-8
Connection: keep-alive
X-Powered-By: PHP/5.4.16
RS: Web1
1.006:0.000:1.006
三次都是返回 200 狀態(tài)凉馆,說(shuō)明 proxy_next_upstream 已經(jīng)將后端server 返回 500 狀態(tài)的主機(jī)攔截為失效薪寓。
3.3 nginx 與后端web連接時(shí)間的三個(gè)參數(shù)
proxy_connect_timeout : 后端服務(wù)器連接的超時(shí)時(shí)間發(fā)起握手等候響應(yīng)超時(shí)時(shí)間
proxy_read_timeout: 連接成功后,等候后端服務(wù)器響應(yīng)時(shí)間其實(shí)已經(jīng)進(jìn)入后端的排隊(duì)之中等候處理(也可以說(shuō)是后端服務(wù)器處理請(qǐng)求的時(shí)間)
proxy_send_timeout : 后端服務(wù)器數(shù)據(jù)回傳時(shí)間_就是在規(guī)定時(shí)間之內(nèi)后端服務(wù)器必須傳完所有的數(shù)據(jù)
這里對(duì) proxy_read_timeout 進(jìn)行測(cè)試:
nginx 配置:web1 - test.php - sleep 3
web2 - test.php - sleep 5
測(cè)試結(jié)果:
[root@localhost ~]# curl -I -w %{time_total}:%{time_connect}:%{time_starttransfer} http://192.168.118.15/test.php
HTTP/1.1 504 Gateway Time-out
Server: nginx/1.14.2
Date: Thu, 14 Mar 2019 11:27:59 GMT
Content-Type: text/html
Content-Length: 537
Connection: keep-alive
ETag: "5c89b5df-219"
2.004:0.001:2.004
三次返回結(jié)果一致澜共,每次請(qǐng)求均耗時(shí) 2秒向叉,這是因?yàn)?proxy_read_timeout 設(shè)置為 2s ,而后端的程序: web1-sleep 3 嗦董、web2-sleep 5母谎,都無(wú)法及時(shí)響應(yīng)。
修改 proxy_read_time 為 3 秒京革,測(cè)試如下:
[root@localhost ~]# curl -I -w %{time_total}:%{time_connect}:%{time_starttransfer} http://192.168.118.15/test.php
HTTP/1.1 200 OK
Server: nginx/1.14.2
Date: Thu, 14 Mar 2019 11:33:30 GMT
Content-Type: text/html; charset=UTF-8
Connection: keep-alive
X-Powered-By: PHP/5.4.16
RS: Web1
3.004:0.001:3.004
[root@localhost ~]# curl -I -w %{time_total}:%{time_connect}:%{time_starttransfer} http://192.168.118.15/test.php
HTTP/1.1 504 Gateway Time-out
Server: nginx/1.14.2
Date: Thu, 14 Mar 2019 11:33:35 GMT
Content-Type: text/html
Content-Length: 537
Connection: keep-alive
ETag: "5c89b5df-219"
3.005:0.001:3.005
當(dāng)輪詢到 web1 -sleep 3秒時(shí)奇唤,滿足 proxy_read_timeout 返回 200 狀態(tài),當(dāng)輪詢到 web2 -sleep 5秒時(shí)存崖,超過(guò) proxy_read_timeout 返回 504 狀態(tài)冻记。
總結(jié):
對(duì)于 max_fails 和 fail_timeout 必須連用,但是都不能為 0 来惧,否則失效檢查被禁止冗栗,每次都會(huì)輪詢到失敗的節(jié)點(diǎn)。
proxy_next_upstream 的使用一定要謹(jǐn)慎供搀,有時(shí)候程序員會(huì)通過(guò) HTTP 狀態(tài)碼來(lái)傳遞信息隅居,如果不小心禁止了會(huì)造成不必要的麻煩。
proxy_read_timeout 參數(shù)根據(jù)業(yè)務(wù)場(chǎng)景需要進(jìn)行設(shè)定葛虐,不宜過(guò)長(zhǎng)胎源,也不宜過(guò)短。
4. 參考
(1)Nginx - upstream 模塊及參數(shù)測(cè)試[參數(shù)解析很詳細(xì)] https://www.cnblogs.com/hukey/p/10534021.html
(2)upstream模塊官網(wǎng)
http://nginx.org/en/docs/http/ngx_http_upstream_module.html