TCP/IP 笔记 - TCP拥塞控制

时间:2020-11-29 20:25:59

拥塞控制是TCP通信的每一方需要执行的一系列行为,这些行为有特定算法规定,用于防止网络因为大规模的通信负载而瘫痪。其基本方法是当有理由认为网络即将进入拥塞状态(或已由于拥塞而出现路由丢包情况)时减缓TCP传输。TCP拥塞控制的关键点自傲与怎样准确的判断何时需要减缓且如何减缓TCP传输,以及何时恢复其原有速度。

注意: M(_x) 表示M的下标是x ,m(^k) 表示m的K次方。

减缓TCP发送

第15章提到,根据接收方剩余缓存空间大小,在TCP头部设置通告窗口大小字段,该数值是TCP发送方调节发送速率的依据,当接收速率和网络传输速率过慢时,便需要降低发送速率。为实现上述操作,基于对网络传输能力的估计,可以在发送端引入一个窗口控制变量,确保发送窗口大小不超过接收端接收能力和网络传输能力,即TCP发送端的发送速率为两者取较小值。

反映网络传输能力的变量称为拥塞窗口,记作cwnd。因此发送端实际可用窗口W就是接收端窗口awnd和拥塞窗口cwnd的较小值:

    W = min(cwnd,awnd)

然而实际情况更显复杂,因为网络和接收端情况会随时间变化,awnd和cwnd值也就会随之变化。另外,由于缺少显示拥塞的明确信号,TCP发送端无法直接获取cwnd的准确值。因此,W、cwnd、awnd的值都需要根据经验设定并需动态调节。W的值不能过大或过小,我们希望其接近带宽延迟积(BDP),也称为最佳窗口大小。W反映网络中可存储的待发数据量大小,其计算值等于RTT与链路中最小通行速率的乘积。

TCP拥塞控制的一些算法

当一个新的TCP连接之初,还无法获知可用的传输资源,所以cwnd的初始值也无法确定(除第14章提到的目的度量达到缓存信息的情况外)。而awnd则可以通过与接收端完成一个数据包交换即可确定。所以,想要获取cwnd最佳值的唯一方法是以越来越快的速率不断发送数据,知道出现数据丢包(或网络拥塞)为止。由于考虑到不影响网络传输的性能,通常采用特定算法来避免过快的传输启动,传输会以慢速启动发送,直至稳定传输后才会运行相应的其他算法。

TCP拥塞控制操作是基于数据包守恒原理运行的:

TCP/IP 笔记 - TCP拥塞控制

由于传输能力有限,数据包(Pb)会适时地"伸展"。接收方以一定间隔(Pt)接收到数据包后,会陆续(以Ar为间隔)生成相应的ACK,以一定的发送间隔(Ab)返回给发送方。当ACK陆续(以As为间隔)到达发送端时,其达到提供了一个信号或者说"ACK时钟",表明发送端可以继续发送数据。在稳定传输状态下,整个系统可"自同步"控制。

慢启动

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

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

    IW = 2*(SMSS)且小于等于2个数据段(当SMSS > 2190字节)
IW = 3*(SMSS)且小于等于3个数据段(当 2190 ≥ SMSS > 1095字节)
IW = 4*(SMSS)且小于等于4个数据段(其他)

假设没有出现丢包情况且每个数据包都有相应的ACK,第一个数据段的ACK到达说明可发送一个新的数据段。每接收到一个"正确的ACK"(即没出现丢包情况正确返回的数据接收响应ACK),慢启动算法会以min(N,SMSS)来增加cwnd值,N指的是在未经确认的传输数据中能通过"正确的ACK"确认的字节数。

为简单计算,以TCP连接初始的cwnd = 1 SMSS为例,接收到一个数据段的ACK后,cwnd值增加到2,接着发送两个数据段,如果成功接收并返回相应的ACK,cwnd由2变4,4变8,以此类推。在k轮后,W值为 W = 2的k次方,即 k = log2W,需要k个RTT时间操作窗口才能达到W大小。

有一种情况,假设某个TCP连接中接收方的通知窗口非常大,这时cwnd就是影响发送速率的主要因素。如前所述,cwnd会随着RTT呈指数增长,最终cwnd会增至很大,大量数据包的发送回导致网络瘫痪。当发生这种情况时,cwnd将大幅度减小(减至原来的一半)。这是TCP由慢启动阶段至拥塞避免阶段的转折点,与cwnd和慢启动阈值(ssthresh)相关。

经典慢启动操作如图:

TCP/IP 笔记 - TCP拥塞控制

没有ACK延时情况下,每接收到一个正确的ACK就意味着发送方可以发送两个新的数据包(左)。这会使得发送方窗口随时间呈指数增长(右,上方曲线)。当发生ACK延时,如每隔一个数据包生成一个ACK,cwnd仍以指数增长,但增幅较小(右,下方曲线)。

拥塞避免

慢启动一旦达到阈值,便是意味着连接可以进入"下个阶段"了。"下个阶段"指的是为了得到更多的传输资源而不致影响其他连接传输的数据传输,这个阶段TCP实现拥塞避免算法。

拥塞避免阶段,cwnd每次的增长值近似于成功传输的数据段大小,这种随时间线性增长方式与慢启动的指数增长相比缓慢得多。每接收一个新的ACK,cwnd会做一下的更新:

    cwnd(_k+1) = cwnd(_t) + SMSS * SMSS/cwnd(_t)

分析上式,假设cwnd(_0) = k * SMSS 字节分为k段发送,在接收到第一个ACK后,cwnd的值增长了1/k倍:

    cwnd(_1) = cwnd(_0) + SMSS * SMSS/cwnd(_0) = k * SMSS + SMSS * (SMSS/(k * SMSS)) = k * SMSS + (1/k) * SMSS = (k + (1/k)) * SMSS = cwnd(_0) + (1/k) * SMSS

随着每个新的ACK到达,cwnd会有相应的小幅增长(取决于上式中的k值),整体增长率呈现轻微的次线性。

TCP/IP 笔记 - TCP拥塞控制

若没有ACK延时发生,每接收一个正确的ACK,就意味着发送方可继续发送1/W个新的数据包。发送窗口随时间近似呈线性增长(右,上方曲线)。当有ACK延时,如每隔一个数据包生成一个ACK,cwnd仍近似呈线性增长,只是增幅较小(右,下方曲线)。

慢启动和拥塞避免的选择及应用

在通常操作中,某个TCP连接总是选择运行慢启动和拥塞避免中的一个,不会出现两者同时进行的情况,而决定使用慢启动还是拥塞避免的则是正确提到的慢启动阈值:

    当 cwnd < ssthresh 时,使用慢启动;
当 cwnd > ssthresh 时,执行拥塞避免;
当 cwnd = ssthresh 时,两者皆可。

有趣的是,慢启动阈值居然是动态得到的值。慢启动阈值的初始值可任意设定,这会使得TCP总是以慢启动状态开始传输。当有重传情况发生,ssthresh会按下式改变:

    ssthresh = max(在外数据值/2, 2 * SMSS)  (ssthresh-公式)

注意,在微软最近("下一代")TCP/IP协议中,上述等式变为 ssthresh = max(min(cwnd,awnd)/2, 2 * SMSS)[NB08]。

慢启动和拥塞避免组成了TCP拥塞控制算法的部分:

  Tahoe(4.2版本的BSD,伯克利软件版本)包含了一个TCP版本,它在连接之初处于慢启动阶段,若检测到丢包,不论由于超时还是快速重传,都会重新进入慢启动状态。有丢包情况发生时,Tahoe简单的将cwnd减为初始值以达到慢启动目的,直至cwnd增长为ssthresh。这种方法对于较大BDP的链路会使得带宽利用率低下,因为TCP发送方经重新慢启动,回归到的还是未丢包状态。

  Reno(4.3版本的BSD)中的快速恢复机制就是为解决Tohoe的带宽利用率低下问题而提出的。针对不同的丢包情况,重新考虑是否需要重回慢启动状态。若是由重复ACK引起的丢包(会引发快速重传),cwnd值将被设为上一个ssthresh(即减半),而非初始值。该算法得到了广泛应用并成为"标准TCP"的基础。

标准TCP及对其算法的改进

"标准"TCP的构成依然存在争议,但上述算法都属于标准TCP。[RFC5681]描述了TCP规范并不要求严格使用上述精确算法,TCP实现过程仅利用其核心思想。总结[RFC5681]中的结合算法,在TCP连接建立之初,首先是慢启动阶段(cwnd = IW),ssthresh通常取一较大值(至少为awnd)。当接收到一个正确的ACK时,cwnd会相应更新:

    cwnd += SMSS (若 cwnd < ssthresh) 慢启动
cwnd += SMSS * SMSS/cwnd (若 cwnd > ssthresh) 拥塞避免

当收到三次重复ACK时,会执行以下行为:

  1. ssthresh 更新为大于等式(ssthresh-公式)中的值。

  2. 启用快速重传算法,将cwnd设为(ssthresh + 3 * SMSS)。

  3. 每接收一个重复ACK,cwnd值暂时增加 1 SMSS。

  4. 当接收到一个正确的ACK,将cwnd重设为ssthresh。

步骤2和3构成了快速恢复。步骤2设置cwnd大小,首先cwnd通常会被减为之前值的一半,考虑到每接收一个重复ACK,就意味着相应的数据包已成功传输,cwnd值会相应的暂时增大。步骤3维持cwnd的增大过程,使得发送方可以继续发送新的数据包(在不超过awnd的情况下)。步骤4假设TCP已完成恢复阶段,所以对cwnd的临时膨胀进行消除。

标准TCP算法在传输控制领域做出了重大贡献,尤其针对网络拥塞崩溃这一难题取得了显著效果。然而,仍然可以找到值得改进的地方。考虑到TCP的普遍使用性,越来越多的研究致力于使TCP在更广泛的环境里更好地工作,下面就是一些改进。

NewReno是Reno算法的改进:Reno中的快速恢复机制存在问题,当一个传输窗口出现多个数据包丢失时,一旦其中一个包重传成功,发送方就会收到一个正确的ACK,这样快速恢复阶段中cwnd窗口的暂时膨胀就会停止,而事实上丢失的其他数据包可能并未完成重传。NewReno对快速恢复做了改进,它记录了上一个数据传输窗口的最高序列号,仅当接收到序列号不小于恢复点的ACK,才停止快速恢复阶段。

采用选择确认机制的TCP拥塞控制:在TCP引入SACK与选择性重复之后,发送方能够更好地确定发送哪个数据段来填补接收方的空缺。为了填补接收数据的空缺,发送方通常只发送丢失的数据段,直至完成所有重传。SACK TCP强调拥塞管理和选择重传机制的分离(为避免可能出现的由于触发重传而导致短时间内大量数据被注入网络),传统TCP则将两者结合。一种实现分离方法是除了维护窗口,TCP还负责记录注入网络的数据量。[RFC3517]称其为管道(pipe)变量,以字节为单位,是对外在数据的估计值,记录传输和重传情况。假设awnd值比较大,只要不等式 cwnd - pipe ≥ SMSS成立,在任何时候SACK TCP均可发送数据。这里cwnd仍被用来限定可传输至网络中的数据量,但除了窗口本身,网络中数据量的估计值也被记录了。

转发确认(FACK)和速率减半:对基于Reno(包括NewReno)的TCP版本中,当快速重传结束后cwnd值减小,发送端在前一半的RTT时间内处于等待状态,在后一半RTT才能发送新数据。为避免前半RTT时间的等待空闲,[MM96]提出了转发确认策略(FACK)。

转发确认策略(FACK)包含两部分算法:过度衰减和缓慢衰减。最终在Hoe的工作基础上[H96]形成统一的算法,称为速率减半。为控制算法近可能有效的运行,进一步添加了界定参数,完整的算法称为带界定参数的速率减半(RHBP)算法[PSCRH]。RHBP的基本操作是在一个RTT时间内,每接收2个重复ACK,TCP发送方可发送一个新数据包。为了记录较为精确的在外数据估计值,RHBP利用SACK信息决定FACK策略:已知的最大序列号的数据到达接收方时,在外数据值加1,FACK给出的在外数据估计值不包括重传。RHBP中区分了调整间隔(cwnd的修正阶段)和恢复间隔(数据重传阶段),一旦出现丢包或其他拥塞信号就立即进入调整间隔。调整间隔结束后cwnd的最终值为:至检测时间为止,网络中已正确传输的窗口数据量的一半。

RHBP要求发送方传输数据需要满足下式:

    (SND.NXT - fack + retran_data + len) < cwnd

上面的等式得到了包括重传的在外数据值,确保当继续发送一个len长度的新数据,也不会超过cwnd。假设在FACK之前的数据已经不在网络中(如丢失或被接收),这样cwnd就能很好地控制SACK发送方的发送。然而由于SACK的选择确认特性,可能导致数据包的传输次序过度重排。

书中也提到 "在接收窗口限制TCP连接的情况下,速率减半方法收效甚微[MM05]" 。

限制传输:[RFC3042]描述了其对TCP做出了微小改进,采用限制传输策略,TCP发送方每接收两个连续的重复ACK,就能发送一个新数据包。这就使得网络中的数据包维持一定数量,足以触发快速重传,TCP因此也可以避免长时间等待RTO而导致吞吐量性能下降。

拥塞窗口校验:在发送操作持续一段时间后,cwnd值可能会增至一个较大值,若此时发送端需要暂停发送且暂定的时间足够长,则之前的cwnd可能无法准确反映路径中的拥塞状况。[RFC2861]提出了一种拥塞窗口校验机制(CWV)。

CWV算法如下:当需要发送新数据时,首先看距离上次发送操作是否超过一个RTO。如果超过,则更新ssthresh值,设为max(ssthresh,(3/4) * cwnd),每经一个空闲RTT时间,cwnd值就减半,但不小于 1 SMSS。

对于应用受限阶段(非空闲阶段),执行相似的操作:已使用的窗口大小记为W_used,更新ssthresh值,设为max(ssthresh,(3/4) * cwnd),cwnd设为cwnd和W_used的平均值。

伪RTO处理-Eifel算法

第15章中已经提到,若TCP出现突发的延时,即使没有出现丢包,也可能造成重传超时的假象。当出现重传超时,TCP会调整ssthresh并将cwnd置为IW,从而进入慢启动状态。假如没有出现实际丢包,在RTO之后到达的ACK会使得cwnd快速增大,但在cwnd和ssthresh值重新稳定前,仍然会有不必要的重传,浪费传输资源。

针对上述问题,在14章提出了一些方法:DSACK、Eifel、F-RTO。其中任一探测方法只要结合相关响应算法,就能"还原"TCP对拥塞控制变量的操作。这里主要介绍Eifel响应算法。

Eifel响应算法用于处理重传计时器以及重传计时器超时后的拥塞控制操作。在首次发生超时重传时,Eifel算法开始执行。若认为出现伪重传情况,会撤销对ssthresh值的修改。若因超时重传而需改变ssthresh值,在修改前需要记录一个特殊变量:pipe_prev。

    pipe_prev = min(在外数据值,ssthresh)

然后需要运行一个检测算法(即之前提到的检测方法中的某个)来判断RTO是否真实,如果出现伪重传,则当到达一个ACK时,执行以下步骤:

  1. 若接收的是包含ECN-Echo标志位的正确的ACK,停止操作;

  2. cwnd = 在外数据值 + min(bytes_acked, IW);

  3. ssthresh = pipe_prev。

过程整理:

  在改变ssthresh值之前需要先保存pipe_prev变量,用于保存ssthresh的记录值,以便在步骤3重设ssthresh。

  步骤1针对待ECN标志位的ACK的情况,这种情况下撤销ssthresh修改会引入不安全因素,所以算法终止。

  步骤2将cwnd设置为一定值,允许不超过IW的新数据进入传输通道,因为即使在未知链路拥塞与否的状况下,发送IW的新数据也被认为是安全的。

  步骤3在真正的RTO发生前重置ssthresh,至此撤销操作完成。

TCP友好性

TCP作为最主要的网络传输协议,在传输路径中经常会出现几个TCP链接共享一个或多个路由的情况,然而它们并非均匀的共享带宽资源,而是根据其他连接动态地调节分配。为避免多个TCP连接对传输资源的恶性竞争,提出了一种基于计算公式的速率控制方法,限制特定环境下TCP连接对带宽资源的使用,该方法被称为TCP友好速率控制(TFRC),它基于连接参数和环境变量实现速率限制。

TFRC使用如下公式来决定发送率:

TCP/IP 笔记 - TCP拥塞控制
                (TEFC-公式1)

这里的X指吞吐率限制(字节/秒),s为包大小(字节,包含头部),R是RTT(秒),p为丢包率[0,0.1],t(_RTO)为重传超时(秒),b指一个ACK能确认的最大包个数。建议t(_RTO)设为4R,b设为1。

在拥塞避免阶段,如何根据接收的无重复ACK来调整窗口大小?使用拥塞避免算法时,每接收一个正确的ACK,cwnd就会增加1/cwnd,而每当出现一次丢包,cwnd就会减半,这被称为和氏增加/积式减少(AIMD)拥塞控制。通过将1/cwnd和1/2替换为a和b,得到AIMD等式:

    cwnd(_t+1) = cwnd(_t) + a/cwnd(_t)
cwnd(_t+1) = cwnd(_t) - b/cwnd(_t)

根据[FHPW00]给出的结果,上述等式得出的发送率为(以包个数/RTT为单位):

TCP/IP 笔记 - TCP拥塞控制

(TEFC-公式2)

对于传统TCP,a = 1,b = 0.5,简化得出T = 1.2/√(根号)p。

高速环境下的TCP

考虑一下,如果BDP较大的高速网络中,使用窗口增加的算法(特别是拥塞避免算法)需要很长一段时间才能使窗口增至传输链路饱和,也就是说,即使没有发生拥塞,TCP也不能很好的利用高速网络。为了弥补这个不足,高速TCP(HSTCP)技术[RFC3742]指出,当拥塞窗口大于一个基础值Low_Window时(Low_Window设置为38个MSS),应当调整标准TCP的处理方式。

[RFC3742]描述了如何修改慢启动阶段,使其在高速环境下得到运行中的拥塞窗口值。它被称为受限的慢启动,即减慢速度的慢启动。其中引入一个新的参数称为max_ssthresh,这个值表示ssthresh的最大值,而是cwnd的一个阈值:

  如果cwnd <= max_ssthresh,则慢启动阶段与传统TCP相同,

  如果max_ssthresh < cwnd <= ssthresh,那么cwnd在每个RTT中最大只能增长(max_ssthresh/2)个SMSS。

具体如下:

    if( cwnd <= max_ssthresh ){
cwnd = cwnd + SMSS
}else{
K = int(cwnd / (0.5 * max_ssthresh))
cwnd = cwnd + int((1/K) * SMSS)
}

建议max_ssthresh的初始值为100个包,或者100 * SMSS个字节。

对与HSTCP而言,在多个具有不同RTT的连接竞争带宽时,不会直接控制这些竞争行为(称为"RTT公平性")。但为建立可扩展的TCP及解决RTT公平性问题,也提出了一些算法。

BIC-TCP算法:该算法使用了两种算法来修改标准TCP发送端,二分搜索增大和加法增大。

  二分搜索增大算法操作过程如下:当前最小窗口是最近一次在一个完整RTT中没有出现丢包的窗口大小,最大窗口是最近一次出现丢包时的窗口大小。预期窗口位于这两个值之间,BIC-TCP则使用二分搜索选择中点作为试验窗口,依次递归。如果这个点依然会发生丢包,那么将它设置为最大窗口,然后继续重复二分搜索试验。反之依然。直到最大窗口和最小窗口的差小于一个预先设置好的阈值时才停止,这个阈值称为最小增量。

  加法增大算法操作过程则如下:当使用二分搜索增大算法时,可能会出现当前窗口大小与中间点之间差距很大。由于可能出现突然大量数据注入网络的情况,所以在一个RTT内将窗口增大到中间点可能并不是一个好方法。这种情况下,就需要采用加法增大算法。此时增量被限制为每个RTT增加S(_max),这一增量被称为窗口夹。一旦中间点距离试验窗口比距离S(max)值更近时,则转换为使用二分搜索增大算法。

总的来说,当检测到丢包现象,窗口会使用乘法系数β来减小,而窗口增大时,首先使用加法增大算法,之后一旦确认加法增量小于S(_max)时就转为使用二分搜索增大算法。这种组合算法称为二进制增长,或者BI。

CUBIC算法,BIC-TCP的改进版本:使用一个高阶多项式函数(具体来说是一个三次方程)来控制窗口的增大。三次方程的曲线既有凸的部分也有凹的部分,这就意味着在一些部分(凹的部分)增长比较缓慢,而在另一些部分(凸的部分)增长比较迅速。在BIC算法和CUBIC算法之前,所有TCP研究提出的都是凸的窗口增长函数。

CUBIC算法中,这个特殊的窗口增长函数如下所示:

    W(t) = C(t - K)³ + W(_max)

W(t)代表在时刻t的窗口大小,C是一个常量(默认为4),t是距离最近一次窗口减小所经过的时间(以秒为单位),K是在没有丢包情况下窗口从W增长到W(_max)所用的时间,W(_max)是最后一次调整前的窗口大小。其中K可依据以下表达式计算:

TCP/IP 笔记 - TCP拥塞控制

(K-公式)

其中β是积式减少的常量(默认为0.2)。CUBIC算法中的β默认为0.8。下图是CUBIC窗口增长函数的三次方程式:

TCP/IP 笔记 - TCP拥塞控制

除了三次方程之外,CUBIC还有"TCP友好性"策略。当窗口太小使得CUBIC不能获得比传统TCP更好的性能时,它将开始工作。根据t可以得到标准TCP的窗口大小W(_tcp)(t):

TCP/IP 笔记 - TCP拥塞控制

当在拥塞避免阶段有一个ACK到达时,如果cwnd值小于W(_tcp)(t),那么CUBIC将cwnd值设置为W(_tcp)(t),这种方法确保了CUBIC在一般的中低速网络中的TCP友好性。

基于延迟的拥塞控制算法

当发送端不断地向网络中发送数据包,不断增长的RTT值也可以作为拥塞形成的信号。新到达的数据包没有被发送而是进入了等待队列,这就造成了RTT值不断增大(直到数据包最终被丢弃)。一些根据这种情况提出的拥塞控制技术成为基于延迟的拥塞控制算法。

Vagas 算法 

Vagas算法于1994年被提出[BP95],它是TCP协议发布后的第一个基于延迟的拥塞控制方法,并经过了TCP协议开发组的测试。该算法首先估算了一定时间内网络能够传输的数据量,然后与实际传输能力进行比较。若本该传输的数据并没有被传传输,那么它有可能被链路上的某个路由器挂起,如果这种情况持续不断发生,那么Vages发送端将降低发送速率。

在拥塞避免阶段,Vages算法测量每个RTT中所传输的数据量,并将这个数除以网络中观察到的最小延迟时间。算法维护了两个阈值α和β,当吞吐量与预期不同时,若得到的吞吐量小于α,则将拥塞窗口增大;若吞吐量大于β,则将拥塞窗口减小。吞吐量在两阈值之间时,拥塞窗口保持不变。拥塞窗口所有的改变都是线性的,这意味着这种方法是一种和式增加/和式减少的拥塞控制策略。α和β的最小值分为设置为1和3,该设置的原因是:在网络中至少有一个数据报缓冲区会被占用才能保持网络资源被充分利用但如果只维护一个缓冲区,那么当有其他可用带宽时,就需要等待额外的RTT时间,因此为了传输更多数据,需要多使用2个缓冲区(达到3,α的值)。此外,保持一个区间(β-α)可用保留一部分空间,使得吞吐量可用有小幅改变而不至于引发串口大小的改变。

需要注意的是,在特定情况下,Vages算法会盲目的相信前向的延迟会高于它实际的值。这种情况发送在它相反的方向产生了拥塞。在这种情况下,虽然不是发送端导致了反向拥塞,但是返回发送端的数据包(ACK)会产生延迟。这就使得在这种不是真正需要调整拥塞窗口的情况下,减小了窗口大小。这是大多数基于测量RTT来进行拥塞控制判断的方法所共有的潜在缺陷。甚至,在反方向上严重的拥塞问题会导致ACK时钟的严重紊乱[M92]。

FAST 算法  

FAST TCP 算法是为了处理大带宽延迟的高速网络环境下的拥塞问题而提出的[WJLH06]。它依据预期的吞吐量和实际的吞吐量的不同、当前性能与预期值的不同来调整窗口。FAST算法会使用速率起搏(rate-pacing)技术每隔一个RTT都会更新发送率。如果测量延迟远小于阈值时,窗口会进行较快增长,一段时间后会逐渐平缓增长;当延迟增大时则相反。

TCP Westwood 算法和 Westwood+ 算法

TCP Westwood(TCPW)算法和 Westwood+(TCPW+)算法则通过修改传统的TCP NewReno发送端来实现对大带宽延迟积链路的处理。TCPW+算法是对TCPW算法发修正,在TCPW算法中,发送端的合格速率估计(ERE)是一种对连接中可用带宽的估计,且该估计值被不断计算。这个速率的测量会有一个测量间隔,该间隔基于ACK的到达动态可变。当拥塞现象不明显时,测量间隔会比较小;反之亦然。当检测到一个数据包丢失时,TCPW不会将cwnd减半,而是计算一个估计的BDP值(ERE乘以观察到的最小RTT),并将这个值作为新的ssthresh值。另一方面,在连接处于慢启动阶段时,使用一种灵活的探测机制适应性的反复设置ssthresh值。因此,当ssthresh值增长时,cwnd值会以指数形式增长。

复合TCP

复合TCP(CTCP)不仅依据丢包来进行窗口调整,还依据延迟的大小。可以认为它是一种标准TCP和Vages算法的结合,还包含了TSTCP可扩展的特点。

CTCP定义了一个新的窗口控制变量dwnd(延迟窗口),可以窗口大小W则变为:

    W = min(cwnd + dwnd,awnd)

对cwnd值的处理与标准TCP类似,但是如果延迟允许,新加入的dwnd值会允许额外的数据包发送,在拥塞避免阶段当ACKA报文到达时,cwnd值根据下面公式进行更新:

    cwnd = cwnd + 1(cwnd + dwnd)

当连接建立时,使用一个变量baseRTT来表示测量到的最小RTT值,然后预期数据与实际数据的差值diff将使用如下公式进行计算:diff = W * (1 - (baseRTT/RTT))。其中RTT是估算的平滑RTT估值,diff的值估算了网络队列中的数据包数量(或字节数)。CTCP算法试图将diff值保持在一个阈值内,以此保证网络的充分利用而不至于出现拥塞,这个阈值定义为γ。对于dwnd的值控制则依据以下公式:

TCP/IP 笔记 - TCP拥塞控制

在第一种情况下,网络没有被充分利用,CTCP根据多项式 α * win(t)(^k) 增大dwnd值。这是一种多项式级的增长,而当缓冲区的占用率小于γ时,会更快速的增长。

在第二种情况下,缓冲区的占用率已经超过了阈值γ,固定值ζ表示延迟窗口的递减速率,这就使得CTCP的RTT更具公平性。

在第三种情况下,当检测到包丢失,则dwnd值会有自己的积式递减系数β。

α表示平滑度默认为0.125,β表示响应性默认为0.5,k值表示速度等级被设置位0.75,γ值设为为30个数据包(根据经验)。

相关知识

在多个TCP连接中,新的连接可能会用到相同主机之间的其他连接的信息,包括已关闭的连接或者正在处于活动状态的其他连接。这就是相同主机间多个连接共享拥塞状态信息。[RFC2140]描述了相关信息,其中注意区分了暂时共享(新连接与已关闭连接间的信息共享)和总体共享(新连接与其他活动连接间的信息共享)。为将此思想形成除了TCP外的新的应用协议,[RFC3124]提出了拥塞管理机制,该机制使得本地操作系统可实现相关协议来了解链路状态信息,如丢包率、拥塞估计、RTT等。

庞大的内存(网络设备中包含大量的内存和几百万字节的包缓冲区,多指(高端)路由器)会导致像TCP这样的协议性能下降,这一问题被称为缓冲区膨胀[G11][DHGSO7]。它主要存在于家用网关的上行端以及家庭或小型办公室的接入点处,与排队等待而产生的大量延迟有关。标准TCP协议的拥塞控制算法会在链路的瓶颈处将缓冲区填满,而由于拥塞的信号(一个数据包丢失)需经很长时间才能反馈到发送端,此时在发送端和接收端之间缓存了大量数据,TCP协议也不能很好地运作。

然而针对这个问题也已经有方法解决,路由器提供一种管理列队的相应方法称为积极列队管理机制(AQM)。AQM通过使用算法(如RED)来一定概率的丢弃数据包或者对数据标记ECN字段置位或者实现。

随机早期检测(RED)网关[FJ93]机制能够探测拥塞情况的发生,并且控制数据包标记。这些网关实现了一种衡量平均占用时间的队列管理方法,如果占用队列的时间超过最小值(minthresh),并且小于最大值(maxthresh),那么这个数据包将被标记一个不断增长的概率值。如果平均队列占用时间超过了maxthresh,数据包将被标记一个可配置的最大概率值(MaxP),MaxP可设置为1.0,RED也可以将数据包丢弃而不是标记它们。

ECN机制主要在IP层进行操作,也可以应用于TCP以外的其他传输层协议,其过程如下:

  1. 当一个包含ECN功能的路由器经过长时间的拥塞,接收到一个IP数据包就,它会查看IP头中的ECN传输能力(ECT)标识,如果有效,负责发送数据包的传输层协议开启ECN功能,然后路由器会在IP头部设置一个已发生拥塞(CE)标识,然后继续向下转发数据包。若拥塞情况不会持续很长,则不好讲CE标识置位,因为即使一个单独的CE标识,传输协议也会做出反应。

  2. 当TCP接收端发现接收到的数据包的CE标识被置位,必须将该标识发送回发送端,并且它会将每个ACK数据包的ECN-Echo(ECN回显)位字段置位,直到接收到一个从发送端来的CWR位字段设置为1的数据包(CWR字段置位说明拥塞窗口已经降低)。

  3. 当TCP发送端接收到ECN-Echo标识的数据包时,会与探测到单个数据包丢失时一样调整cwnd值,同时还会重新设置后续数据包的CWR位字段。常规的拥塞处理方法为:调用快速重传和快速回复算法,使TCP在丢包之前降低发送速率。

相关攻击

早期的攻击是利用ICMPv4 Source Quench(源抑制)报文的结构,当这些报文被发送到允许TCP协议的主机上,任何与该IP地址相连的连接都会减慢发送速率,该IP地址包含在ICMP报文中的违规数据报中。然而随着1995年路由器不再使用Source Quench报文进行拥塞控制,该攻击方式成为不可行。解决这种攻击的简单方式就是在路由器和主机上阻止ICMP Source Quench报文的传输。

一种更复杂、常见的攻击方式是基于接收端的不当行为。这里描述三种攻击(ACK分割攻击、重复ACK欺骗攻击、乐观响应攻击)形式,它们都可以使TCP发送端以一个比正常状态更快的速率进行数据发送。

ACK分割攻击:将原有的确认字节范围拆分成多个ACK信号并返回给发送端,使得发送端的cwnd会比正常情况更快速增长。可通过计算每个ACK能确认的数据量来判断是否为正确的ACK来解决这一问题。

重复ACK欺骗攻击:该攻击可以使发送端在快速恢复阶段增长它的拥塞窗口,因为还没有明确的方法可以将接收到的重复ACK和它们所确认的报文段相对应。使用时间戳选项可以解决这一问题,然而最好的方法是限制发送端在恢复阶段的在外数据。

乐观响应攻击:对那些还没有到达的报文段产生ACK,导致发送端计算出的RTT比实际的小,从而比正常情况下更快的做出反应。为防范这类攻击,可通过定义一个可累加的随机数使得发送数据段大小可随时间动态改变,以此来更好地匹配数据段和它的对应ACK。当发现得到的ACK和数据段不匹配时,发送端就可以采取相应的行为。

参考:

《TCP IP 详解卷1:协议》

RFC官方文档