我上个月我因为流量不够用换了联通刚出的大套餐,附赠了 2000M 家庭宽带,上行标称 200M。按理说,上海 NAS 往老家 NAS 同步文件,速度再差也不该只有几十 KB/s。
实际看到的速度很难看:有的文件 46 KB/s,有的 55 KB/s,偶尔到 155 KB/s。换算下来,已经到了基本不可用的程度。
我的上海和老家的 Nas 是用 TailScale 组的虚拟局域网,最开始我也按常规路径怀疑了一圈:Tailscale 是不是走了 DERP 中继?NAS 本机是不是扛不住?路由器是不是有问题?后来把这些假设一个个拆掉以后,证据指向了一个运营商出口:上海出口到老家方向,被卡在了 5-6 Mbps 附近。关键猥琐的是,只定向限速了我到老家的这条通道,从上海测到任何其他网站,都是还是 200M 上行。
后来找到小区的运营商小哥反馈,检查后跟我说没有限速。后来我把证据贴出来,对方才答应帮忙深度排查下,最终恢复的正常了网速。两天后复测,同一方向恢复到了 200-300 Mbps 量级。
这篇文章记录的是这条证据链。Agent 在这里帮上的忙,是把一个模糊的“网速慢”,拆成运营商也很难忽略的几个事实:单方向、固定阈值、多设备复现、绕开 Tailscale 仍然存在,调整后恢复。
先说结论
这次排障最后收敛到几个判断:
- 上海 NAS 到老家 NAS 方向,存在一个约 5-6 Mbps 的单向瓶颈。
- 绕开 Tailscale 后,公网直连测速仍然复现 5-6 Mbps 附近的大量丢包。
- 上海同一出口下换一台 Mac mini 作为发送端,也能复现这个阈值,基本排除了 NAS 单机问题。
- 老家到上海的反向链路明显好得多,50 Mbps 完整到达,80 Mbps 也能到约 68 Mbps。
我不能证明运营商内部具体是哪台设备、哪条规则在丢包。家用宽带用户也看不到这些配置。但从现象、方向性、固定阈值和调整后的恢复结果看,把问题定位到上海出口方向的 policy / QoS / policer,是这次排查里最符合证据的解释。
排查思路:先看 Tailscale,再测公网直连
看到异地同步慢,Tailscale 很容易成为第一嫌疑。但我不想停在“Tailscale 慢”这个粗结论上。Agent 帮我梳理出来的思路,是把链路拆成两层来测:先看 Tailscale 到底是直连还是中继,再绕开 Tailscale 做公网直连测速。
这两层测试回答的是两个更小的问题:是不是 DERP 中继拖慢?离开 Tailscale 后,公网路径本身是不是仍然卡在同一个阈值?只有这两个问题都收敛到同一个方向,后面再去找运营商谈 policy 才有底气。
第一步:确认 Tailscale 不是 DERP
两台 NAS 之间通过 Tailscale 做异地同步:
- 上海侧 NAS:同步源端。
- 老家侧 NAS:同步目标端。
- 控制面使用 Headscale / Tailscale,数据面正常情况下应走两端 direct。
查看 Tailscale 状态时,上海侧到老家 NAS 的连接状态是 direct,端点是对端公网地址和 UDP 端口。也就是说,数据面没有默认走 DERP 中继。
为了确认 DERP 不是当前瓶颈,我还临时阻断直连 UDP,让链路强制走 DERP relay。结果更差。
| 模式 | 方向 | 结果 |
|---|---|---|
| Tailscale direct | 上海 NAS -> 老家 NAS | TCP 单线程约 5 Mbps |
| 强制 DERP relay | 上海 NAS -> 老家 NAS | TCP 约 188 Kbps |
这说明一个问题:继续怪 DERP 解释不了现象。但 direct 也不是裸公网 TCP。Tailscale direct 仍然是加密 UDP 隧道,所以还要继续把 Tailscale 整层拿掉。
第二步:公网直连测速也复现
下一步是绕开 Tailscale,用公网地址直接测速。具体测试时我同时用了 IPv6 iperf3 和 IPv4 UDP 抓包计数,但它们在文章里的作用是一样的:确认问题离开 Tailscale 以后还在不在。
先用公网 IPv6 直接跑 iperf3,结果很稳定地卡在 5 Mbps 附近:
| 测试 | 方向 | 结果 | 现象 |
|---|---|---|---|
| TCP 单流 | 上海 -> 老家 | 接收端约 1-6 Mbps | 大量 Retr,窗口被打小 |
| TCP 4 并发 | 上海 -> 老家 | 约 2-3 Mbps | 多流没有绕过瓶颈 |
| UDP 1 Mbps | 上海 -> 老家 | 接收约 970 Kbps | 约 3% 丢包 |
| UDP 3 Mbps | 上海 -> 老家 | 接收约 2.76 Mbps | 约 7.9% 丢包 |
| UDP 5 Mbps | 上海 -> 老家 | 接收约 4.56 Mbps | 约 8.6% 丢包 |
| UDP 8 Mbps | 上海 -> 老家 | 接收约 4.84 Mbps | 约 39% 丢包 |
| UDP 10 Mbps | 上海 -> 老家 | 接收约 4.86 Mbps | 约 51% 丢包 |
| UDP 20 Mbps | 上海 -> 老家 | 接收约 5.10 Mbps | 约 74% 丢包 |
IPv4 这边我没有直接给 iperf3 做端口转发。为了尽量少改路由器配置,我用了一个更粗暴也更干净的方法:
- 上海侧向老家公网 IPv4 固定速率发送 UDP 包。
- 老家路由器在 WAN 口用
tcpdump数包。 - 不开放端口,不写防火墙规则,只看包有没有到公网入口。
结果如下:
| 发送速率 | 上海侧发送包数 | 老家路由器 WAN 捕获包数 | 结论 |
|---|---|---|---|
| 1 Mbps | 625 | 625 | 完整到达 |
| 3 Mbps | 1875 | 1875 | 完整到达 |
| 5 Mbps | 3125 | 3125 | 完整到达 |
| 10 Mbps | 6250 | 3818 | 大量丢包 |
| 20 Mbps | 12500 | 3839 | 大量丢包 |
这两组测试放在一起看,信息量就很大:公网直连已经离开了 Tailscale,又换了不同的验证方法,但最后都卡在 5-6 Mbps 附近。到这里,Tailscale 不再是主嫌疑,问题开始像公网路径上的策略。
ping 很漂亮,但吞吐照样崩
两端公网 IPv4 / IPv6 ping 都很好看,延迟大约 12-15 ms,0% 丢包。tracepath 看到 PMTU 约 1480,也符合 PPPoE 场景。大包 ping 没有表现出 MTU 黑洞。
这就是网络排障里很烦人的地方:ping 正常只说明小包 ICMP 往返没问题,不代表持续吞吐正常。
这次真正有信息量的是 UDP 阶梯测试:
- 1 Mbps、3 Mbps 基本能过。
- 5 Mbps 接近阈值,开始出现损耗。
- 8 Mbps、10 Mbps、20 Mbps 继续往上打,接收端仍然停在 5-6 Mbps,多出来的包大量消失。
这类形态很像 policer:低速时放行,超过某个速率以后开始丢超出的包。TCP 看到丢包以后会重传、退避、缩小窗口,最后表现出来就是吞吐很低、Retr 很多、Cwnd 很小。
我当时给运营商沟通时,没有只说“网速慢”。我强调的是这几件事:
- 这是上海到老家的单方向异常。
- 同一上海出口换设备也复现。
- 反向老家到上海明显正常。
- 超过 5-6 Mbps 后接收端不再增长,表现像固定阈值。
这种描述比“我办了 200M 上行但跑不满”更有用。套餐跑不满有很多解释,固定阈值、单方向、多设备复现就很难用普通拥塞糊弄过去。
运营商一开始说没有限速,后改口解除
我先按普通故障方式找运营商人员反馈,对方查了后台,说没有限速。
这个反馈并不意外。后台没有看到一个叫“给这个用户限 5Mbps”的配置,不代表路径上没有策略命中。家庭宽带接入、出口、跨省路径、流量类型识别、中间设备策略,任何一个地方都可能让用户看到类似效果。
我没有继续争“你们肯定限速”。我把前面的证据链整理给对方:这不是所有上行都差,上海侧到 Cloudflare IPv6 上传能到 35-45 Mbps,Mac mini 的 networkQuality 也曾测到接近 200 Mbps 上行,NAS 到局域网内机器也接近千兆。真正异常的是上海到老家公网这个方向。
后来对方答应帮忙调整。中间等了差不多两天,再测,网速恢复了
调整前后对比
下面这张图把同一方向调整前后的测速结果抽象成一张对比图:调整前长期卡在 5 Mbps 附近,调整后恢复到 200 Mbps 以上。
调整前,连接起来以后很快掉到 Kbps 级别,15 秒 sender 侧只有 625 KBytes,Retr 139,Cwnd 一直在 1.2-4.8 KBytes 之间抖。
调整后,同一方向单秒吞吐能看到 147 Mbps、168 Mbps、210 Mbps、231 Mbps、252 Mbps、283 Mbps。虽然我手动 Ctrl-C 中断了测试,尾部 receiver 汇总不适合作为结论,但 per-second sender 已经能说明链路状态完全变了:这不再是一条被压在 5 Mbps 附近的路径。
这个恢复结果反过来也解释了前面的排障为什么值得做。它没有直接告诉我运营商内部改了哪条规则,但证明“沿着出口 policy / QoS / policer 去推动调整”这条方向是对的。
Agent 在这里真正有用的地方
这次我对 Agent 的感受很明确:它最有价值的地方,是帮我守住排障顺序。iperf3 参数和 Python UDP 脚本都不难,难的是别在第一个看起来合理的解释上停住。
真正有用的是它能一直逼我把问题拆小:
- Tailscale direct 慢,还要继续测裸公网。
- 裸 IPv6 慢,还要用 IPv4 旁路确认。
- 单台 NAS 慢,还要换同出口设备。
- 正向慢,还要测反向。
- ping 正常,还要看持续吞吐和丢包阈值。
网络问题最容易变成互相甩锅。用户说运营商慢,运营商说没有限速;你怀疑 Tailscale,Tailscale 状态又显示 direct;你怀疑 NAS 本机,同出口另一台机器又复现。如果没有证据链,讨论会一直停留在“感觉不对”。有了证据链以后,沟通对象就很明确:请看这个方向、这个阈值、这些对照测试。