一、拥塞控制基础:TCP拥塞控制原理
各位同学好,我是老张。今天咱们聊聊TCP拥塞控制。说实话,这玩意儿我研究了十几年,踩过的坑能写本书。但别怕,我会用最接地气的方式讲明白。
先问个问题:为什么网络会拥塞?说白了,就是太多数据挤在一条路上。就像早高峰的北京三环,车多路窄,大家都走不动。TCP拥塞控制,就是给每个数据流配个“智能导航”,让它们别一窝蜂挤上去。
核心思想:TCP通过动态调整发送窗口大小,来探测网络容量。既不能发太快导致丢包,也不能发太慢浪费带宽。
1.1 慢启动:从试探开始
我记得刚入行时,有个老工程师跟我说:“TCP刚开始就像个害羞的小伙子,先轻轻敲门,再慢慢推门。” 这话我记到现在。
慢启动的原理很简单:
- 初始拥塞窗口(cwnd)很小,通常是1-10个MSS(最大报文段长度)
- 每收到一个ACK,cwnd翻倍
- 指数增长,直到达到慢启动阈值(ssthresh)
你想想看,为什么叫“慢启动”?其实它一点都不慢。指数增长,几个RTT就能冲到很高。我曾在项目中见过,一个短连接刚建立就发了大量数据,结果网络瞬间打满。嗯,这就是慢启动没控制好。
实战经验:我个人习惯在数据中心场景下,把初始cwnd设为10。这是Google的推荐值,经过大量验证。但如果你做的是物联网,建议设小点,比如2-3,避免小设备被冲垮。
1.2 拥塞避免:平稳巡航
当cwnd超过ssthresh后,TCP进入拥塞避免阶段。这时候增长方式变了:
- 每个RTT内,cwnd增加1个MSS
- 线性增长,不再翻倍
- 目的是缓慢探测网络剩余容量
为什么要这样?因为指数增长太猛了。你想想,如果一直翻倍,网络很快就会被撑爆。线性增长就像慢慢踩油门,找到那个“刚好不堵车”的速度。
我曾经遇到过一个案例:某视频平台高峰期卡顿严重。排查后发现,他们的TCP参数没调,ssthresh设得太高,导致拥塞避免阶段迟迟不触发。结果就是,网络稍微波动就大量丢包。调低ssthresh后,问题解决了。
避坑指南:我曾经在调优时犯过一个低级错误——把ssthresh设成0。结果TCP直接进入拥塞避免,永远不慢启动。这会导致短连接性能极差。记住:ssthresh是慢启动和拥塞避免的切换点,不是开关。
1.3 快速重传与快速恢复
网络不可能永远顺畅。当发生丢包时,TCP需要快速响应。这里有两个关键机制:
快速重传
传统做法是等超时重传,但那样太慢了。快速重传的思路是:
- 收到3个重复ACK,就认为报文丢失
- 立即重传,不等超时
- 这比超时重传快得多
为什么是3个?不是2个也不是4个?我记得有篇经典分析过:3个重复ACK既能避免误判(比如乱序导致),又能及时响应丢包。这个阈值经过大量实践验证,别乱改。
快速恢复
重传之后,TCP进入快速恢复阶段:
- ssthresh设为当前cwnd的一半
- cwnd设为ssthresh + 3(因为已经收到3个重复ACK)
- 每收到一个重复ACK,cwnd增加1个MSS
- 收到新ACK后,退出快速恢复,进入拥塞避免
说白了,快速恢复就是在丢包后“软着陆”。不像超时重传那样直接降到1,而是降到一半,然后慢慢恢复。这样既避免了网络震荡,又保持了吞吐量。
关键点:快速重传和快速恢复是配套使用的。我见过有人只开了快速重传,没开快速恢复,结果丢包后性能反而更差。因为重传后cwnd直接归零,又得从头慢启动。
知识体系总览
下面这张图是我自己画的,把TCP拥塞控制的三个核心阶段串起来了。你仔细看看,就能理解整个流程。
核心参数速查表
| 参数 | 含义 | 典型值 | 我的建议 |
|---|---|---|---|
| cwnd | 拥塞窗口,决定发送速率 | 动态变化 | 别手动改,让算法自己调 |
| ssthresh | 慢启动阈值 | 初始值通常很大 | 数据中心可设小点,减少震荡 |
| MSS | 最大报文段长度 | 1460字节(以太网) | 别改,除非你知道在做什么 |
| RTT | 往返时间 | 因网络而异 | 监控这个值,能发现很多问题 |
调优小技巧:我个人习惯在Linux上用ss -ti命令查看TCP连接状态。能看到cwnd、ssthresh、RTT等实时数据。调试时特别好用。
好了,这一章就到这里。TCP拥塞控制是网络性能的基石,理解透了,后面讲BBR、CUBIC这些高级算法时你才能跟上。记住:慢启动是试探,拥塞避免是巡航,快速重传/恢复是应急。三者配合,才能让网络跑得又快又稳。
可可精品资料库