這裡只討論作反向代理時,當上游服務發生如介面超時、返回指定狀態碼等狀況時而導致nginx超時重試。 這裡使用的nginx版本為1.16.1,可通過nginx -V查看版本。 超時重試主要通過配置ngx_http_upstream_module和ngx_http_proxy_module模塊中欄位實現 ...
這裡只討論作反向代理時,當上游服務發生如介面超時、返回指定狀態碼等狀況時而導致nginx超時重試。
這裡使用的nginx版本為1.16.1
,可通過nginx -V
查看版本。
超時重試主要通過配置ngx_http_upstream_module
和ngx_http_proxy_module
模塊中欄位實現的。
這兩個模塊的官方文檔:
- https://nginx.org/en/docs/http/ngx_http_proxy_module.html
- https://nginx.org/en/docs/http/ngx_http_upstream_module.html#upstream
準備的工作:
- 準備一個後臺服務,向外暴露訪問地址,服務收到請求後,處理的時間為5s(當然你可以設置為其它大小),隨後返回結果。這是用來模擬nginx訪問上游服務介面時超時場景。
- 運行兩個這樣相同的後臺服務實例,對外暴露的埠分別為9090和9091,用來模擬nginx作負載均衡的場景。
- nginx配置一個server,暴露埠9000,用於接收請求,並把請求分發到9090和9091的兩台實例上。
具體配置:
upstream RETRY_TEST_SERVER {
server 127.0.0.1:9090;
server 127.0.0.1:9091;
}
server {
listen 9000;
server_name localhost;
location / {
proxy_pass http://RETRY_TEST_SERVER;
proxy_next_upstream timeout;
proxy_read_timeout 3;
}
}
配置欄位解釋:
-
proxy_pass
即分發到哪個upstream上
-
proxy_next_upstream
用來配置哪些情景下會重試。當nginx收到請求,並把請求轉發到
RETRY_TEST_SERVER
,upstream預設的負載均衡策略為輪詢,第一次請求轉到9090埠,若9090服務實例響應超時,那麼將會將請求轉到9091,這個“響應超時”,就是這個欄位配置的觸發場景。可配置的欄位有:- timeout
- error
- http_500
預設的配置為
proxy_next_upstream error timeout
;所有的配置列表及含義:https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_next_upstream
-
proxy_read_timeout
配置從上游服務讀取的超時時間。
官方解釋為:
Defines a timeout for reading a response from the proxied server. The timeout is set only between two successive read operations, not for the transmission of the whole response. If the proxied server does not transmit anything within this time, the connection is closed.
運行
由於設置了proxy_read_timeout
為3秒,實例的響應時間為5秒,所以當訪問地址curl localhost:9000/test/delay
(這是實例的介面測試地址)時:
- 請求路由到9090埠,9090接收到請求,3秒後請求超時
- 由於配置了
proxy_next_upstream timeout
,即在發生超時時,會路由到下一節點,這時請求會路由到9091 - 3秒過後請求再次超時,nginx返回給客戶端錯誤信息:Gateway Timeout;
註意
-
由於作測試用,為方便會將多個相同的實例部署到本機通過埠作負載均衡測試,如:
upstream RETRY_TEST_SERVER { server 127.0.0.1:9090; server 127.0.0.1:9091; }
我在測試時,server 後的
127.0.0.1
一開始是寫成localhost
,測試9090發生超時時,沒有路由到9091,而是又在9090執行了一次,改成127.0.0.1
後正常。 -
upstream 的 server 模塊後還可以添加其它屬性欄位:
upstream RETRY_TEST_SERVER { server 127.0.0.1:9090 max_fails=2 fail_timeout=10s; server 127.0.0.1:9091 max_fails=2 fail_timeout=10s; }
官方文檔:https://nginx.org/en/docs/http/ngx_http_upstream_module.html#server
-
max_fails
和fail_timeout
max_fails
和fail_timeout
須結合使用,意為“在多長時間內訪問server多少次不可用”時,標記這個server節點不可用,若不可用則在此周期內當該server收到請求後直接返回錯誤,即nginx會直接返回給客戶端 "Bad Gateway",等到下一個 "fail_timeout"周期,才會再次嘗試該server是否可用。(至於"如何判斷是否可用",則根據欄位proxy_next_upstream
的配置。)這一點相當重要。如實例有兩個請求地址,一個耗時較長
/test/slow
,一個耗時較短/test/fast
;當介面/test/slow
超時時,指定時間(fail_timeout)超過最大嘗試次數(max_fails)時,此時9090標記為不可用,此時請求/tset/fast
路由到9090上時,nginx 會直接返回錯誤(Bad Gateway),即超時介面影響了正常介面的調用。我建議有兩種方式:
-
提高檢測是否可用的頻率
即使 fail_timeout/max_fails變小。如
max_fails=5 fail_timeout=10
要比max_fails=2 fail_timeout=10
可靠 -
為耗時長的介面單獨配置upstream和server(推薦)
-
-