拥塞控制

概念

拥塞控制是TCP避免网络拥塞的算法,是互联网上主要的一个拥塞控制措施。主要的目标是提高网络利用率降低丢包率保证网络资源对每条数据流的公平性*。它使用一套基于线增积减模式的多样化网络拥塞控制方法(包括慢启动和拥塞窗口等模式)来控制拥塞。在互联网上应用中有相当多的具体实现算法。

拥塞算法

TCP Tahoe/Reno

最初的实现,包括慢启动、拥塞避免两个部分。基于重传超时(retransmission timeout/RTO)和重复确认为条件判断是否发生了丢包。
两者的区别在于:
Tahoe算法下如果收到三次重复确认,就进入快重传立即重发丢失的数据包,同时将慢启动阈值设置为当前拥塞窗口的一半,将拥塞窗口设置为1MSS,进入慢启动状态;
Reno算法如果收到三次重复确认,就进入快重传,但不进入慢启动状态,而是直接将拥塞窗口减半,进入拥塞控制阶段,这称为“快恢复”。
而Tahoe和Reno算法在出现RTO时的措施一致,都是将拥塞窗口降为1个MSS,然后进入慢启动阶段。

TCP Vegas

TCP Vegas算法由 Lawrence Brakmo 和 Larry L. Peterson 在1994年提出,它和其他拥塞控制算法的不同之处在于Vegas算法并不急于丢包来判断是否发生了拥塞,而是通过数据包延迟来判断。Vegas通过RTT(roundtrip time)来决定增加或者减小拥塞窗口,它能够拥塞将要发生时就避免拥塞,而不是等到拥塞已经发生之后再减小发送速度,因此能够减小重传和超时的几率。Vegas算法与其他算法(比如Reno)共存时,会由于比其他算法更先降低发送速率而出现公平性问题。

TCP New Reno

TCP New Reno是对TCP Reno中快速恢复阶段的重传进行改善的一种改进算法,其定义于RFC 6582,覆盖了原有在RFC 3782和RFC 2582的旧定义。
在Reno的快恢复中,一旦出现3次重复确认,TCP发送方会重发数据包并设置定时器等待该重发数据包被确认。当重发的数据包被确认后,就立即退出快速恢复阶段,进入拥塞控制阶段。但如果一次拥塞中出现多个丢包,Reno会误以为发生了多次拥塞而重复减小拥塞窗口导致发送速率下降。
而在New Reno的快速恢复中,一旦出现3次重复确认,会记下出现重复确认时未确认的数据包的最大序列号,然后重发重复确认的数据包。如果有多个数据包丢失,则继续重发丢失的数据包,知道最大序列号的数据包被确认才推出快恢复阶段。
New Reno在低错误率时运行效率和“选择确认”(Selective ACKnowledgement,SACK)相当,在高错误率仍优于Reno。

TCP BIC 和 CUBIC

TCP BIC(Binary Increase Congestion control)旨在优化高速高延迟网络(即根据RFC 1072所定义的“长肥网络”(long fat network,LFN))的拥塞控制,其拥塞窗口算法使用二分搜索算法尝试找到能长时间保持拥塞窗口最大值的值。Linux内核在2.6.8至2.6.18使用该算法作为默认TCP拥塞算法。
CUBIC则是比BIC更温和和系统化的分支版本,其使用三次函数代替二分算法作为其拥塞窗口算法,并且使用函数拐点作为拥塞窗口的设置值。Linux内核在2.6.19后使用该算法作为默认TCP拥塞算法。

详细可参考:TCP拥塞控制

Reno算法介绍

主要包含四个部分

  • 慢热启动算法 – Slow Start
  • 拥塞避免算法 – Congestion Avoidance
  • 快速重传 - Fast Retransimit
  • 快速恢复算法 – Fast Recovery

概念术语

  • CWND Congestion Window,拥塞窗口(发送端定义调节发送端的量。跟接收窗口比,那个小取那个)
  • MSS maximum segment size, 指的是TCP传输层的最大传输单元(就是一个包的最大值)
  • RTT, round-trip time, 指的是从发送到接收这一个来回的行程所用的总体时间
慢热启动算法 – Slow Start
  1. 连接建好的开始先初始化cwnd(拥塞窗口)大小为N,表明可以传N个MSS大小的数据。
  2. 每当收到一个ACK,cwnd大小加一,呈线性上升。
  3. 每当过了一个往返延迟时间RTT(Round-Trip Time),cwnd大小直接翻倍,乘以2,呈指数增长。
  4. 还有一个慢启动门限ssthresh(slow start threshold),是一个上限,当cwnd >= ssthresh时,就会进入"拥塞避免算法 - Congestion Avoidance"
    拥塞控制_第1张图片
拥塞避免算法 – Congestion Avoidance
  1. 每收到一个ACK,调整cwnd 为 (cwnd + 1/cwnd) * MSS个字节每当收到一个ACK,cwnd大小加一,呈线性上升。
  2. 每经过一个RTT的时长,cwnd增加1个MSS大小。
    拥塞控制_第2张图片
拥塞状态时的超时重传

TCP是看不到网络的整体状况的,那么TCP认为网络拥塞的主要依据是它重传了报文段出现RTO超时,重传数据包。TCP就认为出现拥塞的可能性就很大,于是它反应非常“强烈”

  1. 由于发生丢包,将慢启动阈值ssthresh设置为当前cwnd的一半,即ssthresh = cwnd / 2.
  2. cwnd重置为1
  3. 进入慢启动过程
    拥塞控制_第3张图片
拥塞状态时的快速重传

在快速重传的时候,一般网络只是轻微拥堵,在进入拥塞避免后,cwnd恢复的比较慢。针对这个,“快速恢复”算法被添加进来,当收到3个冗余ACK时,TCP最后的步骤进入的不是拥塞避免阶段,而是快速恢复阶段。

  1. 调整门限ssthresh的值为当前cwnd值的1/2。
  2. 将cwnd值设置为新的ssthresh的值
  3. 重新进入拥塞避免阶段
    拥塞控制_第4张图片
快速恢复算法 – Fast Recovery

快速恢复的思想是“数据包守恒”原则,即带宽不变的情况下,在网络同一时刻能容纳数据包数量是恒定的。当“老”数据包离开了网络后,就能向网络中发送一个“新”的数据包。既然已经收到了3个冗余ACK,说明有三个数据分段已经到达了接收端,既然三个分段已经离开了网络,那么就是说可以在发送3个分段了。于是只要发送方收到一个冗余的ACK,于是cwnd加1个MSS。快速恢复步骤如下(在进入快速恢复前,cwnd 和 sshthresh已被更新为:sshthresh = cwnd /2,cwnd = sshthresh)

  1. cwnd设置为ssthresh的值加3,重传Duplicated ACKs指定的数据包
  2. 如果再收到 duplicated Acks,那么cwnd = cwnd +1
  3. 如果收到新的ACK,而非duplicated Ack,那么将cwnd重新设置为的sshthresh的值。然后进入拥塞避免状态。
    拥塞控制_第5张图片

细心的同学可能会发现快速恢复有个比较明显的缺陷就是:它依赖于3个冗余ACK,并假定很多情况下,3个冗余的ACK只代表丢失一个包。但是3个冗余ACK也很有可能是丢失了很多个包,快速恢复只是重传了一个包,然后其他丢失的包就只能等待到RTO超时了。超时会导致ssthresh减半,并且退出了Fast Recovery阶段,多个超时会导致TCP传输速率呈级数下降。出现这个问题的主要原因是过早退出了Fast Recovery阶段。为解决这个问题,提出了New Reno算法,该算法是在没有SACK的支持下改进Fast Recovery算法(SACK改变TCP的确认机制,把乱序等信息会全部告诉对方,SACK本身携带的信息就可以使得发送方有足够的信息来知道需要重传哪些包,而不需要重传哪些包),具体改进如下:

  1. 发送端收到3个冗余ACK后,重传冗余ACK指示可能丢失的那个包segment1,如果segment1的ACK通告接收端已经收到发送端的全部已经发出的数据的话,那么就是只丢失一个包,如果没有,那么就是有多个包丢失了。
  2. 发送端根据segment1的ACK判断出有多个包丢失,那么发送端继续重传窗口内未被ACK的第一个包,直到sliding window内发出去的包全被ACK了,才真正退出Fast Recovery阶段。

参考文档:《图解TCP/IP》
参考文档:https://www.zhoulujun.cn/html/theory/ComputerScienceTechnology/network/2015_0708_65.html
参考文档:https://blog.csdn.net/wdscq1234/article/details/52529994

你可能感兴趣的:(TCP/IP)