理论教育 如何进行TCP拥塞控制?

如何进行TCP拥塞控制?

时间:2023-07-01 理论教育 版权反馈
【摘要】:最初的TCP实现并没有考虑拥塞控制机制,直到后来才承认会产生拥挤倒塌或者一直处于高丢包率的超载状态。今天,TCP拥塞控制算法是在因特网上控制拥塞的主流端到端机制。TCP拥塞控制的主要范围[5]包括:无论何时,当丢包发生时,为了让系统恢复,适配有效的技术,同时保证有效的资源使用和数据传输。当达到慢启动门限之后,TCP连接进入拥塞规避模式。TCPCUBIC[7]是在Linux和Android内核的TCP栈中使用默认的拥塞控制算法。cwnd增长依赖于从最后拥塞控制事

如何进行TCP拥塞控制?

最初的TCP实现并没有考虑拥塞控制机制,直到后来才承认会产生拥挤倒塌或者一直处于高丢包率的超载状态。因而,在1988年,引入了第一个拥塞控制算法:Tohoe算法[4]

今天,TCP拥塞控制算法是在因特网上控制拥塞的主流端到端机制。TCP拥塞控制的主要范围[5]包括:无论何时,当丢包发生时,为了让系统恢复,适配有效的技术,同时保证有效的资源使用和数据传输。

由于可适用的拥塞控制机制不同,存在几个TCP版本。最常使用的版本是使用下述拥塞控制元的NewReno版本[6]:拥塞窗口(cwnd)、控制cwnd值以及慢启动的加性增长和乘法减少机制(比如两个端点之间最大数量的在途字节数)、拥塞规避、快速重传以及快速恢复算法。为了提供有效和可靠的数据传输,源端能使用这些机制。

已经建立的TCP连接在慢启动的模式下开始发送数据:发送端在初始化数据传输时设置MSS为cwnd窗口大小并且发送第一个分片。每次接收端确认分片接收后,cwnd窗口增加一个MSS。这意味着在慢启动阶段,cwnd窗口大小在每个来回程时间内都加倍,也就是说是指数增长,如图8.5所示。发送端允许发送的数据量受限于最小cwnd窗口大小以及广播窗口。

直到到达预定义的门限(慢启动门限)、检测到丢包或者发生超时,否则指数级增长会一直持续。当达到慢启动门限之后,TCP连接进入拥塞规避模式。在这种模式下,cwnd窗口在每个RTT中只增长一个MSS。这种机制比慢启动中的方法温和很多。当检测到丢包时,cwnd就不再增长。接收端使用包含期望下一次接收到TCP分片的序列号的ACK去确认已经正确接收到的数据。

978-7-111-57100-1-Part02-90.jpg

图8.5 慢启动例子

在丢包的场景下,如果连续的分片被正确接收,接收端只需发送一个ACK。如果上述情况发生,接收端通过发送第一个分片丢失的序列号去通知源端分片丢失。由于该ACK所代表的数据包与响应最后正确接收数据包的ACK是同一个,所以这个ACK被称为重复ACK。为了辅助正确的源端操作,需要立即发送重复ACK。

当发送端收到多个重复ACK时(带有同样序列号的ACK),就会检测到丢包。当收到3个重复的ACK时,认为分组丢失,比如4个连续的ACK确认相同的数据。依赖于这个事实,会立即重传认为是丢失的分组(重复ACK中的序列号对应的分组)。这个过程被称为快速重传,如图8.6所示。

978-7-111-57100-1-Part02-91.jpg

图8.6 快速重传的3次重复ACK

注:由于简化的原因,使用多个MSS表示序列号(比如:X+2意思是X+2MSS)。

快速重传后,发送端进入快速恢复状态。第一次接收到重复ACK时不立即进行重传会帮助系统规避由于TCP分片重排序引入的重传。3个重复ACK仍旧能被传输数据的源端接收到(除了分片可能丢失的情况),因而没有道理去快速降低连接率。相应的,在快速恢复情况下,把慢启动门限设置为cwnd当前值和接收广播窗口值中的最小值的一半,并且把cwnd值设置为慢启动门限与最大分片大小3倍的和(这个称为窗口膨胀)。当接收到每一个重复ACK后,cwnd的值增加一个分片大小,并且如果cwnd的值(和广播窗口)允许,传输新的分片。直到收到一个ACK,它确认了所有以前没有被确认的分片后,连接状态才转入拥塞避免状态。当连接进入拥塞避免模式时,其使用的cwnd值被重新设置为慢启动门限(这个称为窗口紧缩)。在部分确认的场景下(比如进入快速恢复前只有部分已经被发送的分片被确认),重传第一个未被确认的分片。(www.daowen.com)

对发送的每一个分片,发送端维护了一个定义期望接收端在一个时间区间内回复ACK的辅助重传超时定时器(RTO)。基于来回程时间测量估计得到该定时器的时长。一旦定时器超时,比如:在定时器超时前没有收到ACK,重传该分片;把慢启动门限设置为下述两个值的最大值:两倍的MSS和实际cwnd值的一半;cwnd值设置为MSS,RTO定时器的值加倍以及TCP连接进入慢启动模式。每一次尝试传输分片都失败之后,RTO定时器的值都加倍直到达到64s的上限为止。这个过程被称为指数补偿。

正如之前讨论的,带有拥塞控制的第一个TCP版本是包含有慢启动、拥塞规避以及快速重传机制的TCP Tahoe版本。当收到3个重复ACK时,源端重传丢失分片,设置cwnd的值为一个MSS并且进入慢启动模式。在过渡态丢包的情况下,由于不必降低源端速率,上述不是一种有效的方法。

TCP Reno实现了一个简化版本的快速恢复算法,在这个算法中,当收到3个重复ACK时,重传丢失的分片。当收到一个确认新发送数据的ACK时,源端离开快速恢复状态,也就是说,由于退出准则不需要必须接收到所有分片的确认,所以TCP Reno在每个来回程时间内仅仅能传输一个丢失分片。在只有一个分片丢失的情况下,新的ACK能确认所有的数据,然而在多个分片丢失的情况下,某些但不是所有的分片能被确认。这个就被称为部分确认。

TCPCUBIC[7]是在Linux和Android内核的TCP栈中使用默认的拥塞控制算法。引入该算法是为了在高速长距离网络情况下处理观察到的TCP效率问题。这些网络拥有大量的时延带宽积,并且为了达到更高的资源使用率,这些时延带宽积决定了在源端和目的端所需要的在途分组数量。

在拥塞避免期间(比如拥塞事件发生后)拥有加性增长的TCP版本的cwnd值不能快速增长。一些连接持续的时间比要求达到的时延带宽积的时间还要短。TCPCUBIC通过使用三次曲线函数去替代线性增长函数来解决该问题。当检测到丢包时,执行正常的快速重传、快速恢复机制;通过一个因子(默认值是0.2)去减少cwnd的值;记录丢包前的窗口大小。把这个窗口大小(Wmax)看作饱和点如图8.7所示,直到Wmax到达之前,cwnd的增长是与在Wmax有相对平稳的三次曲线的凹函数部分相一致。当Wmax到达后,紧随着凹函数增长的是凸函数的增长。这个增长函数确保了在短时间内能达到饱和点,在Wmax附近的cwnd值几乎是保持常数,最后在没有检测到丢包的场景下,cwnd的值缓慢增长。即使每一个连接有不同的来回程时间,但每一个连接有几乎相同的cwnd大小。cwnd增长依赖于从最后拥塞控制事件(比如快速恢复)开始的逝去时间t,这提升了竞争连接的公平性。这个算法估计TCPReno在逝去的时间t内将要达到的窗口大小,以及当cwnd大于从三次方函数中计算得到的值时,设置cwnd为上述窗口值。这是CUBIC算法的TCP友好区。

978-7-111-57100-1-Part02-92.jpg

图8.7 窗口增长函数CUBIC的示意图

复合TCP[10]是为Windows(Vista和Server2008)开发的拥塞控制算法。它维护了由两个元素组成的特殊窗口:有一个窗口像TCPReno那样的方式进行增长,另外有一个基于延时的窗口。当网络未充分使用时,窗口增加,比如延时很小的情况;当延时很大时,窗口减小,比如拥塞发生。该算法尽最大可能维护常量cwnd值(例如两个元素的和)。

TCP拥塞控制机制有几个局限性,例如在拥塞检测中分组丢失的可靠性、延时或者来回程时间估计的不准确性以及没有能力区分分组丢失的可能原因。当分组丢失不是由于拥塞产生时,能触发不必要的拥塞控制检测,这种情况在无线环境下经常发生,比如丢包是由于比特错误、移动性等。这种场景会使承载在移动网络上的TCP性能恶化,该部分内容将在下一节中详细讨论。

为了让拥塞控制算法在丢包前生效,比如在迫使网络节点丢包前降低传输速率,引入了明确拥塞通知(ECN、RFC3168)机制。当检测到拥塞时,ECN机制在IP头中设置通知位,进而会有一个解决方案去降低连接两端的速率。

一个提升延时和来回程时间测量的可能性是通过在每一个TCP分片中打时间戳的方式应用TCP时间戳选项(RFC1323)。基于这个时间戳,源端能有一个精确的来回程时间测量和RTO定时器估计值。

免责声明:以上内容源自网络,版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。

我要反馈