7.10.3 健康检查与故障转移机制

本节聚焦 Web 服务高可用中的健康检查与故障转移机制,目标是确保后端实例异常可被快速识别并自动摘除,业务流量在可控范围内切换,避免雪崩与级联故障。内容涵盖健康检查类型、Nginx 侧实现、上游联动、故障转移策略与常见风险控制,并给出可执行示例、排错与练习。


1. 健康检查类型与适用场景#

按检查方式划分
- TCP 探活:仅验证端口可达,适用于简单服务或 TCP 代理;不反映应用层健康。
- HTTP/HTTPS 探活:基于状态码与响应内容校验,更可靠;推荐用于 Web 服务。
- 应用内自检接口/health/ready,可区分“存活/就绪”,适合微服务场景。

按触发方式划分
- 主动健康检查:代理层周期性探测,判断后端状态。
- 被动健康检查:请求失败后触发熔断,依赖真实流量。

示例:后端提供健康检查接口

# /opt/app/server.py(示例:Python 简易健康接口)
from http.server import BaseHTTPRequestHandler, HTTPServer

class H(BaseHTTPRequestHandler):
    def do_GET(self):
        if self.path == "/health":
            self.send_response(200); self.end_headers(); self.wfile.write(b"OK")
        elif self.path == "/ready":
            self.send_response(200); self.end_headers(); self.wfile.write(b"READY")
        else:
            self.send_response(404); self.end_headers()

HTTPServer(("0.0.0.0", 8080), H).serve_forever()

启动并验证:

python3 /opt/app/server.py
curl -i http://127.0.0.1:8080/health

2. Nginx 健康检查机制#

Nginx 原生不包含主动健康检查,但可以结合 upstream 失效参数、开源模块或商业版实现。常用组合如下:

2.1 被动检查(原生)#

  • max_fails:失败次数阈值
  • fail_timeout:统计窗口与摘除时间
  • 失败原因:连接超时、读超时、返回 5xx 等

示例(完整 upstream + location)

# /etc/nginx/conf.d/ha.conf
upstream backend {
    server 10.0.0.1:8080 max_fails=3 fail_timeout=10s;
    server 10.0.0.2:8080 max_fails=3 fail_timeout=10s;
    keepalive 32;
}

server {
    listen 80;
    location / {
        proxy_pass http://backend;
        proxy_connect_timeout 2s;
        proxy_read_timeout 3s;
        proxy_next_upstream error timeout http_500 http_502 http_503 http_504;
        proxy_next_upstream_tries 2;
    }
}

命令说明
- proxy_next_upstream:指定哪些错误触发切换
- proxy_next_upstream_tries:单请求最多切换次数
- max_fails/fail_timeout:统计失败并暂时摘除后端

验证:

nginx -t
systemctl reload nginx

2.2 主动检查(模块/商业版)#

方案 A:nginx_upstream_check_module(开源)

# 1) 安装依赖
yum -y install gcc make pcre-devel zlib-devel openssl-devel

# 2) 下载 Nginx 源码与 check 模块
cd /usr/local/src
wget http://nginx.org/download/nginx-1.22.1.tar.gz
git clone https://github.com/yaoweibin/nginx_upstream_check_module.git
tar xf nginx-1.22.1.tar.gz

# 3) 打补丁并编译
cd nginx-1.22.1
patch -p1 < ../nginx_upstream_check_module/check_1.20.1+.patch
./configure --prefix=/usr/local/nginx \
  --add-module=../nginx_upstream_check_module \
  --with-http_ssl_module
make && make install

配置示例(主动健康检查)

# /usr/local/nginx/conf/nginx.conf
http {
    upstream backend {
        server 10.0.0.1:8080;
        server 10.0.0.2:8080;

        check interval=3000 rise=2 fall=3 timeout=1000 type=http;
        check_http_send "GET /health HTTP/1.0\r\n\r\n";
        check_http_expect_alive http_2xx http_3xx;
    }

    server {
        listen 80;
        location / {
            proxy_pass http://backend;
        }
        location /status {
            check_status;
            access_log off;
        }
    }
}

预期效果

curl http://127.0.0.1/status
# 可看到 each upstream 的 up/down 状态

方案 B:Nginx Plus(商业版)
- 配置 health_check,并通过 API 查看状态
- 适用于企业生产环境


3. 故障转移策略设计#

3.1 负载均衡 + 自动摘除#

  • 探测失败后自动摘除后端实例
  • 不影响整体可用性,适用于横向扩展服务

示例:单请求失败切换

location / {
    proxy_pass http://backend;
    proxy_next_upstream error timeout http_500 http_502 http_503 http_504;
    proxy_next_upstream_tries 3;
}

3.2 主备切换(故障转移)#

  • 适用于状态敏感或需要独占资源服务
  • 搭配 Keepalived/VRRP 浮动 IP 实现主备切换

流程草图(原理)

flowchart TB
    C[Client] --> VIP[VRRP 虚拟IP]
    VIP --> N1[Nginx 主节点]
    VIP --> N2[Nginx 备节点]
    N1 --> U1[Upstream A]
    N1 --> U2[Upstream B]
    N2 -.接管.-> U1
    N2 -.接管.-> U2

3.3 跨机房/多地域切换#

  • 使用 DNS/全局负载均衡切流
  • 需配合 TTL 控制、健康检查与流量灰度

4. 故障检测与转移流程建议#

典型流程
1. 检测:连续探测失败(如 3 次)
2. 隔离:标记为 down,暂停接收流量
3. 通知:触发告警与自动化处理(重启/扩容)
4. 恢复:检测通过后重新加入

演练脚本(模拟后端故障)

# 1) 停止后端服务
pkill -f server.py

# 2) 观察 Nginx 请求切换
curl -I http://127.0.0.1/

# 3) 查看 Nginx 日志
tail -f /var/log/nginx/error.log

5. 关键参数与运维建议#

超时配置(避免请求卡死)

proxy_connect_timeout 2s;
proxy_read_timeout 3s;
proxy_send_timeout 3s;

失败判定

proxy_next_upstream error timeout http_500 http_502 http_503 http_504;
proxy_next_upstream_tries 2;

故障转移风险
- 后端无状态、会话共享(如 Redis)可显著降低切换成本
- 若存在长连接(WebSocket/HTTP2),需评估连接中断影响


6. 常见问题与规避#

问题 1:误判健康(健康接口依赖 DB/缓存)
- 现象:后端 DB 波动导致检查失败,服务被误摘除
- 规避:健康接口只做轻量检查,避免依赖外部组件

问题 2:健康检查频率过高导致雪崩
- 现象:大量探测挤占后端资源
- 规避:降低频率,增加 interval,设置轻量 URI

问题 3:频繁抖动(上下线频繁)
- 现象:请求时好时坏,流量抖动
- 规避:增加 rise/fallfail_timeout,设置退避策略

问题 4:单点检测
- 现象:检测节点异常导致误判
- 规避:多节点监控与告警交叉验证


7. 实战建议#

建议 1:健康接口拆分

/health  -> 只做存活检查
/ready   -> 可用性检查(依赖下游能力)

建议 2:结合监控平台
- Nginx 状态 + 业务 QPS + 响应耗时
- 触发自动扩缩容或重启

建议 3:灰度验证故障转移

# 使用 curl 模拟压测
for i in {1..50}; do curl -s -o /dev/null http://127.0.0.1/; done

8. 安装与排错#

排错 1:Nginx 配置错误

nginx -t
# 输出 "syntax is ok" 才可 reload

排错 2:upstream 无法访问

curl -I http://10.0.0.1:8080/health
ss -lntp | grep 8080

排错 3:主动检查模块未生效

/usr/local/nginx/sbin/nginx -V | grep -o check
# 预期输出:check(说明已编译模块)

9. 练习题#

  1. 在两台后端中模拟一台宕机,观察 proxy_next_upstream 的切换效果。
  2. 调整 max_failsfail_timeout,比较故障摘除速度。
  3. 搭建 /health/ready 两个接口,并在 Nginx 中分别验证。
  4. 使用 nginx_upstream_check_module 部署主动健康检查,并截图 /status 页面状态变化。

通过合理的健康检查与故障转移机制,Nginx 能够在后端故障时快速隔离故障节点并平滑切流,为 Web 服务提供稳定可靠的高可用能力。