TCP BDP / 吞吐量计算器
算清楚带宽时延积、给定 TCP 窗口允许的吞吐量、填满链路所需的窗口大小,以及某个丢包率还能允许多少吞吐量。每个结果都会明确列出模型假设,而不是把理论上限当成实测预测。
第 1 部分 —— 带宽时延积
要让链路端到端始终忙碌,必须在途多少数据。也就是带宽 × RTT。
第 2 部分 —— 受窗口限制的吞吐量
固定的 TCP 窗口每个 RTT 只能把一个窗口的数据放到链路上,因此无论链路多快,吞吐量都会被这个上限卡住。
第 3 部分 —— 所需的 TCP 窗口
反过来算:在给定 RTT 下要达到目标吞吐量,需要多大的窗口?它是否需要窗口扩大选项?
第 4 部分 —— 受丢包限制的吞吐量(Mathis 模型)
丢包对 TCP 吞吐量的压制远比多数人想象的更狠,因为拥塞控制会把每一次丢包都当成速率减半的信号。
0.001 表示每一千个报文中丢失一个。
为什么长肥网络跑不满带宽
带宽高、时延也高的链路被称为长肥网络(long fat network)。TCP 设计时这两者都很小,而原始首部里 16 位的窗口字段正是问题根源。如果发送方每往返一次只能往链路上放一个窗口的数据,吞吐量就被“窗口 ÷ RTT”卡死 —— 链路本身的实际容量根本不参与计算。
带宽时延积(BDP):
BDP(比特) = 带宽(bps) × RTT(秒)
受窗口限制的吞吐量:
吞吐量(bps) = 窗口大小(比特) ÷ RTT(秒)
= 窗口字节数 × 8 ÷ RTT 秒数
达到目标所需的窗口:
窗口(字节) = 目标 bps × RTT 秒数 ÷ 8用一个真实例子完整推算
假设一条 10 Gbps 链路连接相距 25 ms 的两个机房,那么 RTT 就是 50 ms。
示例:在 50 ms RTT 上填满 10 Gbps 链路
第 1 步 —— 先算 BDP,它就是目标值:
10,000,000,000 bps × 0.05 s = 500,000,000 比特 = 62,500,000 字节 = 62.5 MB
第 2 步 —— 默认的 64 KB 窗口能达到多少:
65,536 字节 × 8 ÷ 0.05 s = 10,485,760 bps ≈ 10.5 Mbps
只有链路能力的 0.1%。问题不在链路,而在窗口。
第 3 步 —— 所需的窗口,以及要通告的扩大因子:
所需窗口 = 62,500,000 字节 62,500,000 ÷ 65,535 = 954,所以取扩大因子 2^10 = 1024 即可
只要启用窗口扩大、并把两端的缓冲区都调到 62.5 MB 以上,单条流就能接近链路速率。做不到这一点,再大的带宽也无济于事。
丢包的影响
拥塞控制把丢包当作拥塞的证据,并据此降低发送速率。在存在丢包的路径上,吞吐量的上限来自丢包率,而不是窗口或带宽。
吞吐量 ≈ (MSS ÷ RTT) × (C ÷ √p)
MSS = 最大报文段长度(比特)
RTT = 往返时延(秒)
p = 丢包概率
C ≈ 1.22(AIMD / Reno 式发送方)
示例:MSS 1460 字节,RTT 50 ms,丢包率 0.1%(p = 0.001)
吞吐量 ≈ (11,680 ÷ 0.05) × (1.22 ÷ √0.001)
≈ 233,600 × 38.6
≈ 9,017,000 bps ≈ 9 Mbps一条可能有 10 Gbps 容量的链路,实际只跑出 9 Mbps。这就是为什么网络工程师对长路径上的丢包如此执着,也是为什么监控图上看起来微不足道的 0.1% 丢包率对批量传输却是灾难性的。
两个重要前提。Mathis 模型描述的是稳态下的 Reno 式 AIMD 发送方;CUBIC —— 现代 Linux 与 macOS 的默认拥塞控制算法 —— 对丢包的敏感度要低得多。此外,真实丢包往往是突发的,而不是模型假设的均匀随机过程,这会让结果进一步偏离。请把输出当作数量级上的参考。
长肥网络调优清单
- 在两端都启用窗口扩大。 现代内核默认开启,但中间设备或老旧设备可能在握手中把这个选项剥离掉。
- 调高套接字缓冲区上限。 在 Linux 上, net.core.rmem_max 与 net.core.wmem_max 决定了自动调优能走多远。只有上限够高,自动调优才有意义。
- 用实测确认真实的在途窗口。 抓包或 ss -ti 能看到真实的 cwnd 与 rwnd,而不是理论值。
- 无法调整两端时改用并行流。 每条流都有各自的窗口,因此十条流在高时延路径上大约能达到单流的十倍速率。
- 先把丢包消灭掉。 如果路径本身在丢包,其它调优步骤都是白费功夫。
参考数值
| RTT | 100 Mbps | 1 Gbps | 10 Gbps | 100 Gbps |
|---|---|---|---|---|
| 1 ms(同一机柜) | 12.5 KB | 125 KB | 1.25 MB | 12.5 MB |
| 10 ms(城域) | 125 KB | 1.25 MB | 12.5 MB | 125 MB |
| 50 ms(跨地区) | 625 KB | 6.25 MB | 62.5 MB | 625 MB |
| 100 ms(跨大西洋) | 1.25 MB | 12.5 MB | 125 MB | 1.25 GB |
| 200 ms(洲际) | 2.5 MB | 25 MB | 250 MB | 2.5 GB |
把这张表理解为“要让链路跑满,必须在途多少数据”。1 Gbps 那一列中任何超过 65,535 字节的数值都需要 TCP 窗口扩大,实际上也就是除了时延最短的那几行之外的每一行。
延伸阅读: TCP 吞吐量指南 更深入地讲解拥塞控制行为, MTU / MSS 计算器 则说明隧道开销如何改变 MSS、进而改变报文数量。
常见问题
什么是带宽时延积?
带宽时延积(BDP)是让链路保持满载所必须在途的数据量,等于带宽乘以往返时延。在 10 Gbps、RTT 50 ms 的链路上,BDP 是 10,000,000,000 × 0.05 = 500,000,000 比特,也就是 62.5 MB。这意味着必须始终有 62.5 MB 未被确认的数据在途,才能把管道填满。
为什么链路很快、时延很高时吞吐量却很差?
几乎总是因为 TCP 窗口太小,覆盖不了 BDP。发送方若只有 64 KB 窗口,在 100 ms RTT 上最多只能达到 64,000 × 8 ÷ 0.1 = 5.12 Mbps,无论底层链路有多快。解决办法是在两端启用 TCP 窗口扩大并配置足够的套接字缓冲区,而不是换一条更快的链路。
我需要的 TCP 窗口大小怎么算?
窗口(字节) = 目标吞吐量(比特每秒) × RTT(秒) ÷ 8。10 Gbps 在 100 ms RTT 上就是 10,000,000,000 × 0.1 ÷ 8 = 125,000,000 字节,即 125 MB。由于 TCP 首部的窗口字段只有 16 位,超过 65,535 字节就必须使用 RFC 7323 定义的窗口扩大选项。
什么是 TCP 窗口扩大?
原始 TCP 首部的窗口字段只有 16 位,通告窗口最大只能是 65,535 字节。窗口扩大选项在握手时协商,把这个字段乘以 2 的幂,使窗口最大可达 65,535 × 2^14 = 1,073,725,440 字节。只要有一端不支持,在长路径、高带宽的链路上再怎么调缓冲区都没用。
丢包对 TCP 吞吐量有什么影响?
影响极大。粗略地说,吞吐量与丢包率平方根的倒数成正比,因此丢包率从 0.01% 升到 1% 会让吞吐量下降约十倍。这就是为什么长距离链路上哪怕 0.1% 的丢包,也会毁掉纸面上看起来很好的性能。计算器里的 Mathis 模型可以估算这一影响,但它只是近似,不是预测。
这个计算器能预测我的实际吞吐量吗?
不能,任何在线计算器都不能。这里给出的是单条流在无丢包、无竞争流量路径上的理论上限。真实吞吐量还取决于拥塞控制算法、接收窗口自动调优、CPU 负载、应用行为以及路径上每一台设备的特性。请用这些数字判断当前受哪种约束限制,然后通过实测得到真实数值。
接收窗口和拥塞窗口有什么区别?
接收窗口(rwnd)由接收方通告,反映它还有多少缓冲区空间;拥塞窗口(cwnd)由发送方维护,反映网络看起来能承受多少。真实在途的数据量是两者的较小值。BDP 告诉你要达到的上限,rwnd 限制接收方愿意收多少,cwnd 限制发送方敢于发多少。