杀死开关测试:要量的是空窗期,不只是重连速度
重连足够快只能证明客户端响应快。把空窗期间离开机器的流量和所用触发方式一并记下,否则这项测试只量了一半。
一秒内完成的重连只能说明客户端很快。它不能说明隧道断开期间是否有流量溜了出去。需要一分钟才能重连,说明客户端很慢,但同样没说明空窗期内是否放行了直连流量。这是两项测量,只报告第一项的杀死开关测试,其实没有测到开关。
两种观察,两个独立结论
可用性问题很简单:隧道何时恢复可用,受保护的应用是否需要新建连接才能连上。强制性问题则不同:从保护失效到恢复之间,哪些数据包离开了这台机器。
用两份记录分别回答。一行写明空窗持续了多少秒。另一行写明空窗期内是否有未经保护的请求成功。把两者合并成一个通过或不通过,就会掩盖最要紧的情况:重连很快,但发生了泄漏。
搭一个可以计时的探针
选用一个无害、便宜、且不依赖隧道自身控制通道的请求。下面的循环每秒打印一次时间戳、HTTP 状态码和耗时,遇到问题会直接报错而不是卡住:
while true; do
printf '%s ' "$(date +%H:%M:%S)"
curl -sS -o /dev/null -w '%{http_code} %{time_total}\n' --max-time 2 https://example.com || echo "curl-exit-$?"
sleep 1
done
重点看 curl 的退出码,而不只是状态码。28 表示请求超时,也就是被阻断时的表现。6 表示域名解析失败,这是另一类发现,往往更值得注意。空窗期内出现 200 且耗时很短,说明流量被放了出去。
把输出写入文件并保存。终端里的滚动记录不算证据,真正有价值的内容通常是中间的那三行。
要制造真实故障,而不是体面地断开
从客户端菜单里断开,走的是配合路径,客户端还有时间装好阻断规则。直接杀掉进程,或者拔掉底层链路,测到的才是真实故障会走的那条路。
每种触发方式都会走不同的代码路径。服务端故障、本地链路中断和客户端崩溃留下的状态各不相同,其中一种很可能就是你最终会遇到的情况。至少在两种触发方式下各跑一次探针,并按触发方式标注结果。
从日志里读出放行流量是什么样子
空窗期内出现 200,或者连接失败得特别快,无论朝哪个方向都是泄漏。整个空窗期都在超时,才是阻断策略应有的样子。连接失败但域名解析成功,说明解析器仍然可达,这是另一种性质的泄漏。
已有套接字需要留意。程序可以继续使用断开之前就建立的连接,所以看起来还在传输的流量,未必能证明新路径被放行。套接字列表可以看出一条连接是否早于这次事件:
ss -tunp | grep -E 'ESTAB|SYN-SENT' ip route get 198.51.100.7 resolvectl status | sed -n '1,20p'
把套接字的起始时间和断开的时刻对比。比故障更早建立的连接,说明的是套接字被复用,而不是泄漏;把它当作故障上报,会让下一个人去找一个根本不存在的缺陷。
用能在更新之后仍然成立的格式记录结果
记下触发方式、空窗秒数、是否有未被阻断的请求成功、域名解析是否成功,以及客户端和操作系统版本。这五项事实可以跨版本比较,而一段散文做不到。
客户端更新或配置变更之后,把同样的测试再跑一遍,因为阻断行为属于实现细节,会发生变化。记录的目的是在变化演变成事故之前发现它,而不是一次性给客户端盖章。