为什么同一条隧道上的两次 VPN 测速结果不一致
新的出口会换掉测试服务器,慢启动会改变成绩。固定目标、对齐流数,并把处理器开销与链路容量分开。
两次运行、同一条隧道,数字却差了三倍。两次之间隧道没有变化。变化的是测量本身:一个按你表面位置挑选服务器的测速网站、决定由一条慢启动还是六条慢启动填满管道的流数,以及短到路径还没被正常使用就结束的时长。测速并没有错,但它回答的问题比人们问它的那个更窄。
新的出口地址会改变测试目标
多数测速网站会自动选择测量服务器,而这个选择部分取决于你的连接看起来来自哪里。打开隧道后,你的表面国家变了,选中的服务器也跟着变,于是比较横跨了通往两台不同主机的两条不同路径。
这个结果根本不是 VPN 的测量。它测量的是你通往一台你并未选择的服务器的路径,而两次运行之间的差异,可能主要由那台服务器的对等互联决定,而不是隧道做了什么。
在改动其他任何东西之前,先固定目标。任何可信的工具都允许你明确指定服务器;当它不允许时,结果页面通常会写明所用的服务器,这足以让你发现两次运行并不可比。在相信网站的选择之前,先确认它看到了什么:
curl -sS https://ipinfo.io/json | grep -E '"ip"|"org"|"country"'
如果两次运行之间的国家变了,那么测试此后选择的一切也都变了。把观察到的出口写在每个结果旁边,困惑大部分就会消失。
慢启动在大多数短测试结束之后才结束
TCP 连接并不是以链路速率开始的。它从一个很小的拥塞窗口开始,大约每经过一个往返就翻倍,只有在若干个往返之后才达到路径容量。在高延迟路径上做十秒测试,它可能有相当一部分时间都花在那段爬升里。
这就是为什么延迟更大的隧道在短测试里成绩低于它应得的水平,也是为什么更长的运行常常在没有任何配置改动的情况下报出更高的数字。RFC 6349 吞吐量框架明确处理了这一点,所以严肃的测量都要跑得足够久,以达到稳定状态。在卫星路径上跑五秒,测到的是加速器,而不是路。
不要只信一个数字,去看连接的各个阶段。Curl 会分别报告每个阶段,所以你能看出时间花在握手、爬升还是传输上:
curl -sS -o /dev/null -w 'dns=%{time_namelookup} tcp=%{time_connect} tls=%{time_appconnect} total=%{time_total} bytes/s=%{speed_download}\n' \
https://mirror.example.net/testfile.bin
朝同一目标连续跑两次。如果第二次快得多,那你测到的是爬升而不是路径,任何只用第一次的比较都值得怀疑。
一条流和六条流测的是不同的东西
单条 TCP 流受限于它能在途保持的窗口,大约是往返时间乘以速率。在长路径上这个乘积超过一条流会用的量,所以单次下载会低估实际存在的容量。六条并行流填补了这个缺口,给出更大的数字。
iperf3 -c speed.example.net -t 20
iperf3 -c speed.example.net -t 20 -P 6
mtr -rwc 50 speed.example.net
两个数字都是真的。单流数字说明一次下载能到什么程度,这通常是浏览器标签得到的。并行数字说明路径总体上能承载多少,这是种子下载或多段下载能利用的。把其中一个当作另一个来引用,正是一条健康隧道被无端替换的原因。
拿并行结果去和单流结果比较,是人们得出 VPN 让速度减半这一结论最常见的做法。先把方法对齐,再比较。第三条命令里的轨迹补上了缺失的上下文:抖动大的路径在两种模式下都会给出不一致的结果,而无论多少条流都修不好这一点。
加密消耗处理器时间,封装消耗字节
无论链路多快,每个数据包上都有两套机制在运作。加密按字节消耗处理器,封装则加上链路仍须承载的头部字节。两者都表现为天花板,而症状不同。
处理器天花板表现为高原:无论再加多少条流,吞吐都不再上升,而机器的处理器忙、链路却不忙。在小路由器或手机上,这往往就是真正的上限,这也是为什么一条快线路仍然只能给出平庸的隧道。
字节成本更小,但是恒定的。额外的头部意味着每个包承载的有效载荷更少;在最大传输单元固定的路径上,它们还可能触发分片或黑洞,表现形式是大传输时的卡死,而不是平均值变慢。
| Observation | Likely mechanism | What to measure |
|---|---|---|
| Throughput flat as streams increase | CPU per packet on one core | Per-core utilisation during the test |
| Fast small transfers, stalled large ones | MTU and fragmentation | Payload size at which it breaks |
| Good average, unusable calls | Queueing delay behind a full buffer | Latency under load |
这三者常被混淆,因为用户把它们一律描述为 VPN 很慢。只有第一个会对更强的机器有反应,只有第二个会对更小的 MTU 有反应,只有第三个会对队列管理有反应。
把方法写进记录
值得保留的结果会写明设备、接入网络、出口、测量服务器、方向、流数和时长。没有这些,两个数字无法比较,而只写一个数字的工单其实只是一种情绪。
坏的那几次也要留着。某个出口每次都造成卡死的一串记录,比一个平均值有用得多,而卡死恰恰是平均值会掩盖的东西。
然后去测你真正在意的东西。如果目标是大文件下载,就去下载那个文件。如果目标是通话,就测负载下的延迟而不是空闲吞吐,因为一条隧道可以在测速里表现良好,却仍然让每场会议都听不清。