欢迎光临
我们一直在努力

《TCP 拥塞控制详解(1):慢开始、拥塞避免、快重传与快恢复》

TCP 拥塞控制详解:慢开始、拥塞避免、快重传与快恢复

本篇笔记仅讲解概念,实例分析放在下一篇笔记中

一、什么是 TCP 拥塞控制?

1. 拥塞控制的背景

在 TCP 通信过程中,发送方会不断向网络发送数据。如果发送速度过快,超过了网络中路由器、交换机等设备的处理能力,就可能导致网络中的数据包大量堆积

当网络设备的缓存空间被占满时,后续到达的数据包可能被丢弃,从而产生丢包、重传和延迟增加等问题

这种网络负载超过网络处理能力的现象,称为网络拥塞(Network Congestion)

例如:

发送方 A 网络设备 接收方 B
| | |
|—— 数据包 1 ——->|————————>|
|—— 数据包 2 ——->|————————>|
|—— 数据包 3 ——->| |
|—— 数据包 4 ——->| 缓存逐渐堆积 |
|—— 数据包 5 ——->| 缓存空间不足 |
| | 数据包丢失 |
| | |
|<———————– ACK / 确认信息 ———–|

如果发送方不考虑网络的承载能力,继续高速发送数据,就可能加剧网络拥塞。

因此,TCP 需要根据网络状况动态调整数据发送速度,这就是拥塞控制(Congestion Control)

2. 拥塞控制的核心思想

拥塞控制的核心思想是:

根据网络的拥塞程度动态调整发送方的拥塞窗口,控制发送数据的速度,避免网络出现严重拥塞。

TCP 主要通过四种算法实现拥塞控制:

  • 慢开始(Slow Start)

  • 拥塞避免(Congestion Avoidance)

  • 快重传(Fast Retransmit)·

  • 快恢复(Fast Recovery)

  • 这四种算法并不是彼此独立的,而是协同工作,共同调节 TCP 的数据发送行为。


    二、拥塞控制中的重要概念

    在理解四种算法之前,需要先掌握三个重要概念。

    1. 拥塞窗口(Congestion Window,cwnd)

    拥塞窗口是发送方根据当前网络拥塞情况维护的一个窗口大小。

    它反映了发送方认为当前网络能够承受的未确认数据量。

    • 网络状况较好:可以适当增大拥塞窗口,提高发送速度。

    • 网络出现拥塞:需要减小拥塞窗口,降低发送速度。

    注意:cwnd 是发送方维护的,不是接收方维护的。

    2. 接收窗口(Receive Window,rwnd)

    接收窗口是接收方根据自身接收缓存情况通告给发送方的窗口大小。

    它主要用于流量控制(Flow Control),防止发送方发送的数据超过接收方的处理能力。

    3. 实际发送窗口

    TCP 发送方实际能够使用的发送窗口,同时受到拥塞控制和流量控制的限制。

    实际发送窗口 = min(cwnd, rwnd)

    其中:
    cwnd:拥塞窗口(Congestion Window)
    rwnd:接收窗口(Receive Window)

    例如:

    cwnd = 10 KB
    rwnd = 6 KB

    实际发送窗口 = min(10 KB, 6 KB)
    = 6 KB

    虽然网络允许发送 10 KB,但接收方只能接收 6 KB,因此发送方最多只能发送 6 KB 的未确认数据。

    面试注意:

    • 拥塞控制(Congestion Control):考虑网络的承载能力

    • 流量控制(Flow Control):考虑接收方的接收能力


    三、慢开始(Slow Start)

    1. 为什么需要慢开始?

    TCP 连接刚建立时,发送方并不知道当前网络的承载能力。

    如果一开始就发送大量数据,可能会导致网络突然出现拥塞。

    因此,TCP 不会一开始就使用很大的拥塞窗口,而是从较小的窗口开始,根据收到的确认信息逐步增大窗口。

    这种方式称为慢开始。

    注意:慢开始并不意味着窗口增长速度很慢,而是指从较小的窗口开始探测网络承载能力。

    2. 慢开始的工作原理

    慢开始阶段,拥塞窗口按照指数规律增长。

    在经典教材模型中:

    • 初始拥塞窗口为较小值,示例中取 1 MSS。

    • 每收到一个新的 ACK,cwnd 增加 1 MSS。

    • 一个 RTT 内通常可以收到约 cwnd 个 ACK。

    • 因此,每经过一个 RTT,拥塞窗口大致翻倍。

    MSS(Maximum Segment Size)表示最大报文段长度。

    假设初始拥塞窗口为 1 MSS:

    RTT 0:cwnd = 1 MSS

    RTT 1:cwnd = 2 MSS

    RTT 2:cwnd = 4 MSS

    RTT 3:cwnd = 8 MSS

    RTT 4:cwnd = 16 MSS

    3. 慢开始增长图

    拥塞窗口(Congestion Window,cwnd)
    |
    16| ●
    | /
    | /
    8| ●
    | /
    | /
    4| ●
    | /
    2| ●
    | /
    1| ●
    +——————————–> 时间(RTT)
    0 1 2 3 4

    指数增长(Exponential Growth)

    可以看到,慢开始阶段的窗口增长速度越来越快。

    4. 慢开始门限(Slow Start Threshold,ssthresh)

    为了避免拥塞窗口无限制地指数增长,TCP 引入了一个阈值:

    慢开始门限(ssthresh)。

    它用于决定当前应该使用哪一种窗口增长方式:

    • 当 cwnd < ssthresh 时,使用慢开始。

    • 当 cwnd >= ssthresh 时,进入拥塞避免。

    例如:

    初始 cwnd = 1 MSS
    ssthresh = 16 MSS

    cwnd:1 → 2 → 4 → 8 → 16

    达到 ssthresh 后,进入拥塞避免阶段。

    注意:慢开始门限不是网络拥塞的绝对临界值,而是 TCP 用来切换增长策略的控制参数。


    四、拥塞避免(Congestion Avoidance)

    1. 为什么需要拥塞避免?

    慢开始阶段采用指数增长,窗口增长速度非常快。

    如果一直按照指数规律增长,可能很快超过网络的承载能力,引发拥塞。

    因此,当拥塞窗口达到慢开始门限后,TCP 会降低窗口增长速度,进入拥塞避免阶段。

    2. 拥塞避免的工作原理

    拥塞避免阶段,拥塞窗口按照线性规律增长。

    经典教材模型中:

    每经过一个 RTT,拥塞窗口大约增加 1 MSS。

    例如:

    当前 cwnd = 16 MSS

    RTT 1:17 MSS
    RTT 2:18 MSS
    RTT 3:19 MSS
    RTT 4:20 MSS

    它不再像慢开始一样每经过一个 RTT 就翻倍,而是缓慢增加。

    从每个 ACK 的角度看,拥塞避免通常可以近似表示为:

    每收到一个新 ACK:

    cwnd += MSS * MSS / cwnd

    在一个 RTT 内累计起来,窗口大约增加 1 MSS。

    3. 拥塞避免增长图

    拥塞窗口(Congestion Window,cwnd)
    |
    20| ●
    19| ●
    18| ●
    17| ●
    16| ●
    |
    +——————————–> 时间(RTT)
    0 1 2 3 4

    线性增长(Linear Growth)

    4. 慢开始与拥塞避免的区别

    对比项目慢开始(Slow Start)拥塞避免(Congestion Avoidance)
    增长规律 指数增长 线性增长
    窗口变化 每 RTT 大致翻倍 每 RTT 大约增加 1 MSS
    进入条件 连接初期或超时恢复后 cwnd >= ssthresh
    主要目的 探测网络承载能力 更谨慎地增加发送速度

    可以记忆为:

    慢开始:指数增长,快速探测网络能力。

    拥塞避免:线性增长,谨慎增加发送速度。


    五、快重传(Fast Retransmit)

    1. 为什么需要快重传?

    TCP 采用可靠传输机制,发送方发送数据后,需要接收方返回 ACK 确认。

    如果发送的数据包丢失,发送方需要重新发送丢失的数据。

    传统方式主要依靠超时重传(Retransmission Timeout,RTO):

    发送方等待一段时间,如果仍然没有收到确认,就认为数据可能丢失,然后重新发送。

    但这种方式存在一个问题:

    如果数据实际上已经丢失,发送方仍然需要等待超时时间,才能进行重传。

    这会增加通信延迟。

    因此,TCP 引入了快重传机制。

    2. 快重传的工作原理

    快重传的核心思想:

    发送方连续收到 3 个重复 ACK 时,就认为某个数据段可能丢失,不必等待超时,立即重传丢失的数据。

    为什么会出现重复 ACK?

    假设发送方连续发送 4 个数据段:

    DATA 1
    DATA 2
    DATA 3
    DATA 4

    其中 DATA 2 丢失了。

    接收方收到 DATA 1 后,正常确认 DATA 1。

    但当接收方收到 DATA 3 和 DATA 4 时,由于 DATA 2 尚未收到,数据流中出现了缺口。

    TCP 使用累计确认(Cumulative Acknowledgment),因此接收方仍然确认自己期望收到的下一个字节。

    于是,接收方会连续返回相同的 ACK。

    3. 快重传过程图

    发送方(Sender) 接收方(Receiver)
    | |
    |——— DATA 1 —————–>|
    |<——– ACK 2 ——————-|
    | |
    |——— DATA 2 —-X | 数据丢失
    | |
    |——— DATA 3 —————–>|
    |<——– ACK 2 ——————-| 重复 ACK 1
    | |
    |——— DATA 4 —————–>|
    |<——– ACK 2 ——————-| 重复 ACK 2
    | |
    |——— DATA 5 —————–>|
    |<——– ACK 2 ——————-| 重复 ACK 3
    | |
    | 立即重传 DATA 2 |
    |——— DATA 2(重传)———->|
    | |
    |<——– ACK 6 ——————-| 累计确认
    | |

    说明:

    • DATA 2 丢失。

    • 接收方收到后续数据时,仍然返回 ACK 2。

    • 发送方收到 3 个重复 ACK 后,触发快重传。

    • 发送方不必等待 RTO 超时,立即重传 DATA 2。

    • 接收方收到缺失数据后,可以一次性确认连续收到的数据。

    图中 DATA 1、DATA 2 等是便于理解的简化编号。实际 TCP 的 ACK 确认的是字节序号,而不是数据段编号。

    4. 快重传的优点

    与传统超时重传相比:

    • 不需要等待 RTO 超时。

    • 能够更快地发现可能丢失的数据。

    • 降低数据重传的等待时间。

    • 提高 TCP 传输效率。

    注意:经典 TCP Reno 通常使用 3 个重复 ACK 作为触发快重传的条件。现代 TCP 还可能结合其他丢包检测机制。


    六、快恢复(Fast Recovery)

    1. 为什么需要快恢复?

    快重传解决了数据丢失后等待超时的问题。

    但当发送方发现数据丢失时,也说明当前网络可能出现了拥塞。

    因此,发送方需要降低发送速度。

    如果每次收到 3 个重复 ACK 都直接将拥塞窗口降到 1 MSS,再重新进行慢开始,就可能过于保守。

    所以,TCP Reno 引入了快恢复机制。

    快恢复的核心思想:发生轻度拥塞时,降低拥塞窗口,但不必将窗口直接降到 1 MSS,而是从较大的窗口重新进入拥塞避免。

    2. 快恢复的工作原理

    以经典 TCP Reno 为例:

    假设:

    当前 cwnd = 16 MSS
    FlightSize = 16 MSS

    FlightSize 表示当前已经发送但尚未收到确认的数据量。

    当发送方收到 3 个重复 ACK 时:

    第一步:调整慢开始门限。

    ssthresh = max(FlightSize / 2, 2 * MSS)

    假设 FlightSize = 16 MSS

    ssthresh = 8 MSS

    第二步:调整拥塞窗口。

    cwnd = ssthresh + 3 * MSS

    cwnd = 8 + 3
    = 11 MSS

    这里加上 3 MSS,是因为已经收到 3 个重复 ACK,说明有后续数据到达接收方,网络中仍然存在一定的数据传输活动。

    第三步:执行快重传。

    立即重传丢失的数据段。

    第四步:处理后续重复 ACK。

    如果继续收到额外的重复 ACK,经典 Reno 会将 cwnd 再增加 1 MSS,并在满足发送条件时继续发送数据。

    第五步:收到新的 ACK。

    当发送方收到确认重传数据的新 ACK 后:

    cwnd = ssthresh

    此时:

    cwnd = 8 MSS

    随后进入拥塞避免阶段,按照线性规律增长。

    3. 快恢复过程图

    拥塞窗口(cwnd)

    16 MSS ───────────────● 发生丢包
    |
    | 收到 3 个重复 ACK
    |
    11 MSS ● 快恢复(Fast Recovery)
    |
    | 收到新的 ACK
    |
    8 MSS ───────────────● 进入拥塞避免
    |
    | 线性增长
    |
    ●
    ●
    ●
    +——————–> 时间

    注意:

    经典 Reno 在第三个重复 ACK 到达时,临时将 cwnd 设置为 ssthresh + 3 MSS,收到新的 ACK 后再将其设置为 ssthresh。

    因此,不能简单地说拥塞窗口从 16 MSS 直接变成 8 MSS,中间还有快恢复阶段的临时窗口调整。


    七、超时重传与拥塞窗口调整

    快重传主要针对能够通过重复 ACK 发现的数据丢失。

    但如果发送方长时间没有收到 ACK,就可能触发超时重传(RTO)。

    在经典 TCP Reno 教材模型中,超时通常被认为是更严重的拥塞信号。

    假设:

    原 cwnd = 20 MSS
    FlightSize = 20 MSS

    发生 RTO 超时后:

    第一步:重新计算慢开始门限。

    ssthresh = max(FlightSize / 2, 2 * MSS)

    ssthresh = 10 MSS

    第二步:将拥塞窗口降到 1 MSS。

    cwnd = 1 MSS

    第三步:重新进入慢开始。

    1 → 2 → 4 → 8 → 10

    达到 ssthresh 后,再进入拥塞避免阶段。

    超时重传示意图

    拥塞窗口(cwnd)

    20 MSS ─────────────● 发生 RTO 超时
    |
    |
    ● 降至 1 MSS
    1 MSS ─────────────●
    |
    | 慢开始(指数增长)
    |
    2 MSS ●
    |
    4 MSS ●
    |
    8 MSS ●
    |
    10 MSS ● 达到 ssthresh
    |
    | 拥塞避免(线性增长)
    |
    +——————–> 时间


    八、四种算法如何协同工作?

    前面分别介绍了四种算法,现在将它们联系起来。

    TCP 拥塞控制的整体工作流程可以概括为:

    TCP 连接建立
    |
    v
    慢开始(Slow Start)
    |
    | cwnd 达到 ssthresh
    v
    拥塞避免(Congestion Avoidance)
    |
    | 发现数据丢失
    v
    判断丢失信号
    / \\
    / \\
    3 个重复 ACK RTO 超时
    | |
    v v
    快重传 ssthresh 减半
    (Fast Retransmit) |
    | v
    v cwnd = 1 MSS
    快恢复 |
    (Fast Recovery) v
    | 慢开始
    v
    cwnd = ssthresh
    |
    v
    拥塞避免

    注意:图中是经典 TCP Reno 的简化流程。实际 TCP 实现还可能使用选择确认(SACK)、更复杂的丢包恢复机制和不同的拥塞控制算法。


    九、TCP Tahoe 与 TCP Reno 的区别

    理解完四种算法后,还需要了解两种经典 TCP 拥塞控制方案。

    1. TCP Tahoe

    TCP Tahoe 是较早的一种拥塞控制方案。

    它包含:

    • 慢开始(Slow Start)

    • 拥塞避免(Congestion Avoidance)

    • 快重传(Fast Retransmit)

    但没有快恢复机制。

    无论是收到 3 个重复 ACK,还是发生 RTO 超时,Tahoe 都会将拥塞窗口重新设置为 1 MSS,然后重新慢开始。

    2. TCP Reno

    TCP Reno 在 Tahoe 的基础上增加了快恢复机制。

    它包含四种核心算法:

    • 慢开始

    • 拥塞避免

    • 快重传

    • 快恢复

    当收到 3 个重复 ACK 时,Reno 使用快重传和快恢复,避免拥塞窗口直接降到 1 MSS。

    但发生 RTO 超时时,经典 Reno 仍然会将拥塞窗口降到 1 MSS,重新进行慢开始。

    3. 两者对比

    对比项目TCP TahoeTCP Reno
    慢开始 支持 支持
    拥塞避免 支持 支持
    快重传 支持 支持
    快恢复 不支持 支持
    3 个重复 ACK cwnd 降至 1 MSS 进入快恢复
    RTO 超时 cwnd 降至 1 MSS cwnd 降至 1 MSS

    面试重点:

    Tahoe 与 Reno 最重要的区别是:Reno 增加了快恢复机制。


    十、现代 TCP 拥塞控制算法

    前面介绍的慢开始、拥塞避免、快重传和快恢复,是理解传统 TCP 拥塞控制机制的重要基础。

    但现代 TCP 实际使用的拥塞控制算法还包括 CUBIC、BBR 等。

    1. CUBIC

    CUBIC 是一种基于拥塞窗口变化的拥塞控制算法。

    它使用三次函数调整拥塞窗口,在高带宽、长延迟网络中具有较好的性能。

    Linux 系统中广泛使用 CUBIC。

    2. BBR

    BBR 是一种基于带宽和 RTT 估计的拥塞控制算法。

    它主要通过估计:

    • 瓶颈带宽(Bottleneck Bandwidth)

    • 最小往返时延(Minimum RTT)

    来调整数据发送速率。

    与传统主要依靠丢包判断拥塞的算法不同,BBR 不将丢包作为主要拥塞信号,而是尝试根据网络的带宽和时延模型控制发送速率。

    注意:BBR 并不是完全不处理丢包,而是其拥塞控制决策不单纯依赖丢包信号。


    十一、面试高频考点

    1. 什么是 TCP 拥塞控制?

    TCP 拥塞控制是指发送方根据网络的拥塞情况动态调整拥塞窗口(cwnd),控制数据发送速度,避免网络出现严重拥塞,从而提高网络传输效率。

    2. TCP 拥塞控制有哪些算法?

    经典 TCP 拥塞控制主要包括四种算法:

  • 慢开始:拥塞窗口指数增长。

  • 拥塞避免:拥塞窗口线性增长。

  • 快重传:收到 3 个重复 ACK 后,立即重传丢失的数据。

  • 快恢复:发生轻度拥塞后,将窗口调整到较低水平,再进入拥塞避免。

  • 3. 慢开始为什么叫慢开始?

    慢开始并不是指增长速度慢,而是指发送方从较小的拥塞窗口开始,逐步探测网络承载能力。

    其窗口在经典模型中按照指数规律增长,速度实际上比较快。

    4. 慢开始和拥塞避免有什么区别?

    慢开始采用指数增长,每经过一个 RTT,拥塞窗口大约翻倍。

    拥塞避免采用线性增长,每经过一个 RTT,拥塞窗口大约增加 1 MSS。

    5. 什么是慢开始门限?

    慢开始门限(ssthresh)是 TCP 用来决定拥塞窗口增长策略的参数。

    当 cwnd < ssthresh 时,使用慢开始;当 cwnd >= ssthresh 时,使用拥塞避免。

    6. 快重传为什么需要 3 个重复 ACK?

    当接收方收到失序数据时,会重复确认当前期望收到的下一个字节。

    发送方连续收到 3 个重复 ACK,说明后续数据仍然能够到达接收方,但某个数据可能已经丢失。

    因此,发送方可以推测发生了丢包,并立即进行重传,而不必等待超时。

    7. 快重传和超时重传有什么区别?

    快重传通过重复 ACK 发现可能丢失的数据,不需要等待 RTO。

    超时重传则是在发送方等待确认超过 RTO 后,才执行重传。

    8. 快恢复为什么不将拥塞窗口降到 1 MSS?

    因为收到 3 个重复 ACK 时,说明网络中仍然有后续数据到达接收方,网络并非完全无法传输数据。

    因此,经典 Reno 会将拥塞窗口调整到 ssthresh + 3 MSS,完成重传后再将窗口调整为
    ssthresh,进入拥塞避免。

    9. 拥塞控制和流量控制有什么区别?

    拥塞控制考虑的是网络整体的承载能力,通过 cwnd 调整发送速度。

    流量控制考虑的是接收方的接收能力,通过 rwnd 限制发送方的数据发送量。

    实际发送窗口受二者共同限制:

    发送窗口 = min(cwnd, rwnd)

    10. TCP Tahoe 和 TCP Reno 有什么区别?

    Tahoe 不支持快恢复,发生丢包后会将拥塞窗口降到 1 MSS。

    Reno 增加了快恢复机制,收到 3 个重复 ACK 时可以通过快重传和快恢复,避免窗口直接降到 1 MSS。


    十二、总结

    建议重点理解的窗口变化过程

    这一部分建议单独记忆,因为面试官很喜欢通过给定窗口数值,让你分析 TCP 的状态变化。

    经典 TCP Reno 窗口变化示意

    阶段一:慢开始

    1 → 2 → 4 → 8 → 16

    每经过一个 RTT,cwnd 约翻倍。

    阶段二:拥塞避免

    16 → 17 → 18 → 19 → 20

    每经过一个 RTT,cwnd 约增加 1 MSS。

    阶段三:收到 3 个重复 ACK

    20 → 10(示意)

    ssthresh 调整为 FlightSize 的一半,进入快恢复;这里省略了 Reno 的临时窗口膨胀细节。

    阶段四:发生 RTO 超时

    20 → 1

    经典 Reno 将 cwnd 降到 1 MSS,重新进入慢开始。

    这里有一个容易混淆的地方: 快恢复期间,Reno 的 cwnd 并不是直接从 20 变成 10。它先设置 ssthresh,再将 cwnd 临时设置为 ssthresh + 3 MSS,收到新 ACK 后才将 cwnd 设为 ssthresh。

    容易出现的三个错误

  • 把拥塞控制和流量控制混为一谈。 前者关注网络,后者关注接收方。

  • 认为慢开始增长速度慢。 实际上慢开始是指数增长,增长速度很快。

  • 认为快重传和快恢复是同一个算法。 快重传解决的是尽早重传丢失数据的问题,快恢复解决的是丢包后如何调整拥塞窗口的问题。

  • TCP 拥塞控制的核心是通过动态调整拥塞窗口(cwnd),控制发送方的数据发送速度。

    四种经典算法各司其职:

    • 慢开始(Slow Start):从较小窗口开始,指数增长,探测网络承载能力。

    • 拥塞避免(Congestion Avoidance):达到慢开始门限后,线性增长,谨慎提高发送速度。

    • 快重传(Fast Retransmit):收到 3 个重复 ACK 后,不等待超时,立即重传丢失的数据。

    • 快恢复(Fast Recovery):发生轻度拥塞后,适当降低拥塞窗口,完成恢复后进入拥塞避免。

    可以用一句话记忆整个过程:

    先通过慢开始快速探测网络能力,再通过拥塞避免谨慎增加发送速度;发现丢包后,通过快重传及时补发数据,并利用快恢复调整拥塞窗口。若发生 RTO 超时,则认为拥塞情况较严重,需要将窗口降至较小值重新开始。

    赞(0)
    未经允许不得转载:171主机测评 » 《TCP 拥塞控制详解(1):慢开始、拥塞避免、快重传与快恢复》
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址