拥塞窗口(cwnd)是怎么长大的、什么时候缩小?慢启动真的是指数增长吗?丢包后降到一半还是降到 0.7?这篇每 10 毫秒读一次发送方内核里的 cwnd,在 100 ms 往返、0.3% 丢包的回环上记下一次传输的全过程。
lo0:snd_cwnd = 163321 字节,maxseg = 16332 字节 → 初始窗口 = 10.0 个 MSS;snd_ssthresh = 1073725440(慢启动阈值,初始近似无穷大) en0 到 example.com:snd_cwnd = 13880 字节,maxseg = 1388 字节 → 10.0 个 MSS(RFC 6928 的初始窗口是 10 个 MSS)
新连接的 cwnd 是 10 个 MSS,ssthresh 近似无穷大。
传输 53.8 MB;一共采到 673 个样本;MSS = 16332;srtt 稳定后约 101 ms
时间(秒) cwnd(字节) cwnd(个 MSS) ssthresh(字节) 累计重传包
0.00 163321 10.0 1073725440 0
0.09 163321 10.0 1073725440 0
0.20 310725 19.0 1073725440 0
0.30 621033 38.0 1073725440 0
0.41 1617285 99.0 1073725440 0
0.50 1617285 99.0 1073725440 0
0.60 3103497 190.0 1073725440 0
0.80 2939760 180.0 2939760 1
1.00 16332 1.0 2939760 2
1.50 1731192 106.0 2939760 2
2.00 1796520 110.0 1747524 3
3.00 685944 42.0 636948 6
4.00 408300 25.0 408300 8
6.00 310308 19.0 310308 10
8.00 326640 20.0 293976 11
开头 0.5 秒(5 个 RTT):cwnd 依次约 10 → 10 → 19 → 38 → 99 → 99 个 MSS——每个 RTT 翻倍,这就是指数增长的"慢启动"(名字起得不好)每收到 ACK 就增加 cwnd,等于每个 RTT 翻倍,直到丢包或到达 ssthresh。
8 秒内检测到 8 次 cwnd 明显下降(下降到降前的 75% 以下):
0.93 秒:cwnd 2939760 → 16332 字节(180 → 1 个 MSS),降后 / 降前 = 0.01,此时 ssthresh = 2939760
1.65 秒:cwnd 2498796 → 1747524 字节(153 → 107 个 MSS),降后 / 降前 = 0.70,此时 ssthresh = 1747524
2.15 秒:cwnd 1829184 → 1273896 字节(112 → 78 个 MSS),降后 / 降前 = 0.70,此时 ssthresh = 1273896
3.24 秒:cwnd 702276 → 506292 字节(43 → 31 个 MSS),降后 / 降前 = 0.72,此时 ssthresh = 506292
3.97 秒:cwnd 571620 → 408300 字节(35 → 25 个 MSS),降后 / 降前 = 0.71,此时 ssthresh = 408300
4.55 秒:cwnd 440964 → 326640 字节(27 → 20 个 MSS),降后 / 降前 = 0.74,此时 ssthresh = 310308
5.89 秒:cwnd 440964 → 310308 字节(27 → 19 个 MSS),降后 / 降前 = 0.70,此时 ssthresh = 310308
7.40 秒:cwnd 424632 → 293976 字节(26 → 18 个 MSS),降后 / 降前 = 0.69,此时 ssthresh = 293976
降后 / 降前的中位数 0.70(Reno 是 0.5;CUBIC 是 0.7)——本机默认用的是CUBIC 的 0.7 附近;net.inet.tcp.cubic_sockets 显示本机有 CUBIC 在用
net.inet.tcp.cubic_sockets: 445超时重传让 cwnd 回到 1 个 MSS;快速恢复只降到 0.7 倍(CUBIC),同时 ssthresh 设成降后的值。
0.0~0.9 秒这一段:cwnd 从 67 个 MSS 变到 180 个 MSS;斜率 214.0 个 MSS/秒 = 每个 RTT(100 ms)增加约 21.4 个 MSS 4.5~5.9 秒这一段:cwnd 从 21 个 MSS 变到 27 个 MSS;斜率 7.9 个 MSS/秒 = 每个 RTT(100 ms)增加约 0.8 个 MSS 5.9~7.4 秒这一段:cwnd 从 22 个 MSS 变到 26 个 MSS;斜率 4.5 个 MSS/秒 = 每个 RTT(100 ms)增加约 0.4 个 MSS 慢启动:cwnd 每个 RTT 翻倍,直到遇到 ssthresh 或丢包;拥塞避免:每个 RTT 只增加约 1 个 MSS(线性增长),CUBIC 则按三次函数曲线增长;丢包后乘性减小(cwnd 降到 β × cwnd,并把 ssthresh 设成同样的值)——AIMD
之后每个 RTT 只增长不到 1 个 MSS;CUBIC 接近上次丢包窗口时增长更平缓。