TCP 拥塞控制:cwnd 怎么变大、丢包时怎么收
更新时间:2026-09-17。网络协议域·传输层。本篇讲协议状态机与窗口增减机制;性能调参、CUBIC/BBR 的内核实现与实测见 concepts/network/tcp-flow-congestion-control。
流量控制解决"别压垮接收方"(rwnd,见滑动窗口),拥塞控制解决"别压垮网络"。发送方维护一个由自己估算的拥塞窗口 cwnd,实际发送量取 min(cwnd, rwnd)。新连接或刚发生拥塞时 cwnd 很小,靠算法探测可用带宽逐步放大,一旦发现拥塞(丢包/排队)就果断收缩。
一、四个经典阶段
以早期 TCP Reno/Tahoe 为代表,cwnd 以 MSS 为单位变化:
| 阶段 | 触发 | cwnd 变化 |
|---|---|---|
| 慢启动 slow start | 连接开始 / 超时后 | 每 RTT 翻倍(指数增长),直到 ssthresh |
| 拥塞避免 congestion avoidance | cwnd ≥ ssthresh | 每 RTT +1 MSS(线性增长,AIMD 的 MI 部分) |
| 快重传 fast retransmit | 收到 3 个重复 ACK | 立即重传,见重传篇 |
| 快恢复 fast recovery | 紧跟快重传 | cwnd 减半(+3),不回慢启动,进入拥塞避免 |
bash
cwnd
│ 慢启动(指数) 拥塞避免(线性 +1/RTT)
│ ╱ ╱──────╲ 丢包
│ ╱ ╱ ╲ 减半(快恢复)
│ ╱ ╱ ╲────
│ ╱ ╱
│ 1 MSS╱__________╱
└────────────────────────────────────────── 时间/RTT二、两类拥塞信号,反应不同
- 超时(RTO):被视为严重拥塞。
ssthresh = cwnd/2,cwnd直接打回 1(Tahoe)或极小值,从慢启动重来——吞吐跌得最狠。 - 3 个重复 ACK(快重传):说明后续包其实到了,网络没完全断。Reno 走快恢复:
ssthresh=cwnd/2、cwnd≈ssthresh,减半后线性增长,而不是从头开始。
这种"和式增、积式减"(AIMD:加性增、乘性减)让多条共享瓶颈的 TCP 流最终公平收敛到大致均分带宽——这是互联网公平性的基石。
三、ssthresh:慢启动到线性的闸门
慢启动门限 ssthresh(slow start threshold)决定何时停止指数增长:
cwnd < ssthresh:慢启动(翻倍)。cwnd ≥ ssthresh:拥塞避免(线性)。- 发生丢包时把 ssthresh 降到当时 cwnd 的一半,作为下次探测的目标。
四、现代算法:CUBIC 与 BBR
经典 Reno 把"丢包"当作拥塞的唯一信号,在深缓冲/高 BDP 网络会导致 bufferbloat,在不丢包但已排队的链路过慢。
| 算法 | 信号与模型 | 特点 |
|---|---|---|
| CUBIC(Linux 2.6.19+ 默认) | 仍以丢包为主,但用三次函数曲线探测,增长与 RTT 解耦 | 高 BDP 下比 Reno 更激进、流间更公平,仍是丢包驱动 |
| BBR(Google) | 不看丢包,主动测量 瓶颈带宽与最小 RTT,把发送速率/ inflight 建模在 BDP 附近 | 不填满缓冲区,弱网/长肥管道吞吐与延迟显著改善;与 CUBIC 共存的公平性需评估 |
| 其他 | Reno、NewReno、Vegas(看延迟)、DCTCP(数据中心) | — |
bash
sysctl net.ipv4.tcp_congestion_control # 当前算法(常见 cubic;可设 bbr)
ss -ti | grep -i 'cwnd\|bytes_acked\|bbr' # 单连接 cwnd、rtt 等
# 开启 BBR:net.core.default_qdisc=fq + net.ipv4.tcp_congestion_control=bbr五、和流控、重传、ECN 的分工
- 流控(rwnd):保护接收方;拥塞控制(cwnd):保护网络,发送取两者小值。
- 重传:解决"丢了怎么补";拥塞控制解决"发多快",但快重传是拥塞算法的输入信号(见重传与 RTO)。
- ECN:让网络设备在丢包前就显式通知"开始拥塞了",发送方可提前降速,避免以丢包为代价(见 TCP ECN)。
- 初始拥塞窗口、握手开销与 TFO 影响短连接体验,见 HTTPS 性能。
相关阅读
内核实现/调参/实测见 TCP 拥塞控制(性能篇),接收窗口见滑动窗口流控,显式拥塞通知见 ECN。
总结
TCP 用 cwnd(与 rwnd 取小)探测网络容量:慢启动每 RTT 翻倍到 ssthresh,转拥塞避免后每 RTT 线性 +1(AIMD 的加性增),超时就回慢启动、3 个重复 ACK 则快重传并把窗口减半走快恢复(乘性减),以此公平分享瓶颈带宽;现代 CUBIC 以三次曲线优化高 BDP、BBR 改用带宽与最小 RTT 建模而非等丢包,ECN 则把拥塞信号提前到丢包之前。