TCP 拥塞控制算法

TCP 拥塞检测

  对于 TCP 发送方来说,没有一个精确的方法取知晓中间路由器的状态,换言之,没有一个明确的信号告知拥塞状况已发生.
  在 TCP 中,丢包被用作判断拥塞发生与否的指标,用来衡量是否实施相应的响应措施(即以某种方式减缓发送).

减缓 TCP 发送

  根据接受方剩余缓存空间大小,在 TCP 头部设置了通知窗口大小字段(awnd),该数值是 TCP 发送方调节发送速率的依据.
  基于网络传输能力的估计,可以在发送端引入一个窗口控制变量,确保发送窗口大小不超过接受端接受能力和网络传输能力,即 TCP 发送端的发送速率等于接受速率和传输速率中较小值.

  反映网络传输能力的变量称为拥塞窗口(congestion window),记作 cwnd.因此,发送端实际窗口 W 就是接受端通知窗口 awnd 和拥塞窗口 cwnd 的较小值.

  根据上等式,TCP 发送端发送的数据中,还没有收到 ACK 回复的数据量不能多于 W.这种已经发出但还未经确认的数据量被称为在外数据值(flight size),它总是小于等于 W.

两个核心算法

  慢启动和拥塞避免算法,这两个算法是基于包守恒和 ACK 时钟原理.
  这两个算法不是同时运行的, TCP 只运行一个算法,但两个可以相互切换.

慢启动

  当一个新的 TCP 连接建立或检测到由重传超时(RTO)引起的丢包时,需要执行慢启动,TCP 发送端长时间处于空闲状态也可能调用慢启动算法.
  慢启动的目的是,使 TCP 在用拥塞避免来探寻更多可用带宽之前得到 cwnd 值,以及帮助 TCP 建立 ACK 时钟.

  在传输初始阶段,由于未知网络传输能力,需要缓慢探测可用传输资源,防止短时间内大量数据注入导致拥塞.慢启动算法正是针对这一问题而设计.在数据传输之初或者重传计时器检测到丢包后,需要执行慢启动.

  TCP 以一定数目的数据段开始慢启动(在 SYN 交换后),称为初始窗口(Initial Window, IW).IW 的初始值设为一个 SMSS(发送方的最大段)大小,关于 IW RFC5681 定义了一个计算公式,这里不赘述.
  只讨论 的情况.TCP 连接初始的 , 意味着初始可用的窗口 W 也为 1 SMSS, 大部分情况下,SMSS 为接收方的 MSS(最大段大小)和路径 MTU(最大传输单元)两者中较小值.
  假设没有出现丢包情况且每个数据包都有相应的 ACK, 每接受到一个好的 ACK 相应,慢启动算法会以 来增加 cwnd.
  这里的 N 是指在未经确认的传输数据中能用过这一 好的 ACK 确认的字节数.所谓的好的 ACK 是指新接受的 ACK 号大于之前收到的 ACK.
  因此,在接收到一个数据段的 ACK 后,通常 cwnd 会增加到 2, 接着会发送两个数据段.如果收到相应的新的 ACK, cwnd 会由 2 变 4,由 4 变 8,依次类推.一般情况下,假设没有丢包且每个数据包都有相应的 ACK, 在 k 轮后 W 的值为 , 即 , (W 不会超过 awnd).
  假设当 awnd 非常大时,cwnd 就会变成影响发送速率的主要因素,由上可知,cwnd 会随着 RTT 指数增长,最终 cwnd (W) 会增至很大,大量数据包的发送将导致网络瘫痪(TCP 吞吐量和 W / RTT 成正比),丢包现象是网络拥塞的征兆,当发生丢包时,cwnd 将会大幅度减小(原值一半).这是 TCP 由慢启动阶段至拥塞避免阶段的转折点, 与 cwnd 和慢启动阈值(slow start threhold, ssthresh).

拥塞避免

  在慢启动阶段,cwnd 会快速增长,帮助确立一个慢启动阈值.一旦确立慢启动阈值,TCP 会进入慢启动阶段,cwnd 每次的增长值近似与成功传输的数据段大小,这种增长方式是随时间线性增长.
  每接受一个新的 ACK, cwnd 会做如下更新

  假设 字节分 k 段发送,在接收到一个 ACK 后,cwnd 的值增长了 倍.
  随着每个 ACK 的到达,cwnd 会有相应的小幅增长(取决于上式中的 k 值),这个函数也称为累加增长,每成功接受到相应数据,cwnd 都会增加一个特定值(大约是一个包的大小)

慢启动和拥塞避免的选择

  慢启动是在连接建立之初以及超时发生时执行的,而切换至拥塞模式的界限是由慢启动阈值(ssthresh)和 cwnd 的关系决定的.
  当 时,使用慢启动算法.
  当 时,使用拥塞避免算法.
  当两者相等时,任何一种算法都可以使用.

  慢启动阈值不是固定的,而是随时间改变的.
  它的主要目的是,在没有丢包发生的情况下,记住上一次最好的操作窗口估计值.或者说,它估计 TCP 最优窗口的下界.

  慢启动阈值的初始值可任意设定,这会使得 TCP 总是以慢启动状态开始.当有重传状态发生,无论是超时重传还是快速重传,ssthresh 会按下式改变

  其中 flight 是在外数据值,即已经发送还没有超时没有收到 ACK 的数据包