Surge 的自动类型策略组的测试策略比较复杂,该文档详细描述了各种情况下的设计行为与原因。
自动类型策略组包含:url-test、fallback 和 load-balance。
初次使用时
当第一次使用某个策略组时,Surge 默认行为是使用策略组中的第一个子策略,并与此同时触发策略组的测试,在测试完成之前,若该策略组被再次使用,依然会使用第一个子策略。
若策略组配置了 evaluate-before-use=true 参数,那么当策略组测试未完成时,将会堵塞住对应请求,等待测试完毕后使用测试结果再继续。
定期重测试
自动类型策略组支持配置 interval 参数,当上一次的测试的时间与当前时间超过此间隔后,则上一次的测试结果被标记为过期。
当该策略组再次被使用时,将先使用过期结果的子策略,同时触发一次新的测试。也就是说,如果该策略组未被使用,即使结果已过期也不会立刻触发重测试。
tolerance 参数
url-test 策略组有一个特别的参数:tolerance,默认为 100 ms。只有当某子策略的测试成绩比原先的选定子策略的成绩,差值高于 tolerance 的设定值时,才变更选定策略。
举例说明,策略组包含 A 与 B 两子策略,目前选定为 A,tolerance 为 100 ms。
当新的测试结果为 A: 50ms B: 10 ms 时,依然继续使用 A。
当新的测试结果为 A: 150ms B: 10 ms 时,切换至 B。
该特性用于避免选定策略在若干个结果相差不大的策略间反复跳动。导致出口 IP 不断变化引发异常。
异常情况下的重测试
当某策略组的选定代理策略出现故障时,理应立刻进行重测试并切换至其他策略,但是由于实际情况通常并不简单,Surge 为此做了较为复杂的逻辑。
通过代理访问一个目标网站时出现了问题,遇到的错误可被分为三大类
- 设备本身的网络问题,如信号差、网络中断等。
- 代理服务器出现故障或网络问题。
- 目标网站服务器出现故障或网络问题。
很明显,我们只希望在遇到错误 2 时才触发策略组的重测试。问题在于,Surge 无法准确地确认问题的来源。为此 Surge 将错误重新进行分类:
A 类:一定是错误 1。(如:No route to host 错误)
B 类:可能是错误 1 或 2。(如:TCP hankshake timeout 错误)
C 类:一定是错误 2。(如:Connection refused 错误)
D 类:可能是错误 2 或 3。(如:Socket closed by remote 错误)
E 类:一定是错误 3。
目前版本 Surge 的策略为:当选定子策略遇到错误 C 时,将立刻触发重测试,当在 60 秒内遇到 3 次 B 或 D 类错误,也会触发重测试。A 与 E 类不触发重测试。
对于不同的代理协议,错误的划分方法会有不同,比如 shadowsocks、Trojan、VMess 协议都不会在目标网站出错时返回状态码,所以填错了代理服务器密钥和目标服务器不通这两种截然不同的错误,从 Surge 看来并没有任何区别,都只是代理服务器主动断开了 TCP 连接。(Snell 协议有完整的错误码和错误信息回报)