nginx proxy_next_upstream 與openresty balancer.set_more_tries的使用

語言: CN / TW / HK

背景

我們這邊閘道器服務使用的 kong,前段時間上線一個服務,這個服務它報錯了,產生了502的錯誤碼,追查這個報錯的時候發現了閘道器服務的兩個可疑的地方,第一個疑點是我們在Kong上配置的 Retries = 5,但是實際實際上我們的代理重試至多隻會重試三次。第二個疑點是我們的重試只重試了502 和 504,大量的500錯誤沒有重試。帶著這兩個問題了查了下kong和openresty程式碼。

結論

首先給出問題的結論

第一個問題 Kong上配置的 Retries = 5,但是實際上只會重試三次。出現這個問題的原因是因為我們在nginx上有一行配置

proxy_next_upstream_tries 3;

當我們在基於openresty Kong 上做 balancer.set_more_tries(5) 這個操作的時候nginx會基於保護措施啟用nginx的配置 proxy_next_upstream_tries,所以proxy重試的時候最多隻能重試三次。

第二個問題,就是為什麼只有502 504 作出了重試,而且500沒有做重試

這個的原因也是因為我們在nginx的配置裡面有這麼一行配置

proxy_next_upstream error timeout http_502 http_504 non_idempotent;

只需要加上http_500 500的錯誤碼就可以重試了。

問題的定位

先說一下第一個問題的定位過程

主要是不知道有 nginx 有proxy_next_upstream_tries 這個引數,一直以為是openresty balancer.set_more_tries 控制的重試次數,一度自以為是的覺得這是bug,都想提個issues,直到在openresty的群組郵件裡面春哥有一個關於這個問題的回覆。

這個問題春哥在openresty的郵件群組裡作出過解釋

Hello!

2015-11-19 18:52 GMT+08:00 DeJiang Zhu:
>> > - 在 `proxy_next_upstream_tries 0;` 的時候, set_more_tries 好像沒有效果了.
>
> 我測試了也是這樣
> 然後看了程式碼發現: set_more_tries 並不能超過 proxy_next_upstream_tries 的配置 [1]

這是故意的,proxy_next_upstream_tries 規定的是重試上限。這可以避免 Lua 程式碼邏輯上的錯誤而導致無休止的重試。

Regards,
-agentzh

就看到了 proxy_next_upstream_tries 配置,以及互斥的時候以哪個為準。

第二個問題,上游500的錯誤碼沒有被重試。

這個問題的定位主要是陷入了以前引入Kong的一個誤區了,我們的服務引入Kong的其中一個原因就是有些服務重啟中發生錯誤的不能將服務重試到沒有問題的上游伺服器上去(其實主要是nginx不能按照我們的預想重試到上游服務上)。所以一直以為這是Kong的問題,所以把Kong的Kong init中關於Kong.balancer()的方法看了很長時間,測試了好多次,才確定不是這裡問題,後來又去看了下 Passive health checks 被動健康檢查程式碼,以為是這裡做了重試,上游服務區的列表輪訓引起的,最後也確定了跟這裡沒有關係。

最後一個一個過proxy_XXX的方法的時候,發現了 proxy_next_upstream 的配置說明,這個函式其實手冊將的特別清楚

http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_next_upstream
Specifies in which cases a request should be passed to the next server:

error
an error occurred while establishing a connection with the server, passing a request to it, or reading the response header;
timeout
a timeout has occurred while establishing a connection with the server, passing a request to it, or reading the response header;
invalid_header
a server returned an empty or invalid response;
http_500
a server returned a response with the code 500;
http_502
a server returned a response with the code 502;
....
non_idempotent
normally, requests with a non-idempotent method (POST, LOCK, PATCH) are not passed to the next server if a request has been sent to an upstream server (1.9.13); enabling this option explicitly allows retrying such requests;

其它引數挺簡單的,有哪些請求應該被轉發到下一個上游伺服器。主要是最後一個引數

non_idempotent, 預設情況下一些非冪等的函式(POST, LOCK, PATCH)不會被轉發到下一個上游伺服器,這個引數會允許此類請求也被轉發到下一個上游伺服器上。

還是應該多研究書冊,仔細看說明