TCP/IP卷一:86---TCP拥塞控制之(慢启动、拥塞避免技术与经典算法(Tahoe、Reno以及快速恢复算法))

  • 现在我们讨论TCP的两个核心算法:慢启动和拥塞避免
    • 这两个算法是基于包守恒和ACK时钟原理,最早在Jacobson [J88]的经典论文里被正式提出。几年后,Jacobson对拥塞避免算法提出了改进[J90]
    • 这两个算法不是同时运行的——在任一给定时刻,TCP只运行 一个算法,但两者可以相互切换
    • 下面我们将详细讨论这两个算法,包括如何使用以及对算法的改进。每个TCP连接都能独立运行这两个算法

一、慢启动

  • 何时使用慢启动:
    • 当一个新的TCP连接建立或检测到由重传超时(RTO)导致的丢包时,需要执行慢启动
    • TCP发送端长时间处于空闲状态也可能调用慢启动算法
  • 慢启动的目的是:
    • 使TCP在用拥塞避免探寻更多可用带宽之前得到cwnd值,以及帮助TCP建立ACK时钟
    • 通常,TCP在建立新连接时执行慢启动,直至有丢包时,执行拥塞避免算法(见下面的拥塞避免)进入稳定状态
    • 下文引自[RFC5681]:

初始窗口(IW)

  • TCP以发送一定数目的数据段开始慢启动(在SYN交换之后),称为初始窗口(Initial Window,IW)
  • IW的值初始设为一个SMSS(发送方的最大段大小),但在[RFC5681]中设为一个稍大的值,计算公式如下:

  • 上述IW的计算方式可能使得初始窗口为几个数据包大小(如3个或4个)
  • 为简单起见,我们只讨论IW= 1 SMSS的情况。TCP连接初始的cwnd= 1 SMSS,意味着初始可用窗口W也为1 SMSS。注意到大部分情况下,SMSS为接收方的MSS(最大段大小)和路径MTU(最大传输单元)两者中较小值

cwnd的初始化(线性增长)

  • 因此,在接收到一个数据段的ACK后,通常cwnd值会增加到2,接着会发送两个数据段。如果成功收到相应的新的ACK,cwnd会由2变4,由4变8,以此类推......
  • 一般情况下,假设没有丢包且每个数据包都有相应ACK,在k轮后W的值为W=2^{k},即k= log2W,需要k个RTT时间操作窗口才能达到W大小
  • 这种增长看似很快(以指数函数增长),但若与一 开始就允许以最大可用速率(即接收方通知窗口大小)发送相比,仍显缓慢。 (W不会超过awnd)

慢启动阀值

  • 如果假设某个TCP连接中接收方的通知窗口非常大(比如说,无穷大),这时cwnd就是影响发送速率的主要因素(设发送方有较大发送需求)
  • 如前所述,cwnd会随着RTT呈指数增长。因此,最终cwnd(W也如此)会增至很大,大量数据包的发送将导致网络瘫痪(TCP吞吐量与,W/RTT成正比)
  • 当发生上述情况时,cwnd将大幅度减小(减至原值一半)。这是TCP由慢启动阶段至拥塞避免阶段的转折点,与cwnd和慢启动阂值(sIow start threshold,ssthresh)相关

慢启动图示

  • 图左描述了慢启动操作:数值部分以RTT为单位。假设该连接首先发送一个包(图上部),返回一个ACK,接着在第二个RTT时间里发送两个包,会接收到两个ACK。TCP发送方每接收一个ACK就会执行一次cwnd的增长操作,以此类推
  • 右图描述了cwnd随时间增长的指数函数:图中另一条曲线显示了每两个数据包收到一个ACK时cwnd的增长情况。通常在ACK延时情况下会采用这种方式,这时的cwnd仍以指数增长,只是增幅不是很大。正因ACK可能会延时到达,所以一些TCP操作只在慢启动阶段完成后才返回ACK。Linux系统中,这被称为快速确认( “快速ACK模式”),从内核版本2.4.4开始,快速确认 一直是基本TCP/IP协议栈的一部分

TCP/IP卷一:86---TCP拥塞控制之(慢启动、拥塞避免技术与经典算法(Tahoe、Reno以及快速恢复算法))_第1张图片

二、拥塞避免

为什么设计拥塞避免

  • 如上所述,在连接建立之初以及由超时判定丢包发生的情况下,需要执行慢启动操作。在慢启动阶段,cwnd会快速增长,帮助确立一个慢启动阈值。一旦达到阈值,就意味着可能有更多可用的传输资源。如果立即全部占用这些资源,将会使共享路由器队列的其他连接出现严重的丢包和重传情况,从而导致整个网络性能不稳定
  • 为了得到更多的传输资源而不致影响其他连接传输,TCP实现了拥塞避免算法

算法分析

  • 一旦确立慢启动阈值,TCP进入拥塞避免阶段,cwnd每次的增长值近似于成功传输的数据段大小。 这种随时间线性增长方式与慢启动的指数增长相比缓慢许多
  • 更准确地说,每接收一个新的 ACK,cwnd会做以下更新:

  • 分析上时,假设字节分k段发送没在接收到第一个ACK后,cwnd的值增长了1/K倍:

图示分析

  • 随着每个新的ACK到达,cwnd会有相应的小幅增长(取决于上式中的居值),整体增长率呈现轻微的次线性。尽管如此,我们通常认为拥塞避免阶段的窗口随时间线性增长(见下图),而慢启动阶段呈指数增长(见慢启动中的图片)。这个函数也称为“累加增长”,因为每成功接收到相应数据,cwnd就会增加一个特定值(这里大约是一个包大小)

TCP/IP卷一:86---TCP拥塞控制之(慢启动、拥塞避免技术与经典算法(Tahoe、Reno以及快速恢复算法))_第2张图片

  • 左图描述了拥塞避免操作。数值部分仍是以RTT为单位。假设连接发送了4个数据包(图上方),返回了4个ACK,cwnd可以有相应的增长。在第2个RTT阶段,增长可达到整数值,使得cwnd增加一个SMSS,这样可以继续发送一个新的数据包
  • 右图描绘了cwnd随时间近似呈线性增长。另一曲线模拟ACK延时,显示了每两个数据包收到一个ACK时cwnd的增长情况。这时的cwnd仍近似呈线性增长,只是增幅不是很大
  • 拥塞避免算法假设由比特错误导致包丢失的概率很小(远小于1%),因此有丢包发生就表明从源端到目的端必有某处出现了拥塞如果假设不成立:
    • 比如在无线网络中,那么即使没有拥塞TCP传输也会变慢
    • 另外,cwnd的增大可能会经历多个RTT,这就需要有充裕的网络资源,并得到高效利用
    • 这些问题还有很大的研究空间,以后我们将会讨论其中一些方法

三、慢启动和拥塞避免的选择

  • 在通常操作中,某个TCP连接总是选择运行慢启动和拥塞避免中的一个,不会出现两者同时进行的情况。现在我们考虑,在任一给定时刻如何决定选用哪种算法。我们已经知道,慢启动是在连接建立之初以及超时发生时执行的。那么决定使用慢启动还是拥塞避免的关键因素是什么呢?

慢启动阈值(ssthresh)

  • 前面我们已经提到过慢启动阈值。这个值和cwnd的关系是决定采用慢启动还是拥塞避免的界线:
    • 当cwnd < ssthresh,使用慢启动算法
    • 当cwnd > ssthresh,需要执行拥塞避免
    • 而当两者相等时,任何一种算法都可以使用
  • 由上面描述可以得出,慢启动和拥塞避免之间最大的区别在于:当新的ACK到达时,cwnd怎样增长
  • 有趣的是,慢启动阈值不是固定的,而是随时间改变的。它的主要目的是,在没有丢包发生的情况下,记住上一次“最好的”操作窗口估计值。换言之,它记录TCP最优窗口估计值的下界
  • 慢启动阈值的初始值可任意设定(如awnd或更大),这会使得TCP总是以慢启动状态开始传输
  • 当有重传情况发生,无论是超时重传还是快速重传,ssthresh会按下式改变:

  • 我们已经知道,如果出现重传情况
    • TCP会认为操作窗口超出了网络传输能力范围。这时会将慢启动阈值(ssthresh)减小至当前窗口大小的一半(但不小于2*SMSS),从而减小最优窗口估计值
    • 这样通常会导致ssthresh减小,但也有可能会使之增大。分析TCP拥塞避免的操作流程,如果整个窗口的数据都成功传输,那么cwnd值可以近似增大1 SMSS。因此,若cwnd在一段时间范围内已经增大,将ssthresh设为整个窗口大小的一半可能使其增大。这种情况发生在当TCP探测到更多可用带宽时
    • 在慢启动和拥塞避免结合的情况下,ssthresh和cwnd的相互作用使得TCP拥塞处理行为显现其独有特性
  • 下面我们探讨将两者结合的完整的算法

四、Tahoe、Reno以及快速恢复算法

  • 至此讨论的慢启动和拥塞避免算法,组成了TCP拥塞控制算法的第一部分。它们于20世纪80年代末期在加州大学伯克利分校的4.2版本的UNIx系统中被提出,称为伯克利软件版本,或BSD UNIX。至此开始了以美国城市名命名各个TCP版本的习惯,尤其是那些赌博 合法的城市

Tahoe

  • 4.2版本的BSD(称为Tahoe)包含了一个TCP版本,它在连接之初处于慢启动阶段,若检测到丢包,不论由于超时还是快速重传,都会重新进入慢启动状态。有丢包情况发生时,Tahoe简单地将cwnd减为初始值(当时设为1 SMSS)以达到慢启动目的,直至cwnd增长为ssthresh
  • 这种方法带来的一个问题是,对于有较大BDP的链路来说,会使得带宽利用率低下。因为TCP发送方经重新慢启动,回归到的还是未丢包状态(cwnd启动初始值设置过小)。
  • 为解决这一问题,针对不同的丢包情况,重新考虑是否需要重回慢启动状态。若是由重复ACK引起的丢包(引发快速重传),cwnd值将被设为上一个ssthresh,而非先前的1 SMSS。(在大多数TCP版本中,超时仍是引发慢启动的主要原因)这种方法使得TCP无须重新慢启动,而只要把传输速率减半即可

Reno

  • 进一步讨论较大BDP链路的情况,结合之前提到的包守恒原理,我们可以得出结论,只要接收到ACK回复(包括重传ACK),就有可能传输新的数据包
  • BSD UNIX的4.3 BSD Reno版中的快速恢复机制就是基于上述结论。在恢复阶段,每收到一个ACK,cwnd就能(临时)增长1 SMSS,相应地就意味着能发送一个新的数据包。因此拥塞窗口在一段时间内会急速增长,直到接收一个好的ACK。不重复的(“好的”) ACK表明TCP结束恢复阶段,拥塞已减少到之前状态
  • TCP Reno算法得到了广泛应用,并成为“标准TCP”的基础

五、标准TCP

  • 尽管究竟哪些构成了“标准” TCP还存在争议,但我们讨论过的上述算法毋庸置疑都属于标准TCP。慢启动和拥塞避免算法通常结合使用,[RFC5681]给出了其基本方法。这个规范并不要求严格使用这些精确算法,TCP实现过程仅利用其核心思想。
  • 总结[RFC5681]中的结合算法,在TCP连接建立之初首先是慢启动阶段(cwnd = IW),ssthresh通常取一较大值(至少为awnd)。当接收到一个好的ACK (表明新的数据传输成功),cwnd会相应更新:

  • 当收到三次重复ACK(或其他表明需要快速重传的信号)时,会执行以下行为:
    • 1.ssthresh更新为大于等式(上面慢启动阈值中的等式)中的值
    • 2.启用快速重传算法,将cwnd设为(ssthresh + 3*SMSS)
    • 3.每接收一个重复ACK,cwnd值暂时增加1 SMSS
    • 4.当接收到一个好的ACK,将cwnd重设为ssthresh
  • 以上第2步和第3步构成了快速恢复:
    • 步骤2设置cwnd大小,首先cwnd通常会被减为之前值的一半。然后,考虑到每接收一个重复ACk,就意味着相应的数据包已成功传输(因此新的数据包就有发送机会),cwnd值会相应地暂时增大。这一步也可能出现cwnd加速递减的情况,因为通常cwnd会乘以某个值(这里取0.5)来形成新的cwnd
    • 步骤3维持cwnd的增大过程,使得发送方可以继续发送新的数据包(在不超过awnd的情况下)
  • 步骤4假设TCP已完成恢复阶段,所以cwnd的临时膨胀也消除了(有时称这一步为“收缩”)
  • 以下两种情况总会执行慢启动:新连接的建立以及出现重传超时。当发送方长时间处于空闲状态,或者有理由怀疑cwnd不能精确反映网络当前拥塞状态(参见下一篇文章中的“拥塞窗口校验”)时,也可能引发慢启动。在这种情况下,cwnd的初始值将被设为重启窗口(RW)。在文献[RFC5681] 中,推荐RW值为RW=min(IW,cwnd)。其他情况下,慢启动中cwnd初始设为IW

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