upstream 服务器返回 500 错误 Nginx 如何配置被动健康检查

文章导读
原生 Nginx 开源版本的被动健康检查主要关注连接层面的失败,默认不会把 HTTP 500 状态码计入故障次数,建议通过配置请求重试机制来缓解用户感知,若需严格基于状态码剔除节点需考虑 Plus 版本或第三方模块。
📋 目录
  1. A 命令速用版
  2. B 为什么会这样
  3. C 分步处理
  4. D 怎么验证是否生效
  5. E 常见坑
  6. F 参考来源
A A

原生 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 服务器返回 500 错误 Nginx 如何配置被动健康检查

第二步,配置上游服务器组。确保 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。

upstream 服务器返回 500 错误 Nginx 如何配置被动健康检查

制造测试请求,可以通过脚本或工具向后端发送请求,并模拟后端返回 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