nginx作为反向代理服务器,后端有多台服务器,上层通过一定机制保证容错和负载均衡。
nginx的重试机制就是容错的一种
官方链接:http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_next_upstream
Syntax: |
|
Default: |
|
Context: |
|
指定在哪种情况下将请求传递到下一个服务器:
error | 与服务器建立连接,向服务器传递请求或读取响应头时发生错误; |
timeout | 与服务器建立连接,向服务器传递请求或读取响应头时发生超时; |
invalid_header | 服务器返回空的或无效的响应; |
http_500 | 服务器返回代码为500的响应; |
http_502 | 服务器返回代码为502的响应; |
http_503 | 服务器返回代码为503的响应; |
http_504 | 服务器返回代码为504的响应; |
http_403 | 服务器返回代码为403的响应; |
http_404 | 服务器返回代码为404的响应; |
http_429 | 服务器返回代码为429的响应;(1.11.13); |
non_idempotent | 通常,具有请求 非幂等 方法(POST,LOCK,PATCH)不传递到请求是否已被发送到上游服务器(1.9.13)的下一个服务器; 启用此选项将允许重试此类请求; |
off | 禁用将请求传递到下一个服务器。 |
- 应该记住的是,只有在还没有任何内容发送给客户端的情况下,才有可能将请求传递给下一台服务器。即,如果在响应的传输过程中发生错误或超时,则无法解决该问题。
- 该指令还定义了与服务器通信的不成功尝试 的情况下。错误、超时和invalid_header的情况始终被视为不成功的尝试,即使在该指令中没有指定他们。只有在指令中指定http_500、http_502、http_503、http_504和http_429的情况下才被视为不成功的尝试。http_403和http_404 永远不会被视为不成功的尝试。
下面还有一个参数影响重试次数,0表示不限制。
Syntax: proxy_next_upstream_tries number;
Default: proxy_next_upstream_tries 0;
Context: http, server, location
#该配置决定了最多重试多少次,0表示不限制。
配置示例:
upstream app-proxy {
server 192.168.5.100:8080;
server 192.168.5.101:8080;
check interval=2000 rise=1 fall=3 timeout=3000 type=http;
check_keepalive_requests 1;
# check_http_send "HEAD /status/status.html HTTP/1.1\r\n\r\n";
check_http_send "GET /status/status.html HTTP/1.1\r\nConnection: close\r\nHost: localhost\r\n\r\n";
check_http_expect_alive http_2xx http_3xx;
}
location / {
proxy_pass http://app-proxy;
proxy_next_upstream error timeout http_500 http_502 http_503 http_504;
proxy_next_upstream_tries 3;
proxy_connect_timeout 60s;
proxy_read_timeout 60s;
proxy_send_timeout 60s;
proxy_pass_request_headers on;
proxy_set_header Host $host:$server_port;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
set $domain default;
Ps:
upstream fail_timeout可能造成的问题
upstream web_server {
server 192.168.1.10:8000 weight=1 max_fails=3 fail_timeout=10s;
server 192.168.1.10:8000 weight=1 max_fails=3 fail_timeout=10s;
keepalive 2000;
}
通过配置上游服务器的max_fails 和fail_timeout,来指定每个上游服务器,当fail_timeout时间内失败了max_fails次请求,则认为该上游服务器不可用/不存活,然后会摘掉该上游服务器,fail_timeout时间后会再次将该服务器加入到存活上游服务器列表进行重试。
在nginx的配置文件中,proxy_next_upstream项定义了什么情况下进行重试,默认情况下,当请求服务器发生错误或超时时,会尝试到下一台服务器。
- proxy_connect_timeout time:与后端/上游服务器建立连接的超时时间,默认为60s
- proxy_read_timeout time:设置从后端/上游服务器读取响应的超时时间,默认为60s,此超时时间指的是两次成功读操作间隔时间,而不是读取整个响应体的超时时间,如果在此超时时间内上游服务器没有发送任何响应,则Nginx关闭此连接。
- proxy_send_timeout time:设置往后端/上游服务器发送请求的超时时间,默认为60s,此超时时间指的是两次成功写操作间隔时间,而不是发送 整个请求的超时时间,如果在此超时时间内上游服务器没有接收任何响应,则Nginx关闭此连接。
考虑一个场景:
proxiy_read_timeout设置5s,当请求转发到服务器A,若处理时间超过5S(比如大文件上传),此时被nginx认定失败,转发请求到服务器B,这样A、B服务器将会重复处理数据。(当然,这种场景,内网可以通过机器名访问该服务器进行操作,就可以绕过nginx了,不过外网就没办法了。)
在处理POST请求的时候也需要注意类似的问题。网上有一篇讨论如何阻止POST请求的超时重试,感兴趣的可以看看。点击打开链接
将if指令(具有少数有效用例之一)与自定义错误处理程序结合使用:
upstream backend {
server backend1;
server backend2;
}
server {
server_name www.qsh.com;
location / {
error_page 598 = @retry;
error_page 599 = @no_retry;
if ($request_method = POST) {
return 599;
}
return 598;
}
location @retry {
rewrite ^/api/(.*) /$1 break;
add_header Method "GET";
proxy_pass http://backend;
}
location @no_retry {
rewrite ^/api/(.*) /$1 break;
add_header Method "POST";
proxy_pass http://backend;
proxy_next_upstream off;
}
}
总结:根据不同的业务场景考虑设置不同的超时时间