嘿,大家好!今天咱们聊聊 TCP 拥塞控制和流量算法这个话题。TCP 是互联网的命脉之一,得保证数据顺畅跑,又不能把网络搞瘫。那这些算法咋实现的?有哪些种类?咱们从最简单的想法出发,一步步逼近现在的主流方案,顺便看看每步是怎么改进的。先上个表格,理清思路:
阶段 | 优势 | 劣势 |
---|---|---|
无控制随便发 | 简单,发送端爽快 | 网络容易堵死,丢包重传效率低 |
固定窗口 | 限制发送量,避免一次性塞满网络 | 窗口死板,适应不了网络变化 |
慢启动 + 拥塞避免 | 动态试探网络,丢包后能收敛 | 丢包反应太猛,恢复慢效率不高 |
TCP Reno(快恢复) | 丢包后恢复快,能更好利用带宽 | 只看丢包不管原因,误减窗口浪费 |
TCP Cubic | 恢复平稳,抗抖动强,带宽利用好 | 还是靠丢包判断,根子没变 |
BBR | 不依赖丢包,精准匹配网络状态 | 实现复杂,对带宽估算要求高 |
好了,有了这个地图,咱们开始正题,从最朴素的策略聊起,一路推到现在的牛掰方案。
最朴素的开场:随便发,想发多少发多少
想象 TCP 刚起步时,啥规矩没有,发送端跟个愣头青似的,想发多少就发多少。比如我有 10 个数据包,带宽 100Mbps,那就一股脑全扔出去,多痛快!
但问题立马就冒出来了。网络带宽要是只有 50Mbps,或者中间路由器忙不过来,数据包就堆积,队列一满就丢包。丢了包咋办?重传呗。可重传又占资源,网络更堵。这策略的毛病太明显:完全不看网络脸色,容易把路堵死。那咋改进呢?得让发送端有点眼色,感知一下网络状态,别乱来。
第一步:引入窗口,稍微收敛一点
于是就有了个新点子:别一次发太多,定个"窗口",每次就发这么多,等确认收到再发下一波。这就是 TCP 的滑动窗口。比如窗口设成 4 个包,我先发 4 个,收到 ACK(确认)后窗口往前滑,继续发后面的。
这比乱发靠谱多了,至少不会一下把网络塞爆。但窗口大小定死了行不行?比如永远是 4 个包?不行。网络是活的,有时候能撑 8 个包,有时候 2 个包都嫌多,丢包了还得重传,效率低得不行。固定窗口太僵,没法跟上网络节奏 。那咋优化?窗口得活起来,根据网络反馈动态调整。
再进一步:慢启动 + 拥塞避免
光有窗口不够,发送端得学会"试探"网络。这就有了"慢启动"(Slow Start)。一开始窗口很小,比如 1 个包,收到 ACK 就翻倍到 2 个,再收到 ACK 变 4 个,指数增长。到了一个阈值(ssthresh),就切到"拥塞避免"(Congestion Avoidance),窗口每次加 1 个,线性增长。
为啥这么搞?慢启动是探路,看看网络能吃下多少。一旦丢包了,说明可能超载,发送端就把窗口砍一半,然后重新进入慢启动,从 1 个包开始试探。比如窗口从 1 到 2、4、8,丢包后砍到 4,再从 1 开始涨到 2、4。这比固定窗口聪明,能自己适应环境。这是 TCP Tahoe 的基本逻辑。
但问题来了:丢包后窗口砍一半,然后直接从 1 个包重新慢启动,是不是有点狠?有时候丢包只是网络抖了一下,不是真堵死,从 1 爬回来太慢,效率不高。反应太简单粗暴,没能充分利用网络潜力 。那优化方向呢?能不能更细致地判断丢包情况,或者丢包后恢复得更快些?
进化版:TCP Reno,快恢复登场
接下来是 TCP Reno,它在 Tahoe 的基础上加了个"快恢复"(Fast Recovery),让丢包处理更聪明。Reno 把丢包分成两种情况:一种是收到三个重复的 ACK(说明丢了一个包,但后面的包还到了),另一种是超时(啥都没收到,网络可能真崩了)。
- 三个重复 ACK:这说明网络没完全堵死,只是丢了个包。发送端把窗口砍一半,然后进入快恢复,直接线性增长。比如窗口是 10,丢包后收到三个重复 ACK,砍到 5,然后每次加 1,变成 6、7,很快试探回去。
- 超时:这可能是网络彻底挂了,发送端就老实点,把窗口设回 1,重新慢启动,从 1、2、4 这样涨回来。
举个例子,网络能撑 8 个包,窗口涨到 10 时丢了一个,收到三个重复 ACK,窗口砍到 5,很快加到 6、7、8,比 Tahoe 从 1 爬上来快多了。如果超时了,才会回 1 重启。这比 Tahoe 高明,能更快用上带宽。
但短板呢?Reno 只看丢包,不管丢包为啥发生的 。要是无线网信号差丢的包,Reno 也傻乎乎减窗口,白浪费带宽。优化方向:得更聪明地搞清楚丢包根源,别一刀切。
现代主流:TCP Cubic 和 BBR
现在拥塞控制已经很高级了,咱们聊俩代表:TCP Cubic 和 BBR。
TCP Cubic 是现在常见的,比如 Linux 默认用它。它用三次函数控制窗口增长,丢包后减一点(比如乘 0.7),然后快速涨回之前的高点,再放缓。比 Reno 强在哪?恢复平稳,对抖动不敏感,带宽利用率高。
但 Cubic 还是老思路,靠丢包判断拥塞。现代网络丢包不一定是堵了,可能是信号问题。咋办?Google 的 BBR 来了。它不看丢包,直接算网络的瓶颈带宽和最小延迟(RTT),然后贴着这速度发。比如测出带宽 50Mbps,RTT 20ms,就控制在 50Mbps 附近跑,动态调整。结果是丢包少,效率高,尤其在无线网或长距离传输里特别香。
总结:从愣头青到精算师
TCP 拥塞控制的演进就像从愣头青变精算师。一开始乱发,堵了再说;后来加窗口学会试探;再后来分清丢包类型,恢复加速;现在直接算网络能跑多快,精准发力。每步都在解决前面的坑:效率低、反应慢、误判网络。
现代方案的核心:感知网络更聪明,利用带宽更狠,适应场景更灵活。数字上,BBR 在高丢包场景下吞吐量能比 Cubic 高 2-3 倍,延迟降 10 倍,下次视频不卡,记得夸一句:TCP 拥塞控制,真牛!