实际上健康检查不是必须的,因为redispatch的存在保证了,就算有后端宕机,客户端仍将收到正确的响应。那么我们考虑关掉健康检查。通过upstream 的server配置的max_fails 参数
RR 的peer.get,如果max_fails 为0,则该后端总是可用的(就算它真有问题)。
if (peer->max_fails == 0
|| peer->fails < peer->max_fails)
{
break;
}
因为redispatch的次数,取决于后端的个数,所以后端的个数稍微多一点是有好处的。
下面是一些佐证分析的测试。
upstream test {
server 127.0.0.1:8060 max_fails=0;
server 127.0.0.1:8070 max_fails=0;
server 127.0.0.1:8080 max_fails=0;
server 127.0.0.1:8090 max_fails=0;
}
只有8060,8070是存活的,8080,8090处于不可用状态,这里max_fails=0,关闭了健康检查。
proxy_read_timeout 2;
读超时设为2S。
proxy_next_upstream error timeout;
默认当 error 和 timeout发生时,redispatch。
测试请求的sleep参数指定后端的sleep时间,code参数指定后端返回的http code。根据time和sleep时间的对比,判断重试了几个后端。
time curl "http://127.0.0.1:8099/index.php?sleep=3" -vv
real 0m4.014s
sleep=3,读超时,重试了2个后端。
修改配置 proxy_next_upstream error;
time curl "http://127.0.0.1:8099/index.php?sleep=3" -vv
real 0m2.018s
读超时,不再redispatch,重试了1个后端。
修改配置 proxy_next_upstream error http_504;
time curl "http://127.0.0.1:8099/index.php?sleep=1" -vv
real 0m1.022s
这个是正常请求。
time curl "http://127.0.0.1:8099/index.php?sleep=1&code=504" -vv
real 0m2.023s
让后端返回504,此时nginx会做redispatch,重试了2个后端
但是nginx返回给客户端的是502,不是504,因为所有的后端都返回504,nginx认为后端不可用,返回502.
测试健康检查,关掉redispatch。proxy_next_upstream off;
curl "http://127.0.0.1:8099/index.php?sleep=3" -vv
返回了两次502,两次504。存活的后端返回504,有问题的返回502。
修改 max_fails server 127.0.0.1:8060 max_fails=1; 对8060开启健康检查。
curl "http://127.0.0.1:8099/index.php?sleep=3" -vv
第一轮4次请求,返回两次502,两次504
8080和8090有问题,返回502,8060和8070响应超时,返回504,因为8060开启了健康检查,并且返回了504,所以被标记为不可用。
第二轮4次请求,返回三次502,一次504。8070没有开启健康检查,所以仍然返回504。
根据测试分析,业务请求(sleep 3s,或者 输出 http 504)可以让nginx误以为后端宕了,而这时后端活得好好的。在私有云平台,这个通常不是问题,把超时设大点,不返回5XX错误,可以避免这个问题。但是在公有云平台,这是致命的,因为业务可以编程输出5XX错误。有两种方法应对,一种是关闭健康检查,一种是修改nginx的代码,仅对 NGX_HTTP_UPSTREAM_FT_ERROR 判定为后端有问题。
Linux公社的RSS地址:https://www.linuxidc.com/rssFeed.aspx