故障检测与自动切换策略

5.2k 词

摘要:在代理服务的运营中,节点故障是无法完全避免的——IP 被封、服务器宕机、线路劣化都可能随时发生。真正区分服务质量的不是”节点会不会出问题”,而是”出问题后多快能恢复”。本文系统讨论故障检测的方法和自动切换的实现策略,帮你构建高可用的代理服务架构。


故障类型分析

要设计有效的故障转移策略,首先需要理解代理节点可能遭遇的各类故障。不同类型的故障有不同的表现、检测难度和恢复方式。

IP 被 GFW 封锁

这是最常见也最令人头疼的故障类型。表现为节点突然无法连接,TCP 握手超时。GFW 的封锁可能是全端口封锁(整个 IP 不可达),也可能是特定端口封锁。

特征:从中国大陆无法连接,但从海外仍可正常访问。ping 不通或极高丢包率。封锁通常是持久性的——被封的 IP 短期内不会自动解封。

恢复方式:更换 IP 地址。这是唯一可靠的恢复手段。有些运营者会保留一批备用 IP,有些则通过云服务商 API 动态更换。

服务器宕机

服务器本身的硬件故障、操作系统崩溃、或云服务商的基础设施问题导致服务器不可用。

特征:从任何位置都无法连接。如果是云服务商问题,通常会影响同一数据中心的多台服务器。

恢复方式:等待服务商修复;或在其他服务器上重新部署。如果有自动化部署体系,恢复时间可以控制在分钟级。

ISP 线路问题

不是 GFW 主动封锁,而是运营商之间的线路拥塞或路由变更导致的连接质量下降。

特征:不是完全不能连接,而是延迟大幅增加、丢包率升高、速度明显下降。通常有时间规律——晚高峰(20:00-23:00)严重,凌晨恢复。可能只影响特定运营商(如联通用户正常但电信用户卡顿)。

恢复方式:等待线路恢复;或切换到经过不同线路的备用节点。使用 IPLC/IEPL 等专线可以避免此类问题,但成本较高。

证书过期

使用 TLS 证书的协议配置(如 VLESS+TLS+WebSocket)中,Let’s Encrypt 证书每 90 天需要续签。如果自动续签失败,客户端会因证书过期而拒绝连接。

特征:客户端报告 TLS 握手失败或证书验证错误。服务本身仍在运行,只是 TLS 层面出问题。

恢复方式:手动或自动续签证书并重启服务。使用 Reality 协议可以完全避免证书管理问题,因为 Reality 不需要自己的 TLS 证书。

后端进程崩溃

代理后端(XrayR、V2bX 等)的进程因 bug、内存溢出或配置错误而崩溃。

特征:端口不再监听,但服务器本身仍可通过 SSH 登录。systemd 或 Docker 的自动重启机制通常会在几秒内恢复进程。

恢复方式:如果配置了 systemd 的 Restart=on-failure 或 Docker 的 restart: always,进程会自动重启。否则需要手动重启服务。


故障检测方法

检测速度直接决定恢复速度。检测方法从简单到复杂分为三个层次。

第一层:TCP 连接检测

最基本的检测方式——尝试与节点的服务端口建立 TCP 连接。如果连接超时或被拒绝,则判定节点不可用。

1
2
3
4
5
6
7
8
9
10
11
12
# 简单的 TCP 端口检测脚本
#!/bin/bash
HOST="1.2.3.4"
PORT=443
TIMEOUT=5

if timeout $TIMEOUT bash -c "echo > /dev/tcp/$HOST/$PORT" 2>/dev/null; then
echo "节点 $HOST:$PORT 在线"
else
echo "节点 $HOST:$PORT 离线!"
# 触发告警或切换逻辑
fi

优点:实现简单,资源消耗极低。

局限:只能检测端口是否可达。如果后端进程虽然在监听但已经无法正常处理代理请求(比如与面板的通信中断导致鉴权失败),TCP 检测无法发现这个问题。

第二层:协议级检测

在 TCP 连接基础上,模拟代理客户端的行为,实际发起一次代理请求。如果能成功通过代理访问到目标网页,则判定节点正常。

这种检测方式能发现 TCP 检测遗漏的问题:后端进程运行异常、鉴权失败、协议配置错误等。

实现方式:使用代理客户端的 API 接口发起一次测试请求。例如,通过 curl 指定 SOCKS5 代理访问特定 URL:

1
2
3
4
5
# 通过节点代理访问测试页
curl -x socks5://127.0.0.1:1080 \
--connect-timeout 10 \
-s -o /dev/null -w "%{http_code}" \
https://www.google.com/generate_204

如果返回 HTTP 204,说明代理链路完整可用。

第三层:业务级检测

最全面的检测方式——不仅检查代理是否可用,还检查特定业务功能是否正常。例如:

  • 流媒体解锁检测:通过节点访问 Netflix、Disney+ 等流媒体的 API 接口,检查是否返回解锁状态
  • 延迟和速度检测:不仅要求能连通,还要求延迟低于某个阈值、下载速度高于某个标准
  • DNS 解析检测:检查通过节点进行的 DNS 解析是否返回正确结果

业务级检测最准确,但实现复杂度和资源消耗也最高。建议将其作为定期(如每小时)的补充检测,而非高频的核心检测手段。


客户端侧故障转移

对于终端用户来说,最直接的故障转移发生在客户端——当正在使用的节点不可用时,客户端自动切换到备用节点。

Clash 的代理组策略

Clash 系客户端提供了完善的代理组机制来实现自动故障转移。

url-test 策略组:根据延迟测试结果自动选择最快的节点。

1
2
3
4
5
6
7
8
9
10
11
12
proxy-groups:
- name: "自动选择"
type: url-test
proxies:
- 香港节点1
- 香港节点2
- 日本节点1
- 新加坡节点1
url: "https://www.gstatic.com/generate_204"
interval: 300 # 每 5 分钟测试一次
tolerance: 50 # 延迟差异超过 50ms 才切换
lazy: true # 没有流量时不主动测试

fallback 策略组:按优先级依次尝试节点,只在当前节点不可用时切换到下一个。这种策略更适合希望固定使用某个节点、只在它不可用时才切换的场景。

1
2
3
4
5
6
7
8
9
proxy-groups:
- name: "故障转移"
type: fallback
proxies:
- 首选节点
- 备用节点1
- 备用节点2
url: "https://www.gstatic.com/generate_204"
interval: 300

关键区别:url-test 总是选最快的,节点切换频繁;fallback 优先使用列表靠前的节点,只在故障时切换,更稳定。

切换速度优化

客户端故障转移的速度取决于两个因素:

  1. 检测间隔(interval):设置过长会导致故障发现慢,设置过短会增加不必要的检测流量。建议 180-300 秒。
  2. 超时判定:TCP 连接超时时间通常默认 5 秒。如果节点被封,每次检测都要等 5 秒超时才能判定失败。

服务端侧故障转移

客户端故障转移有一个根本局限:它依赖客户端的配置和能力。如果你是服务提供者,不应将所有容错能力交给客户端,而应在服务端实现故障转移。

DNS 故障转移

将节点域名的 DNS 解析与健康检查结合。当检测到某个节点不可用时,自动将其从 DNS 记录中移除。

实现方式:使用 Cloudflare、AWS Route 53 等 DNS 服务商的 API,配合自定义的健康检查脚本:

  1. 健康检查脚本定期检测所有节点
  2. 发现节点不可用时,通过 DNS 服务商 API 将该节点的 A 记录删除或将域名指向备用节点
  3. 节点恢复后重新添加记录

局限:DNS 解析有缓存(TTL),即使你立即修改了记录,客户端缓存的旧 IP 在 TTL 过期前仍然会尝试连接已故障的节点。建议将 TTL 设置为较短的值(如 60 秒),但这会增加 DNS 查询量。

负载均衡器健康检查

在节点前部署负载均衡器(如 Nginx、HAProxy),由负载均衡器执行健康检查并自动将流量从故障节点转移到健康节点。

1
2
3
4
5
6
# Nginx upstream 健康检查配置
upstream proxy_backends {
server node1.example.com:443 max_fails=3 fail_timeout=30s;
server node2.example.com:443 max_fails=3 fail_timeout=30s;
server node3.example.com:443 backup;
}

这种方式对用户完全透明——用户始终连接负载均衡器的地址,后端节点的切换由负载均衡器自动完成。

自动 IP 更换

对于 IP 被封的场景,最彻底的服务端故障转移是自动更换 IP。流程为:

  1. 健康检查检测到节点 IP 被封(从海外可达但从国内不可达)
  2. 通过云服务商 API 释放旧 IP,分配新 IP
  3. 更新 DNS 记录指向新 IP
  4. 更新面板中的节点信息
  5. 通过 Telegram 通知运营者

整个流程可以在 2-5 分钟内完成,用户感知到的中断时间极短。


监控工具选择

外部监控服务

  • UptimeRobot:免费版支持 50 个监控器,5 分钟检测间隔。适合监控节点端口可达性。但注意:UptimeRobot 的监测点在海外,它检测的是全球可达性,不等同于从中国大陆的可达性。
  • Hetrixtools:类似 UptimeRobot,提供更细粒度的监控选项。

自建监控

对于代理服务来说,从中国大陆发起的检测才是有意义的。自建监控方案:

  • 在国内服务器上部署检测脚本,定期从国内发起 TCP 连接和代理请求测试
  • 检测结果写入数据库或推送到 Telegram
  • 结合 Grafana 展示节点状态仪表板

Telegram 告警集成

Telegram Bot 是代理服务运维中最常用的告警渠道。通过 Telegram Bot API 发送告警消息,运营者可以在手机上即时收到节点状态变更通知。

1
2
3
4
5
6
7
8
9
10
11
# Telegram 告警函数
send_alert() {
local message="$1"
curl -s -X POST "https://api.telegram.org/bot${BOT_TOKEN}/sendMessage" \
-d chat_id="${CHAT_ID}" \
-d text="${message}" \
-d parse_mode="Markdown"
}

# 使用示例
send_alert "⚠ 节点 HK-01 (1.2.3.4) 已离线,正在执行自动切换..."

恢复时间目标(RTO)

不同的故障转移方案对应不同的恢复时间目标(Recovery Time Objective)。明确你的 RTO 有助于选择合适的方案。

方案 典型 RTO 适用场景
客户端 url-test/fallback 30 秒 - 5 分钟 用户端自动切换,最常用
DNS 故障转移 1 - 10 分钟 取决于 DNS TTL 设置
负载均衡器 10 - 30 秒 对用户完全透明
自动 IP 更换 2 - 5 分钟 需要云服务商 API 支持
手动恢复 30 分钟 - 数小时 无自动化,不推荐

常见问题(FAQ)

url-test 和 fallback 应该选哪个?

如果你希望始终使用最快的节点并且不介意频繁切换,选 url-test。如果你更重视稳定性(比如保持同一出口 IP),选 fallback。对于流媒体解锁等需要 IP 一致性的场景,fallback 更合适。

健康检查间隔设置多少合适?

建议 TCP 检测设置为 60-120 秒间隔,协议级检测设置为 300-600 秒间隔。间隔过短会产生大量无效流量,过长则故障发现慢。需要在及时性和资源消耗之间取得平衡。

DNS TTL 应该设多短?

对于需要快速故障转移的代理服务,建议将 DNS TTL 设为 60-120 秒。更短的 TTL(如 30 秒)虽然能更快切换,但会显著增加 DNS 查询量,部分解析器也可能忽略过短的 TTL。

自动 IP 更换是否适用于所有云服务商?

不是。需要云服务商提供弹性 IP 或 IP 更换的 API。Vultr、DigitalOcean、AWS 等主流云服务商支持这一功能。部分小型服务商可能不提供 API,或者 IP 更换有频率限制。

负载均衡器本身是否会成为单点故障?

是的。如果只部署一台负载均衡器,它的故障会导致所有后端节点不可达。解决方案是部署多台负载均衡器并配合 DNS 轮询,或使用云服务商提供的托管负载均衡服务。

故障转移会影响用户的连接体验吗?

会有短暂中断。TCP 连接切换时,正在传输的连接会断开,需要重新建立。对于 HTTP 浏览来说影响很小(页面刷新即可),但对于实时通话、游戏等长连接场景,用户会感知到中断。


外部参考