原生 Nginx 开源版本的被动健康检查主要关注连接层面的失败,默认不会把 HTTP 500 状态码计入故障次数,建议通过配置请求重试机制来缓解用户感知,若需严格基于状态码剔除节点需考虑 Plus 版本或第三方模块。
先说结论:开源版 Nginx 的 max_fails 机制不统计 HTTP 500 错误,应优先配置 proxy_next_upstream 实现故障转移。
- 先确认:检查当前 Nginx 是开源版还是 Plus 版,两者健康检查能力不同。
- 先处理:在 location 块中配置 proxy_next_upstream http_500 实现请求重试。
- 再验证:观察 access.log 中 upstream_status 变化,确认请求是否成功转发。
命令速用版
upstream backend {
server 192.168.1.10:8080 max_fails=3 fail_timeout=30s;
server 192.168.1.11:8080 max_fails=3 fail_timeout=30s;
}
server {
location / {
proxy_pass http://backend;
proxy_next_upstream http_500 http_502 http_503 http_504;
proxy_next_upstream_tries 2;
proxy_next_upstream_timeout 10s;
}
}为什么会这样
Nginx 的被动健康检查机制核心在于 upstream 模块中的 max_fails 和 fail_timeout 参数。在开源版本中,这两个参数统计的是与后端服务器建立连接或通信过程中的失败,例如连接拒绝、连接超时或读取超时。
HTTP 500 错误意味着 Nginx 成功连接到了后端服务器,并且后端服务器也成功返回了响应,只是响应内容表示应用程序内部出错。从网络通信层面看,这是一次成功的交互,因此默认不会触发 max_fails 计数,也不会导致该节点被暂时剔除。
为了在不升级版本的前提下改善体验,通常使用 proxy_next_upstream 指令。它的作用不是标记节点健康状态,而是当当前节点返回特定错误码时,将当前请求重试转发给上游组中的下一个节点。
分步处理
第一步,编辑 Nginx 配置文件。通常位于/etc/nginx/nginx.conf 或/etc/nginx/conf.d/下的站点配置文件中。找到对应的 upstream 块和 server 块。
第二步,配置上游服务器组。确保 upstream 块中定义了至少两台服务器,并设置了 max_fails 和 fail_timeout。注意,这里的 max_fails 依然只针对连接故障,但保留配置有助于处理真正的宕机情况。
第三步,配置重试策略。在 server 块的 location 上下文里,添加 proxy_next_upstream 指令。将 http_500 加入参数列表,同时建议加上 http_502、http_503 和 http_504 等常见网关错误。
第四步,限制重试范围。配置 proxy_next_upstream_tries 限制最大重试次数,避免所有节点都故障时请求无限循环。配置 proxy_next_upstream_timeout 限制重试总耗时,防止请求长时间挂起。
第五步,检查配置并重载。执行 nginx -t 检查语法是否正确,确认无误后执行 nginx -s reload 使配置生效。
怎么验证是否生效
查看访问日志是验证配置最直接的方法。确保 log_format 中包含了 upstream_status 变量,格式示例为$upstream_status。
制造测试请求,可以通过脚本或工具向后端发送请求,并模拟后端返回 500 错误。观察 Nginx 的 access.log,如果配置生效,你会看到同一个请求对应的 upstream_status 可能出现多个状态码,例如"500, 200",表示第一次尝试得到 500,重试后得到 200。
同时检查 error.log,确认没有发生过多的 upstream 连接错误。如果日志中出现 upstream timed out 或 connection refused,说明是连接层面的问题,此时 max_fails 才会生效。
常见坑
第一个坑是误以为 max_fails 能统计 500 错误。很多管理员配置了 max_fails=3 后发现服务器返回多次 500 依然没有被剔除,这是因为机制定义不同,不要在此处浪费排查时间。
第二个坑是重试风暴。如果所有后端节点都同时返回 500 错误,且没有设置 proxy_next_upstream_tries 限制,Nginx 可能会在所有节点间反复重试,导致后端压力倍增。务必设置重试次数上限。
第三个坑是 POST 请求重试风险。默认情况下,proxy_next_upstream 不会重试非幂等请求(如 POST),除非显式配置了 proxy_next_upstream non_idempotent。对于涉及数据写入的接口,开启此选项需谨慎,避免重复提交数据。
参考来源
- Nginx Official Documentation, ngx_http_upstream_module, https://nginx.org/en/docs/http/ngx_http_upstream_module.html
- Nginx Official Documentation, ngx_http_proxy_module, https://nginx.org/en/docs/http/ngx_http_proxy_module.html