搜索 K
Appearance
你买了号称 2.5Gbps 的 IEPL 专线,Speedtest 单线程却只跑到 180Mbps,多线程一开瞬间飙到 900Mbps——问题大概率不在专线,而在你到专线入口这一段,以及 TCP 协议本身的物理天花板。
先把结论摆上来,后面的章节全是用来证明它们是怎么来的。
tcp_rmem 上限通常是 6MB,Windows 自动调优实测也就在 16MB 附近收敛。ping 延迟看起来完全正常。ping 看 RTT → iperf3 -P 1 与 -P 8 对比 → ss -ti 看 cwnd/rtt → mtr 定位丢包点。四步走完,瓶颈在本地、在中转、还是在落地,基本一目了然。TCP 是带确认的滑动窗口协议。在任何时刻,发送方能"在途"的未确认数据量,不能超过接收方通告的窗口大小。于是:
单条 TCP 连接的理论吞吐 = 接收窗口大小 ÷ 往返时延(RTT)
把 1Gbps 换算成 125MB/s,你要在 T 秒的 RTT 内塞满 125MB 数据,窗口就得是 125MB × RTT。这就是带宽时延积(BDP,Bandwidth-Delay Product)。
看清楚了吗?跨境链路的 RTT 一旦上到 150ms 以上,"跑满千兆"这件事就已经不是带宽问题,而是一个内存分配问题。
TCP 报文头里的窗口字段只有 16 位,最大 65535 字节(约 64KB)。在 RFC 1323 引入窗口缩放因子(Window Scale)前,单连接在 200ms RTT 下的极限吞吐是 65535 ÷ 0.2 ≈ 327KB/s ≈ 2.6Mbps。这个数字在 1990 年代够用,放到今天是灾难。
窗口缩放因子最大为 14,理论窗口上限约 1GB,但能不能开到那么大,取决于内核参数和内存策略,而不是取决于你的专线带宽。这就是为什么很多人报"专线跑不满"时,我们第一步问的不是线路,而是"你的 tcp_rmem 是多少"。
即便窗口足够,拥塞控制算法(CC)决定了发送端多快把窗口"涨"上去。
一句话:在跨境场景里,CUBIC + 默认窗口 = 主动放弃一半带宽。
IEPL(International Ethernet Private Line)本质是运营商在两端之间提供的一条二层以太网透明通道,数据不经过公网 BGP 路由,中途不打环回、不经过国际出口的拥塞点。它天然带来三个特性:
但请注意:IEPL 内网段只有"你所在城市的接入点 → 落地机房"这一段。你从家宽到接入点这一段,依然是公网、依然是家用宽带、依然受运营商 QoS 管辖。绝大多数"专线跑不满"的锅,都出在这段最后几百米到几十公里上。
当你通过 Clash / sing-box / Xray 这类客户端走专线时,数据路径变成:
应用 → TUN/system 栈 → 代理内核加密 → 本地出口 → 公网 → IEPL 接入点 → IEPL 内网 → 落地 → 目标站
这���有三个隐形损耗点:
| 平均 RTT | 6MB 窗口上限 | 16MB 窗口上限 | 32MB 窗口上限 | 跑满 1Gbps 所需窗口 |
|---|---|---|---|---|
| 20 ms | 2.4 Gbps | 6.4 Gbps | 12.8 Gbps | 2.5 MB |
| 50 ms | 960 Mbps | 2.56 Gbps | 5.12 Gbps | 6.25 MB |
| 100 ms | 480 Mbps | 1.28 Gbps | 2.56 Gbps | 12.5 MB |
| 150 ms | 320 Mbps | 853 Mbps | 1.7 Gbps | 18.75 MB |
| 200 ms | 240 Mbps | 640 Mbps | 1.28 Gbps | 25 MB |
| 250 ms | 192 Mbps | 512 Mbps | 1.02 Gbps | 31.25 MB |
读表方法:假设你用的是某香港 IEPL、实测 RTT 45ms、系统接收窗口上限 6MB,那么你的单线程理论天花板就是 960Mbps——这已经接近千兆,说明 Windows 默认参数下"跑不满"其实可以接受。换成美国 IPLC、RTT 180ms、窗口 6MB,单线程天花板就只剩 267Mbps,此时抱怨专线不行,纯属冤枉线路。
| # | 影响因素 | 典型影响量级 | 可否本地缓解 | 快速判定方法 |
|---|---|---|---|---|
| 1 | 端到端 RTT | 决定 BDP 分母,影响可达 5 倍以上 | 换落地地区 / 换接入城市 | ping / mtr |
| 2 | TCP 接收窗口上限 | 200ms 下从 240Mbps 到 1Gbps 差距 | ✅ 调 tcp_rmem/tcp_wmem | ss -ti 看 rcv_space |
| 3 | 拥塞控制算法 | CUBIC→BBRv3 常见提升 1.5–3 倍 | ✅ 切换内核算法 | sysctl net.ipv4.tcp_congestion_control |
| 4 | 单连接 / 多连接并发 | 多线程通常提升 3–8 倍 | ✅ 客户端开并发 | iperf3 -P 1 vs -P 8 |
| 5 | MTU / MSS 分片 | PPPoE + 隧道常见降至 1350–1400 | ✅ 修正 MSS Clamping | ping -M do -s 1472 |
| 6 | 运营商 QoS / BRAS 限速 | 可砍掉 30%–80% 带宽 | ⚠️ 只能规避,无法改 | 分时段重复测速对比 |
| 7 | 光猫 / 路由 NAT 转发 | 低端设备 400–700Mbps 封顶 | ✅ 桥接 + x86 软路由 | 直连光猫对比测试 |
| 8 | 代理内核栈与 mux | gVisor 栈约为 system 栈 40%–60% | ✅ 换栈 / 关 mux | 换客户端内核对比 |
| 9 | 落地机房出口带宽 | 超售节点晚高峰可掉 50%+ | ❌ 只能换节点 | 分时段多节点对比 |
| 10 | 测速节点自身能力 | 部分公共节点单线程上限 300Mbps | ✅ 换节点 / 换工具 | 多节点交叉验证 |
我见过太多人一上来就换机场、换协议、换线路,最后发现是自己的光猫在 PPPoE 转发时单核跑不动。按顺序走完下面五步,能省下你至少三个月试错成本。
先测本地直连(不走代理)的裸带宽,作为参照系:
# Speedtest CLI,多线程
speedtest -s 36646
# 单线程(关键!)
speedtest -s 36646 --threads 1
# 同时记录本地上行
speedtest -s 36646 --upload判定:如果本地直连单线程也只有 300Mbps,那你的问题跟专线一点关系都没有,是本地接入侧的问题,直接跳到步骤 5。
# 面向 IEPL 接入点的持续探测,100 包 TCP SYN
mtr -rwzc 100 -T -P 443 你的接入点IP
# 大包探测,验证 MTU 与分片
ping -M do -s 1472 -c 20 你的接入点IP
# 常规延迟抖动观测(Windows / macOS 通用)
tcping -t -n 50 你的接入点IP 443读法:重点看第 2 跳之后的 Loss% 与 StDev。如果丢包集中在某中间跳但后续跳恢复为 0,那通常是该跳的 ICMP 限速策略,不是真实丢包。如果丢包一路延续到终点,那就是真丢。
这一步是整个排查的分水岭。不要用 Speedtest 的网页版,它的默认并发数不透明。用 iperf3 直连 IEPL 服务商提供的测试节点(如果没有,用落地机上的 iperf3 -s):
# 单线程
iperf3 -c 落地机IP -p 5201 -t 30 -P 1
# 8 线程
iperf3 -c 落地机IP -p 5201 -t 30 -P 8
# 反向测试(下行)
iperf3 -c 落地机IP -p 5201 -t 30 -P 8 -R结果解读表:
| 单线程结果 | 多线程结果 | 结论 | 下一步 |
|---|---|---|---|
| 低 | 高 | 典型 BDP / 窗口瓶颈 | 做第五章 TCP 调优 |
| 低 | 低 | 链路容量或本地接入受限 | 跳步骤 5 |
| 高 | 相同或略低 | 链路本身正常,问题在代理客户端 | 检查 mux / 内核栈 |
| 波动剧烈 | 波动剧烈 | 运营商 QoS 或晚高峰整形 | 分时段重复测试 |
这是最容易被忽略、但信息量最大的一步:
# 查看活跃连接的拥塞窗口、RTT、重传
ss -ti | grep -A 1 "iperf3"
# 关键字段:
# cwnd:10 <- 拥塞窗口(单位 MSS)
# rtt:180.5/1.2 <- 平滑 RTT / 抖动
# retrans:0/12 <- 重传计数
# rcv_space <- 接收窗口实际值
# 内核 TCP 统计
nstat -az | grep -E