NOTEDevOps

自动代理组失效时,用本地故障守护恢复连接

本文结论

用真实请求探测、受限本地控制和明确的状态所有权,为健康信息滞后的自动代理组补上可恢复的故障切换。

一个自动代理组看起来仍有多个延迟正常的节点,当前策略组却会突然显示失败并停止转发流量。直接选择界面中延迟最低的节点只能偶尔恢复,因为部分正延迟来自旧记录,代理核心维护的实时健康状态又是另一套数据。

最终处理方式是在现有客户端外增加一个很小的本地故障守护。它不改订阅,不替换代理核心,也不调整系统代理。真实请求正常时,守护保持观察;连续失败后才临时接管;自动组恢复稳定后,再把控制权交还给原有策略。

先区分展示记录与运行时健康状态

排查首先确认,界面同时呈现了两类含义不同的证据:

  • 桌面客户端保存的单节点延迟记录;
  • 代理核心维护的实时探测与选中状态。

第一类数据中的正数只能说明某次测量曾经成功,不能证明该节点此刻仍能完成代理请求。现场有些条目保留了旧延迟,最近一次检查却已经超时或返回异常响应。因此,策略组已经失效时,界面仍可能展示看似可用的节点。

生成的运行配置还省略了 URLTest 的显式参数。sing-box 的 URLTest 文档说明了这种情况下的默认值:使用 Google 的连通性检查地址,每三分钟测试一次,允许 50 毫秒容差,并在空闲 30 分钟后暂停测试。这些默认值适合一般自动选择,但不会保证界面中的绝对最低延迟,也无法覆盖所有短时故障的快速恢复需求。

于是,故障判断改为观察本地代理能否完成真实请求。界面的缓存数字只用于辅助诊断。

在自动组外补一层有限状态机

守护程序使用五个状态:

自动 -> 疑似故障 -> 临时节点 -> 恢复观察 -> 自动

处于“自动”状态时,程序通过实际本地代理请求两个轻量连通性地址。任一地址返回预期成功响应,本轮就视为健康。一次失败只进入“疑似故障”;下一轮恢复即可清除。只有连续两轮都失败,程序才允许启动恢复。

恢复过程保持顺序和边界清晰:

  1. 从正在运行的客户端和生成配置中发现实际运行参数;
  2. 要求控制接口只能监听回环地址;
  3. 让代理核心重新测量候选节点;
  4. 按本轮测量结果依次尝试可用候选;
  5. 每次切换后立即验证真实代理请求;
  6. 所有候选都失败时保持当前状态,并退避后重试。

sing-box 文档说明,Selector 当前通过 Clash API 控制;Clash API 配置定义了 REST 控制地址和可选认证。守护复用了已有的本地控制面,并拒绝访问非回环地址。它没有编辑客户端在重启或刷新订阅时可能重写的生成配置。

记录当前选择由谁负责

故障恢复程序如果持续覆盖人工选择,也会制造新的抖动。为此,状态文件会记录临时节点是否由守护程序选中。

  • 守护选中的临时节点,允许在后续验证后恢复自动组;
  • 用户手动选择节点后,守护停止改写 Selector;
  • 用户重新选择自动组,表示把状态所有权交还给正常监控。

从临时节点切回自动组之前还需要一段稳定观察期。一次成功不会立即触发回切,自动组必须连续通过检查。这个门槛可以减少临时恢复与再次失败之间的来回切换。

让故障处理程序保持最小权限

实现通过运行时发现取得安装位置和监听信息,没有硬编码本机目录或具体端口。它检查所有控制地址是否为本地回环,使用命名互斥锁保证单实例,并限制状态文件和诊断日志的大小。

监控程序由当前用户的登录计划任务启动,并使用有限权限。微软的 计划任务主体文档区分了 LimitedHighest 两种运行级别。这个程序只需读取当前用户的本地进程与文件,提升权限会扩大故障影响范围,对恢复没有帮助。

代理客户端未启动、正在重启或控制接口暂时不可用时,守护只会等待。它不会因此修改操作系统代理、订阅存储或客户端数据库。

既验证状态转换,也验证真实链路

最终验收覆盖了相互独立的几层证据:

  • 16 项确定性测试覆盖配置发现、URL 编码、候选排序、连续失败门槛、空结果、人工选择保护和自动组恢复;
  • DryRun 在不切换节点的情况下发现了多条当前可达候选;
  • 受控演练切到本轮测得的可用节点,通过代理取得两个连通性检查的预期响应,再恢复自动组;
  • 重启桌面客户端后,守护能够重新发现新的客户端与核心进程;
  • 系统代理、订阅、运行数据库和生成配置均未变化。

这些检查同时覆盖了状态机、控制边界和用户实际依赖的流量路径,结论不只来自“进程仍在运行”。

适用边界与可复用经验

当可用候选仍然存在且本地控制接口正常时,这套守护可以缩短恢复时间。它无法修复订阅失效、供应商整体故障、代理下层网络中断或被禁用的控制接口。失败次数和超时时间也需要根据业务能够接受的切换延迟与连接扰动调整。

这次处理沉淀出六条可复用原则:

  1. 分开展示缓存与运行时健康数据;
  2. 连续失败后再接管,避免单次抖动触发切换;
  3. 每次恢复动作后验证真实请求路径;
  4. 明确记录当前状态由自动化还是人工负责;
  5. 持续恢复后才释放临时控制;
  6. 控制通道保持本地、有限且最小权限。

原有自动组继续负责日常选择,本地守护只补充缺失的故障语义。这样既保留客户端原生行为,也让异常恢复具备可验证的边界。

分类DevOps
遇到类似系统问题?

先说明系统,再说明症状

如果需要生产排障、DevOps 交付或物流系统集成协作,请提供当前表现、预期结果、受影响环境、可用日志或数据样例,以及发布限制。我会从现有证据开始判断。

通过邮件开始