NetCalcLab

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 以上,单条流就能接近链路速率。做不到这一点,再大的带宽也无济于事。

丢包的影响

拥塞控制把丢包当作拥塞的证据,并据此降低发送速率。在存在丢包的路径上,吞吐量的上限来自丢包率,而不是窗口或带宽。

Mathis 等人的近似公式
吞吐量 ≈ (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,而不是理论值。
  • 无法调整两端时改用并行流。 每条流都有各自的窗口,因此十条流在高时延路径上大约能达到单流的十倍速率。
  • 先把丢包消灭掉。 如果路径本身在丢包,其它调优步骤都是白费功夫。

参考数值

常见链路与时延组合下的带宽时延积
RTT100 Mbps1 Gbps10 Gbps100 Gbps
1 ms(同一机柜)12.5 KB125 KB1.25 MB12.5 MB
10 ms(城域)125 KB1.25 MB12.5 MB125 MB
50 ms(跨地区)625 KB6.25 MB62.5 MB625 MB
100 ms(跨大西洋)1.25 MB12.5 MB125 MB1.25 GB
200 ms(洲际)2.5 MB25 MB250 MB2.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 限制发送方敢于发多少。