7.3.3 健康检查与故障切换

健康检查与故障切换#

本节聚焦 Nginx 在反向代理场景中的被动健康检查与故障切换,通过失败统计与重试策略提升后端可用性,并给出可执行配置、验证、排错与练习。

原理草图(被动检查 + 故障切换流程)

文章图片

核心机制与配置要点
- max_fails:在 fail_timeout 窗口内允许的失败次数,超过即标记不可用。
- fail_timeout:失败统计窗口与摘除时间;过期后允许再次尝试。
- proxy_next_upstream:指定哪些错误触发重试,例如 error timeout http_502 http_503 http_504
- proxy_next_upstream_tries:最大重试次数,避免过度切换导致延迟放大。
- proxy_connect_timeout/proxy_read_timeout:连接与读超时,直接影响失败统计。

示例:被动健康检查与故障切换(完整可执行)

# /etc/nginx/conf.d/api.conf
upstream api_backend {
    server 10.0.0.11:8080 max_fails=3 fail_timeout=10s;
    server 10.0.0.12:8080 max_fails=3 fail_timeout=10s;
    server 10.0.0.13:8080 max_fails=3 fail_timeout=10s;
    keepalive 32;  # 连接复用,注意后端重启导致的连接失效
}

server {
    listen 80;
    server_name api.example.com;

    location /api/ {
        proxy_pass http://api_backend;

        # 超时控制
        proxy_connect_timeout 2s;
        proxy_read_timeout 5s;

        # 失败切换策略
        proxy_next_upstream error timeout http_502 http_503 http_504;
        proxy_next_upstream_tries 2;

        # 记录上游与状态,便于排错
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}

安装/生效步骤(命令解释清晰)

# 1) 检查配置语法
nginx -t
# 预期:syntax is ok / test is successful

# 2) 重载配置
nginx -s reload
# 预期:不重启主进程即可生效

验证与故障切换演示

# 在后端 10.0.0.11 停服务(示例)
# 假设后端为 systemd 管理
ssh 10.0.0.11 "systemctl stop myapi"

# 从客户端发起请求观察切换
curl -i http://api.example.com/api/health

# 预期:依然返回 200,且响应来自其他节点

日志与排错(关键命令 + 解释)

# 查看 Nginx 错误日志是否出现 upstream failed
tail -f /var/log/nginx/error.log

# 关键字定位上游超时/错误
grep -E "upstream|timeout|failed" /var/log/nginx/error.log

# 观察访问日志中 upstream 响应与状态
# 建议在 nginx.conf 中定义包含 $upstream_addr $upstream_status
tail -f /var/log/nginx/access.log

常见问题与修复建议
1. 频繁切换fail_timeout 过短或后端抖动,适当增大 fail_timeout,排查后端性能。
2. 切换不生效:确认 proxy_next_upstream 是否包含实际错误码;检查后端是否返回 5xx。
3. 切换导致延迟大proxy_next_upstream_tries 过大,建议 1~2 次。
4. keepalive 连接失效:后端重启后需等待连接回收,适当减小 keepalive 或开启健康检查模块。

练习
1. 将 max_fails 设置为 1,fail_timeout 设置为 5s,模拟单节点异常,观察摘除时长与恢复时机。
2. 分别对幂等与非幂等接口配置不同的 proxy_next_upstream_tries,比较响应延迟与失败率。
3. 添加访问日志字段 $upstream_addr $upstream_status,验证请求实际落到的后端节点。