Reno、CUBIC、BBR 到底有什么不同?本机用的是哪一个,它的窗口增长真的符合公式吗?这篇验证 CUBIC 的三次曲线,用 Mathis 公式对比实测吞吐,再用一个明确标注的玩具模拟比较基于丢包和基于测量的两类思路。
net.inet.tcp.cubic_sockets: 407 net.inet.tcp.use_newreno: 0 net.inet.tcp.pacing: 0 net.inet.tcp.cc_debug: 0 use_newreno = 0 表示默认不用 NewReno;cubic_sockets 是当前在用 CUBIC 的套接字数(随时间变化);没有找到按套接字切换算法的 setsockopt(Linux 的 TCP_CONGESTION 在 macOS 上没有对应项),所以下面不做 Reno / BBR 的实测对照
本机默认是 CUBIC;macOS 上没有按套接字选择算法的接口,所以没有 Reno / BBR 的实测对照。
传输 36.6 MB;找到 5 个快速恢复事件(降到降前的 60%~80%)
事件时刻 降前 W_max(MSS) 降后(MSS) K(秒) 丢包后 0.3 s:实测/预测 0.6 s:实测/预测 0.9 s:实测/预测(MSS)
0.51 s 33 23 2.91 24/26 26/28 27/30
2.22 s 33 24 2.91 26/26 (中间又丢包) (中间又丢包)
2.72 s 26 19 2.69 20/21 21/22 23/24
3.73 s 24 17 2.62 18/19 20/21 21/22
7.15 s 43 30 3.18 31/33 29/36 25/38
13 个可比较的点上,实测与预测的相对误差:中位 6%,最大 35%——量级吻合;不完全相等是因为 ① 实测 cwnd 受 ACK 到达节奏和 10 ms 采样影响;② 窗口很小时 CUBIC 会切换到"像 Reno 一样增长"的 TCP 友好区域;③ 公式里的 C、β 是 RFC 8312 的建议值,实现可能有差别丢包后窗口按 C·(t − K)³ + W_max 回升,先快后平再快;实测与公式基本吻合。
丢包率 实测吞吐(MB/s) Reno(Mathis 公式)(MB/s) 实测 / 公式
0.1% 13.25 6.30 2.10
0.3% 9.92 3.64 2.73
1.0% 3.88 1.99 1.95
3.0% 1.19 1.15 1.04
丢包越少,CUBIC 比 Reno 公式的预测快得越多(高 BDP 路径上 CUBIC 恢复更快);丢包很多时两者接近。公式是粗略的稳态估计,这里只看趋势用 Mathis 公式当作 Reno 的预期吞吐,实测的 CUBIC 在高时延路径上快 1~2.7 倍。
丢包率 Reno(MB/s) CUBIC(MB/s) BBR 近似(MB/s) 链路带宽 12.5 MB/s
0.01% 1.74 3.25 11.87
0.10% 0.57 0.56 11.86
1.00% 0.19 0.10 11.75
3.00% 0.10 0.04 11.52
这个模拟只体现思路:基于丢包的算法(Reno / CUBIC)把每个丢包都当成拥塞,随机丢包多的链路(无线、长距离)吞吐被压得很低;BBR 依据带宽和 RTT 的测量建模,对随机丢包不敏感——但 BBR 的真实表现(与别的流公平、队列长度)模拟里没有体现,本机也没法切换到 BBR 实测玩具模拟说明:基于丢包的算法在随机丢包多的链路上吞吐被压得很低,基于带宽 / RTT 测量的算法不受影响。BBR 一栏是假设设定,不是实测。