微软官方MSDN原版Win10系统下载

现在位置: 首页  > 系统教程  > 系统帮助

tcp如何实现拥塞控制

时间:2024-11-23 15:04:31   

大家好,今天Win10系统之家小编给大家分享「tcp如何实现拥塞控制」的知识,如果能碰巧解决你现在面临的问题,记得收藏本站或分享给你的好友们哟~,现在开始吧!

生意如何小账本专业版-小商户销售和存货记账系列软件最新版本下载

1.跪求 TCP拥塞控制原理演示系统


9.9需要说明的问题。传输控制协议(Transmission Control Protocol)

在这一部分中,我们将讨论TCP拥塞的非常情况,以说明拥塞控制原理的实现,包括添加到传输协议产品中的一些细节。

9.1缓慢启动

TCP发送方不能通过一次发送一大段数据(如接收方建议的窗口)来打开新的连接。TCP发送方对拥塞窗口的初始值有限制。在慢启动过程中,TCP发送方可以通过在一个周期内将两个因素合二为一来提高传输速率。当检测到拥塞或发送方的拥塞窗口大于慢启动的临界值时,慢启动结束。

标准化过程已经清楚地提出了全局拥塞控制的潜在影响,包括初始窗口值的增加[参见RFC2414、RFC2581]。

通常认为标准化过程提出的问题不需要标准化,包括是否使用基于速率的步进方法,以及在拥塞窗口达到临界值之前提前结束慢启动的机制。这种机制使得慢启动或多或少比标准TCP保守。

9.2加法的增加和乘法的减少。

当没有拥塞时,TCP发送方每个周期增加一个包来增加拥塞窗口。当拥塞发生时,TCP发送方将拥塞窗口缩小一半。(更准确地说,新的拥塞窗口是最小拥塞窗口和接收方建议的窗口的一半)。

标准化过程已经清楚地提出了全局拥塞控制的潜在影响,包括针对“纯响应”流返回的拥塞控制的附加建议。

一个标准化的过程并没有提出通常认为不需要标准化的问题,包括拥塞窗口的改变是在字节数的上界在流水线中继续时应用的,而不是在确认后滑动窗口开始时应用的。(显然,接收者推荐的窗口应用是在确认后以滑动窗口开始的。因为从确认方收到的数据包被放在TCP接收方的缓存中,所以它没有被传送到应用程序。然而,拥塞窗口随着流水线中分组的数量而变化,并且不需要包括由TCP接收器以无序方式接收的分组。

9.3重发定时器

TCP发送方设置一个重传定时器来通知网络一个分组已经被丢弃。当重传计时器超时时,发送方得知有数据包丢失,将当前窗口设置为原来的一半,缓慢启动,然后重传丢失的数据包。如果重传定时器由于重传的分组没有被确认而到期,则重传定时器也“后退”,使下一次重传的时间间隔加倍。

标准化过程很可能明确提出这样一个问题,对全局拥塞控制有潜在的影响,包括在发送方没有得到确认,数据包实际没有被丢弃的情况下,如何使重传定时器增加重传时间间隔的修正机制。因为重传定时器会增加拥塞链路上不必要的数据包传输,网络标准化进程对此非常关注。

9.4快速重传和快速修复

当您看到三个重复的确认时,TCP发送方知道有数据包丢失。然后TCP发送方将临界值设置为当前窗口的一半,将拥塞窗口缩小到前一半,重新发送丢失的数据包。

标准化过程很可能明确提出这样的问题,其对整体拥塞控制具有潜在影响,包括当只有一个或两个重复确认时通知分组丢失的建议。如果设计不好,这种方案可能会导致数据包在拥塞的路径上不必要的传输。

标准化过程没有提出的问题(通常认为不需要标准化)是,如果拥塞窗口同意,则建议响应于重复确认发送“新的”或丢失的分组。例如,如果只有一个重复的确认,并且没有更多的确认到达,将发送一个新的数据包响应以保持“响应时钟”运行。这个提议是一个有益的改变。它不涉及互操作性,也不影响全局拥塞控制,因此由开发者应用,无需IETF标准化过程的介入。

来源:3360王雪(www.xue5.com),原地址为:http://www.xue5.com/itedu/200802/76308_4.html.



2.tcp拥塞控制四种算法


TCP拥塞控制的四种算法分别是:慢启动,和性增长/乘性降低,快速重传和快速恢复。

1、慢启动

慢启动初始启动时设置拥塞窗口值(cwnd)为1、2、4或10个MSS。拥塞窗口在每接收到一个确认包时增加,每个RTT内成倍增加,当然实际上并不完全是指数增长,因为接收方会延迟发送确认,通常是每接收两个分段则发送一次确认包。发送速率随着慢启动的进行而增加,直到遇到出现丢失、达到慢启动阈值(ssthresh)、或者接收方的接收窗口进行限制。

2、和性增长/乘性降低

和性增长/乘性降低(additive-increase/multiplicative-decrease,AIMD,)是一种反馈控制算法,其包含了对拥塞窗口线性增加,和当发生拥塞时对窗口积式减少。多个使用AIMD控制的TCP流最终会收敛到对线路的等量竞争使用。

3、快速重传

快速重传(Fast retransmit)是对TCP发送方降低等待重发丢失分段用时的一种改进。TCP发送方每发送一个分段都会启动一个超时计时器,如果没能在特定时间内接收到相应分段的确认,发送方就假设这个分段在网络上丢失了,需要重发。这也是TCP用来估计RTT的测量方法。

4、快速恢复

“快速恢复”算法是在上述的“快速重传”算法后添加的,当收到3个重复ACK时,TCP最后进入的不是拥塞避免阶段,而是快速恢复阶段。快速重传和快速恢复算法一般同时使用。快速恢复的思想是“数据包守恒”原则,即同一个时刻在网络中的数据包数量是恒定的,只有当“老”数据包离开了网络后,才能向网络中发送一个“新”的数据包。



3.TCP(IV) 拥塞控制


网络中的路由器因无法处理高速到达的流量而被迫丢弃数据信息的现象称为拥塞。这里可能是因为路由器缓存较小或者处理不及时,虽然和流量控制时接收方的情况相似,但是这里有本质区别。因为后者是一对一的,几乎只影响一条连接;后者则影响多个连接。


当网络中大量的发送方和接收方被要求承担超负荷的通信任务时,可以采用降低发送方发送速率或者丢弃部分数据(也可二者结合)来降低拥塞。


通常来说,接收方没有一个精确的方法去知道中间路由器的状态。目前基本的方法有:


之前的文章提到,发送方为了适应接收方接受速度,设置了一个发送窗口来控制流量。同样的,当拥堵发生时,也需要控制发送速率,于是引入了一个窗口变量,来反映网络传输能力,称为拥塞窗口(Congestion window),记作 cwnd。很直观的,我们可以知道,发送端实际可用窗口 W 表示如下,其中 awnd 表示接收方窗口大小:


W = min(cwnd, awnd)


也就是说,还没有收到 ACK 的数据量(也称在外数据量)不能多于 W 。通常 W 以字节或包为单位。很明显, W 的值是在随时变化的,并且我们希望 W

接近一个最佳窗口大小——带宽延时积(Bandwidth-Delay Product, BDP),BDP 表示某一时刻的在外数据量,但是确定一个连接的 BDP

也是一个难点。


当连接建立之初,还无法获知可用的连接资源,也无法确定 cwnd 初始值(有例外,就是之前文章里提到的目的度量)。这时候不应该直接大量快速的向网络中发送数据,因为会造成更严重的网络拥堵。获得 cwnd 最佳值的唯一方法就是以越来越快的速度发包,直到有数据包丢失(或网络拥堵)。可以考虑慢启动发送。在讨论具体算法之前,需要先了解数据包守恒的概念。


TCP 发送端的拥塞控制行为是由 ACK 的接收来驱动或“控制”的。并且链路的传输能力是固定的,当发送方接收到一个 ACK 时,就表示链路上多了一个“空位”,于是发送方可以再发送一个数据包。数据包守恒就是指链路中最大包的数量守恒。


当一个连接刚启动时,或者检测到重传超时导致的丢包时,需要执行慢启动

; TCP 长时间处于空闲状态也可能触发慢启动。其目的是探寻到 cwnd 值已经帮助 TCP 建立 ACK 时钟。


TCP

发送一定数目的报文开始慢启动,该数目称为初始窗口(IInitial Window,IW)。为了简便,我们讨论 IW

为一个 SMSS (sender's MSS)的情况。意味着初始 cwnd 大小为

1 SMSS。


假设没有丢包且每一个数据都有相应的 ACK。那么第一个 ACK 到达,说明可以再发送一个新的报文段(数据包守恒),每收到一个“好的” ACK,cwnd = cwnd + min(N, SMSS),这里的 N 是指那个“好的” ACK 所确认的字节数。所谓“好的”是指 ACK 号使窗口更新了。


因为通常来说 N 的值等于 SMSS,使得 cwnd 在收到一个 ACK 后增大一倍。所以慢启动实际上是以指数增长,在 K 轮之后,cwnd =

2^K。如下图:


当接收方开启延时 ACK,则发送方 cwnd 增长曲线如图中蓝色曲线,虽然起步看起来慢,但仍是指数增长。当然这对于带宽延时积很大的网络来说,确实有所浪费,应该采用更好的办法。


当然不可能让窗口大小无限增长,否则会造成严重的网络拥堵直至网络瘫痪。在上述情况下,cwnd 将大幅减小(减至原值一半),也是慢启动和拥塞避免的转折点,与慢启动阈值(slow start threshold, ssthresh)有关。


当 cwnd 达到 ssthresh 时,可能还有一些传输资源未被占用。但这时候需要谨慎的试探,不能再以较快速度增大 cwnd。采用避免拥塞算法,每接收到一个新的 ACK,cwnd 会做以下更新:


cwnd = cwnd + SMSS * SMSS / cwnd


假设 cwnd = k * SMSS,则可推导如下:


cwnd = cwnd + SMSS / k


发包来看像这样:


通常认为拥塞避免阶段 cwnd 呈线性增长,称为累加增长。


通常 TCP 连接总是会选择慢启动和拥塞避免中的一个,依据就是之前提到的慢启动阈值。当 cwnd < ssthresh,采用慢启动算法, cwnd > ssthresh 采用拥塞避免,相等时选择任意都行。所以关键就是 ssthresh 的值,该值并不是固定的,它的主要目的是,记录上一次最好的窗口估计值


ssthresh 初始值可以任意设定(如 awnd 或更大),这通常会使 TCP 总是以慢启动开始。当出现重传,无论是超时重传还是快速重传,都会导致 ssthresh 值更新如下:


ssthresh = max(在外数据值 /

2, 2 * SMSS)


在外数据值其实就是当前窗口大小。这样通常会使 ssthresh 变小(但也可能使其变大),然后触发拥塞避免。


Tahoe 算法规定当重传时,都会进入慢启动,并且丢包时,将 cwnd 设为

1 SMSS。这显然性能不太好,已被弃用,不用深究。


Reno 算法是标准 TCP 的基础,它根据之前提到的“包守恒”实现了快速恢复,较好的利用了带宽。快速恢复是针对快速重传的情景实现的,来看一下它在标准 TCP 中的使用:


以下是 Reno 的状态转换图:


Reno 算法在同一窗口下丢失多个包时,其中一个包快速重传成功,就会停止 cwnd 膨胀,造成其它丢失的包可能触发超时重传,然后 cwnd 降为

1 SMSS,吞吐量大大降低。NewReno 采用了一个“恢复点”,指的是收到的 ACK 号大于已发送包的序列号的最大值,达到这个恢复点,才会退出快速恢复。下图最右图中, ACK11 达到了恢复点。


限制传输策略对 TCP 做了微小改进,主要是为了解决窗口较小时,出现丢包,但是没有足够的包去引发快速重传/快速恢复机制。为了尽快触发快速重传,每接收两个连续重复 ACK,就发送一个新的包,使网络中的数据量维持一定数量。这是 TCP 推荐策略。


这里对应 TCP/IP 详解卷一里,书上对于“应用受限”说法不正确。书上说此时“无法发送”,但是查阅 rfc 原文如下:


拥塞窗口校验(Congestion Window Validation)机制规定,需要发送新数据时,距离上次发送操作超过一个 RTO,如果是:


在长时间发送暂停后,cwnd 低于 ssthresh,再次发送时会进入慢启动。Linux 默认开启 CWV。


在之前的超时重传里,我们提到了 伪超时,再来回顾下(注意下图是相当简易的情形,没有考虑延时 ACK 以及 cwnd 增长,会意即可):


伪超时可能引起“回退 N 步”的行为,并且可能触发快速重传,浪费不少资源。


该算法利用 TCP 的 TSOPT 选项,在发送生超时后,重传报文并记录 TSV,期待一个 ACK,若 ACK 的 TSER 小于重传报文的 TSV,则认为该 ACK 是对原始报文的确认而不是对重传报文的确认,即认定该重传是伪重传。


前面提到过,发生超时,则 ssthresh 减半,cwnd 降为

1 SMSS。发生伪超时的话,在 RTO 之后到来的 ACK 会使 cwnd 快速变大,但仍会有不必要重传。


采用 Eifel 算法,在判定伪超时后,会撤销对 ssthresh 的修改。在每次超时对 ssthresh 修改之前,会用 pipe_prev 变量来保存当前的 ssthresh,以便撤销修改。


若出现伪重传,当 ACK 到达时,假设 ACK 确认的报文段长度为 A:


前面讨论了当失序或者超时的时候 TCP 的行为,这些行为都是通过 ACK 的反馈来触发或者驱动的,换句话说,这些“拥塞”的情况是“猜出来的”。当明确知道发生拥堵了,TCP 会执行拥塞窗口缩减(congestion window reducing,CWR)。明确知道拥堵的情况主要有两种:


CWR 处理过程如下:


直到 cwnd 达到新的 ssthresh 值或者由于其他原因(如丢包)打断 CWR。


到此,我们总结一下 TCP 拥塞控制的几个重要状态:


这个问题还是很有趣的,所以拿出来讲一下。先说结论,网络设备的缓冲区并不是越大越好,也不是越小越好,而是需要根据链路速率和RTT进行计算,得到一个经验值。


缓冲区过小的问题很明显,如果缓冲区太小,很容易就被写满了,只要不能进行适当的排队,丢包率会高,导致传输效率差。


假设如下场景:


上图中,我们假设中间的路由设备的buffer极大,理论来说无论来多少数据,都能buffer起来。中间的路由设备,接收速率是1M/s,而发送速率只有10k/s。



到某一时刻,发送方认为某一数据超时丢失(实际上没有丢失,而是在缓冲区没来得及处理),于是重发,导致缓存区有冗余数据。大量的冗余数据导致利用率变得极低。


而缓冲区为正常大小的时候,多的数据会被丢弃,过一会而缓冲区有新的位置,新的数据会到来,接收方收到数据是失序的,于是发送冗余 ACK,促进快速重传,反而使链路利用率得到保障。


大多数攻击是强迫 TCP 发送速率比一般情况更快或更慢。


原理是接收方将原来的确认范围划分成很多小块,把一个 ACK 变成多个 ACK,使得发送方不断增大 cwnd,使网络变的拥堵。可以通过计算每个 ACK 的确认量(而不是一个包)来判断是否是正确的 ACK。


接收方对还没到达的数据进行提前确认,使得 RTT 变得比较小,同样使得发送方不断增大 cwnd。可以采用一个可累加的随机数,动态匹配 ACK。



4.TCP拥塞控制及BBR原理分析


导语:TCP拥塞控制不仅仅是网络层的概念,可以将其归属于控制论的范畴。在TCP的演进过程中,出现了很多优秀的思想和算法,以实现网络传输过程中,在公平竞争性的前提下,尽可能地利用带宽资源。本文介绍TCP发展过程中出现的几种拥塞控制算法,并着重介绍BBR的原理。


TCP拥塞控制不仅仅是网络层的概念,可以将其归属于控制论的范畴。在TCP的演进过程中,出现了很多优秀的思想和算法,以实现网络传输过程中,在公平竞争性的前提下,尽可能地利用带宽资源。


公平性是在发生拥塞时各源端(或同一源端建立的不同TCP连接或UDP数据报)能公平地共享同一网络资源(如带宽、缓存等)。处于相同级别的源端应该得到相同数量的网络资源。产生公平性的根本原因在于拥塞发生必然导致数据包丢失,而数据包丢失会导致各数据流之间为争抢有限的网络资源发生竞争,争抢能力弱的数据流将受到更多损害。

因此,没有拥塞,也就没有公平性问题。


TCP层上的公平性问题表现在两方面:



(1)面向连接的TCP和无连接的UDP在拥塞发生时对拥塞指示的不同反应和处理,导致对网络资源的不公平使用问题。在拥塞发生时,有拥塞控制机制的TCP会按拥塞控制步骤进入拥塞避免阶段,从而主动减小发送到网络的数据量。但对无连接的数据报UDP,由于没有端到端的拥塞控制机制,即使网络出现了拥塞,也不会减少向网络发送的数据量。

结果遵守拥塞控制的TCP数据流得到的网络资源越来越少,没有拥塞控制的UDP则会得到越来越多的网络资源。



(2)TCP连接之间也存在公平性问题。产生问题的原因在于使用了不同的拥塞控制算法,一些TCP在拥塞前使用了大窗口尺寸,或者它们的RTT较小,或者数据包比其他TCP大,这样它们也会多占带宽。


拥塞控制主要包括四个过程:

1)慢启动;2)拥塞避免;3)拥塞发生;4)快速恢复。


RTT:数据包从发出去到收到对它的ack的来回时间,采用平滑方式计算RTT


RTO

:重传超时。简单的如RTO=n*RTT,

n=3(或其他RTO计算方法)


SACK:TCP Option携带多组ACK信息


FR:Fast Retransmission,收到3个dup ack后,即可认为发生了丢包。不需要等待RTO超时即可重传丢失的包。


ER:Early Retransmission,无法产生足够的dupack和没有新的数据包可以发送进入网络的情况下,减少触发FR的dup ack数量,以达到触发FR的目的。


TLP:如果发生了尾丢包,由于尾包后面没有更多的数据包,也就没有办法触发任何的dupack。实际上,Google统计超过70%的RTO是尾丢包导致没有任何dup


ack。TLP算法是通过发送一个loss probe包,来产生足够的SACK/FACK的信息以触发RF。


Pacing:控制发送速率,防止bursting


流控:Flow control站在单条TCP连接的维度,目的是让发送方发包的速度,不超过接收方收包的能力。所以流控解决的问题是,如何在接收方可承受的范围内,让单条 TCP 连接的速度最大化。通过滑动窗口机制实现。


拥塞控制:Congestion control站在整个互联网的维度,让网络里所有TCP连接最大化共享网络通道的同时,尽可能的少出现网络拥塞现象,让网络世界里的每一个参与者既公平又高效。


cwnd:发送窗口,拥塞窗口;在拥塞控制过程中窗口大小值变化。


rwnd:接收窗口,通知发送者能够发送的数据大小。


sliding window:滑动窗口,只是一种抽象机制概念;在发送请求及收到ack的过程中滑动。


历史上出现的各种TCP拥塞控制算法,其本质是针对拥塞控制的四个过程做策略调整。按照算法依据的因素,可以简单的分为以下类型:


因为Reno等算法是后续算法的基础,这里详细的描述下Reno算法的过程。


(1)慢热启动算法 – Slow Start


(2)拥塞避免算法 – Congestion Avoidance

当cwnd >= ssthresh时,就会进入“拥塞避免算法”。算法如下:


(3)拥塞状态算法 – Fast Retransmit

Tahoe是等RTO超时,FR是在收到3个duplicate ACK时就开启重传,而不用等到RTO超时。拥塞发生时:


(4)快速恢复 – Fast Recovery


Reno算法以其简单、有效和鲁棒性,应用最广泛。该算法所包含的慢启动、拥塞避免和快速重传、快速恢复机制,是现有的众多算法的基础。从Reno运行机制中很容易看出,为了维持一个动态平衡,必须周期性地产生一定量的丢失,再加上AIMD机制--减少快,增长慢,尤其是在大窗口环境下,由于一个数据报的丢失所带来的窗口缩小要花费很长的时间来恢复,这样,带宽利用率不可能很高且随着网络的链路带宽不断提升,这种弊端将越来越明显。

另外,丢包并不一定是网络拥塞,可能是网络常态,但是基于丢包的拥塞控制并不能区分。


vegas通过对RTT的非常重的监控来计算一个基准RTT。然后通过这个基准RTT来估计当前的网络实际带宽,如果实际带宽比我们的期望的带宽要小或是要多的活,那么就开始线性地减少或增加cwnd的大小。


中间路由器缓存数据导致RTT变大,认为发生拥塞;RTT不公平性,当不同的数据流对网络瓶颈带宽进行竞争时,具有较小RTT的TCP数据流的拥塞窗口增加速率将会快于具有大RTT的TCP数据流,从而将会占有更多的网络带宽资源。


在发送端做带宽估计,当探测到丢包时,根据带宽值来设置拥塞窗口、慢启动阈值。 那么,这个算法是怎么测量带宽的?每个RTT时间,会测量一次带宽,测量带宽的公式很简单,就是这段RTT内成功被ACK了多少字节。Westwood会根据RTT变化来判断丢包是否是网络拥塞造成的,还是网络常态的丢包。如果时延变化不明显,就认为是非网络拥塞,此时cwnd减少的比较小。


BIC-TCP是Linux

2.6.18默认拥塞控制算法,依赖丢包条件触发。BIC-TCP认为TCP拥塞窗口调整的本质就是找到最适合当前网络的一个发送窗口,为了找到这个窗口值,TCP采取的方式是(拥塞避免阶段)每RTT加1,缓慢上升,丢包时下降一半,接着再来慢慢上升。BIC-TCP的提出者们看穿了事情的本质,其实这就是一个搜索的过程,而TCP的搜索方式类似于逐个遍历搜索方法,可以认为这个值是在1和一个比较大的数(large_window)之间,既然在这个区间内需要搜索一个最佳值,那么显然最好的方式就是二分搜索思想。


BIC-TCP就是基于这样一个二分思想的:当出现丢包的时候,说明最佳窗口值应该比这个值小,那么BIC就把此时的cwnd设置为max_win,把乘法减小后的值设置为min_win,然后BIC就开始在这两者之间执行二分思想--每次跳到max_win和min_win的中点。


BIC也具备RTT的不公平性。RTT小的连接,窗口调整发生的速度越快,因此可能更快的抢占带宽。


CUBIC在设计上简化了BIC-TCP的窗口调整算法,在BIC-TCP的窗口调整中会出现一个凹和凸(这里的凹和凸指的是数学意义上的凹和凸,凹函数/凸函数)的增长曲线,CUBIC使用了一个三次函数(即一个立方函数),在三次函数曲线中同样存在一个凹和凸的部分,该曲线形状和BIC-TCP的曲线图十分相似,于是该部分取代BIC-TCP的增长曲线。

另外,CUBIC中最关键的点在于它的窗口增长函数仅仅取决于连续的两次拥塞事件的时间间隔值,从而窗口增长完全独立于网络的时延RTT,使得连接之间保持良好的RRTT公平性。


来看下具体细节:当某次拥塞事件发生时,Wmax设置为此时发生拥塞时的窗口值,然后把窗口进行乘法减小,乘法减小因子设为β,当从快速恢复阶段退出然后进入到拥塞避免阶段,此时CUBIC的窗口增长开始按照“凹”式增长曲线进行增长,该过程一直持续直到窗口再次增长到Wmax,紧接着,该函数转入“凸”式增长阶段。该方式的增长可以使得窗口一直维持在Wmax附近,从而可以达到网络带宽的高利用率和协议本身的稳定性。


CUBIC窗口的增长函数:W(t) = C * (t-K)3 + Wmax, 其中C和β为常量。


t为当前时间距上一次窗口减小的时间差,而K就代表该函数从W增长到Wmax的时间周期。



通俗一点讲,假如我们知道了Wmax,那么CUBIC的核心思想就是需要在连续两次拥塞期间执行完上面的三次函数增长曲线


BBR通过实时计算带宽和最小RTT来决定发送速率pacing rate和窗口大小cwnd。完全摒弃丢包作为拥塞控制的直接反馈因素。


传统的拥塞控制算法是计算cwnd值来规定当前可以发送多少数据,但是并不关注以什么样的速度发送数据。如果简单而粗暴地将窗口大小(send.cwnd、recv.cwnd的最小值)数据全部突发出去,这往往会造成路由器的排队,在深队列的情况下,会测量出rtt剧烈地抖动。bbr在计算cwnd的同时,还计算了一个与之适配的pacing rate,该pacing rate规定cwnd指示的一窗数据的数据包之间,以多大的时间间隔发送出去。


我们知道,网络工作的最优点是在物理链路延迟状态下,以最大速率传输数据。传统的拥塞控制算法思想是根据数据传输及ACK来确定RTT,但是这个RTT并不是物理链路延时,可能包含了路由器缓存耗时,也可能是拥塞状态下的耗时。传统的带宽计算也是在不断的试探逼近最优发送窗口,并在RTT或者统计周期内计算带宽。这种情况下,RTT并不是真正的物理链路延迟,带宽也有可能是在有路由缓存或丢包状况下计算得到,那么必然得到的不是精准的值。


BBR摒弃了丢包和实时RTT作为拥塞控制因素。引入BDP管道容量来衡量链路传输水平。BBR追求的是在链路最小RTT(物理链路延迟)的状态下,找到最大带宽。


首先我们认为网络最优点是可以达到的。下面描述RTT及收包速率与数据包投递速率的关系。


图中上半部分的过程可以描述为:随着数据包投递速率增加,如果没有超过最优带宽,则RTT不会变化,此时的RTT是物理链路延迟。随着投递速率继续增加,这时中间路由节点可能出现需要缓存数据包的情况,这会导致RTT变大。如果投递速率继续增加,超过路由缓存能力,则可能出现丢包。


图中下半部分的过程可以描述为:随着数据包投递速率增加,如果没有超过最优带宽,则发送方确认接收端收到的数据速率增加。随着投递速率继续增加,因为数据包缓存在中间路由,这些包并不能及时得到ACK,因此发送方得到的ACK速率,即发送发确认接收方收到数据的速率会维持不变。如果投递速率继续增加,超过路由缓存能力,则可能出现丢包。



1)应答了多少数据,记为delivered;

2)应答1)中的delivered这么多数据所用的时间,记为interval_us。

将上述二者相除,就能得到带宽:bw = delivered/interval_us;该计算方法不关注数据包ack及顺序,是纯粹的标量。


我们可以根据图示很容易算出从Delivered为7时的数据包被确认到X被确认为止,一共有12-7=5个数据包被确认,即这段时间网络上清空了5个数据包。我们便很容易算出带宽值了。



当10s内没有发现最小RTTProp时,就要进入ProbeRTT状态。在ProbeRTT状态,仅发4MSS/RTT(接近停止发送),从而排空链路上的数据包,测量真实的RTTProp。这里带来的一个问题是,在一个RTT时间内以4MSS速率发送可能会造成抖动,特别是长RTT场景。具体的参考willko文章《GBN手札-BBR实时大数据传输之痛》。



5.浅谈TCP(2):流量控制与拥塞控制


上文 浅谈TCP(1):状态机与重传机制 介绍了TCP的状态机与重传机制。本文介绍 流量控制 (Flow Control,简称流控)与 拥塞控制 (Congestion Control)。TCP依此保障网络的 QOS (Quality of Service)。


根据前文对TCP超时重传机制的介绍,我们知道Timeout的设置对于重传非常重要:


而且,这个超时时间在不同的网络环境下不同,必须动态设置。为此,TCP引入了 RTT (Round Trip Time,环回时间):

一个数据包从发出去到回来的时间。这样,发送端就大约知道正常传输需要多少时间,据此计算 RTO (Retransmission TimeOut,超时重传时间)。 听起来似乎很简单:在发送方发包时记下t0,收到接收方的Ack时记一个t1,于是RTT =

t1 –

t0。然而,这只是一个采样,不能代表网络环境的普遍情况。


RFC793 中定义了一个 经典算法 :


经典算法描述了RTO计算的基本思路,但还有一个重要问题:RTT的采样取“

第一次

发Seq+收Ack的时间”,还是“重传Seq+收Ack的时间”?


如图:


问题的本质是:发送方无法区分收到的Ack对应第一次发的Seq还是重传的Seq(进入网络就都一样了)。针对该问题, Karn / Partridge 算法选择回避重传的问题: 忽略重传的样本,RTT的采样只取未产生重传的样本 。


简单的忽略重传样本也有问题:假设当前的RTO很小,突然发生网络抖动,延时剧增导致要重传所有的包;由于忽略重传样本,RTO不会被更新,于是继续重传使网络更加拥堵;拥堵导致更多的重传,恶性循环直至网络瘫痪。Karn / Partridge算法用了一个取巧的办法:

只要一发生重传,就将现有的RTO值翻倍(指数回退策略),待网络恢复后再仿照经典算法逐渐平滑以降低RTO 。


该算法已经做到可用,然而网络抖动对性能的影响比较大。


前面两种算法均使用加权移动平均算法做平滑,这种方法的最大问题是:很难发现RTT值上的较大波动,因为被平滑掉了(1 - a比较小,即最新RTT的权重小)。


Linux

2.6采用该算法计算RTO,默认取α =

0.125, β =

0.25, μ =

1, =

4(玄学调参,你懂的)。


TCP使用 滑动窗口 (Sliding Window)做流量控制与 乱序重排 。乱序重排在TCP的重传机制中已经介绍,下面介绍流量控制。


TCP头里有一个字段叫Window(或Advertised Window), 用于接收方通知发送方自己还有多少缓冲区可以接收数据 。发送方根据接收方的处理能力来发送数据,不会导致接收方处理不过来,是谓流量控制。暂且把Advertised Window当做滑动窗口,更容易理解滑动窗口如何完成流量控制,后面介绍拥塞控制时再说明二者的区别。


观察TCP协议的发送缓冲区和接收缓冲区:


假设位置序号从左向右增长(常见的读、写缓冲区设计),解释一下:


据此在接收方计算 AdvertisedWindow ,在发送方计算 EffectiveWindow :


AdvertisedWindow衡量接收方还能接收的数据量,发送方要根据AdvertisedWindow决定接下来发送的数据量上限,即EffectiveWindow(可能为0)。


由于乱序问题的存在,LastByteRcvd可能指向Seq(LastByteSent),而Seq(LastByteAcked +

1)至Seq(LastByteSent -

1)都还在路上 ,即将到达接收方,最好的情况是不丢包(丢包后会重传), 则LastByteRcvd之后、接收缓冲区边界之前的空间就是发送方下一次发送数据的长度上限 (重传不属于下一次发送),因此, AdvertisedWindow = MaxRcvBuffer – (LastByteRcvd - LastByteRead) 。


LastByteRcvd还可能指向Seq(LastByteAcked)(一个新包都没有收到) ,显然AdvertisedWindow的公式不变, 而Seq(LastByteAcked +

1)至Seq(LastByteSent)都还在路上 ,未来将到达接收方,进入接收缓冲区,则“还在路上的Seq(LastByteAcked +

1)至Seq(LastByteSent)”不应超过接收缓冲区的剩余空间AdvertisedWindow(目前等于MaxRcvBuffer),这要求的是上一次发送满足LastByteSent - LastByteAcked ≤ AdvertisedWindow, 那么LastByteSent之后、接收缓冲区剩余空间边界之前的空间就是发送方窗口内剩余可发送数据的长度上限 ,因此, EffectiveWindow = AdvertisedWindow - (LastByteSent - LastByteAcked) 。


以下是一个发送缓冲区的滑动窗口:


上图分为4个部分:


其中,

#2 +

#3 组成了滑动窗口,总大小不超过AdvertisedWindow,二者比例受到接收方的处理速度与网络情况的影响(如果丢包严重或处理速度慢于发送速度,则

#2:#3 会越来越大)。


以下是一个AdvertisedWindow的调整过程,EffectiveWindow随之变化:


上图,我们可以看到一个处理缓慢的Server(接收端)是怎么把Client(发送端)的发送窗口size给降成0的。对于接收方来说,此时接收缓冲区确实已经满了,因此令发送方的发送窗口size降为0以暂时禁止发送是合理的。那么,等接收方的接收缓冲区再空出来,怎么通知发送方新的window size呢?


针对这个问题,为TCP设计了ZWP技术(Zero Window Probe,零窗通告):发送方在窗口变成0后,会发ZWP的包给接收方,让接收方来Ack他的Window尺寸;ZWP的重传也遵循指数回退策略,默认重试3次;如果3次后window size还是0,则认为接收方出现异常,发RST重置连接(<font color="red">部分文章写的是重试到window size正常???</font>)。


注意:只要有等待的地方都可能出现DDoS攻击,Zero Window也不例外。

一些攻击者会在和服务端建好连接发完GET请求后,就把Window设置为0,于是服务端就只能等待进行ZWP;然后攻击者再大量并发发送ZWP,把服务器端的资源耗尽。(<font color="red">

客户端等待怎么耗服务端???</font>)


为什么要进行拥塞控制?假设网络已经出现拥塞,如果不处理拥塞,那么延时增加,出现更多丢包,触发发送方重传数据,加剧拥塞情况,继续恶性循环直至网络瘫痪。可知,拥塞控制与流量控制的适应场景和目的均不同。


拥塞发生前,可避免流量过快增长拖垮网络;拥塞发生时,唯一的选择就是降低流量。主要使用4种算法完成拥塞控制:



算法1、2适用于拥塞发生前,算法3适用于拥塞发生时,算法4适用于拥塞解决后(相当于拥塞发生前)。


在正式介绍上述算法之前,先补充下 rwnd (Receiver Window,接收者窗口)与 cwnd (Congestion Window,拥塞窗口)的概念:


介绍流量控制时,我们没有考虑cwnd,认为发送方的滑动窗口最大即为rwnd。实际上, 需要同时考虑流量控制与拥塞处理,则发送方窗口的大小不超过 min{rwnd, cwnd} 。

下述4种拥塞控制算法只涉及对cwnd的调整,同介绍流量控制时一样,暂且不考虑rwnd,假定滑动窗口最大为cwnd;但读者应明确rwnd、cwnd与发送方窗口大小的关系。


慢启动算法 (Slow Start)作用在拥塞产生之前: 对于刚刚加入网络的连接,要一点一点的提速,不要妄图一步到位 。如下:


因此,如果网速很快的话,Ack返回快,RTT短,那么,这个慢启动就一点也不慢。下图说明了这个过程:


前面说过,当cwnd >= ssthresh(通常ssthresh = 65535)时,就会进入 拥塞避免算法 (Congestion Avoidance): 缓慢增长,小心翼翼的找到最优值 。如下:


慢启动算法主要呈指数增长,粗犷型,速度快(“慢”是相对于一步到位而言的);而拥塞避免算法主要呈线性增长,精细型,速度慢,但更容易在不导致拥塞的情况下,找到网络环境的cwnd最优值。


慢启动与拥塞避免算法作用在拥塞发生前,采取不同的策略增大cwnd;如果已经发生拥塞,则需要采取策略减小cwnd。那么,TCP如何判断当前网络拥塞了呢?很简单,如果发送方发现有Seq发送失败(表现为“丢包”),就认为网络拥塞了


丢包后,有两种重传方式,对应不同的网络情况,也就对应着两种拥塞发生时的控制算法:


可以看到,不管是哪种重传方式,ssthresh都会变成cwnd的一半,仍然是 指数回退,待拥塞消失后再逐渐增长回到新的最优值 ,总体上在最优值(动态)附近震荡。


回退后,根据不同的网络情况,可以选择不同的恢复算法。慢启动已经介绍过了,下面介绍快速恢复算法。


如果触发了快速重传,即发送方收到至少3次相同的Ack,那么TCP认为网络情况不那么糟,也就没必要提心吊胆的,可以适当大胆的恢复。为此设计 快速恢复算法 (Fast Recovery),下面介绍TCP Reno中的实现。



回顾一下,进入快速恢复之前,cwnd和sshthresh已被更新:


然后,进入快速恢复算法:


下面看一个简单的图示,感受拥塞控制过程中的cwnd变化:



6.TCP 流量控制与拥塞控制


TCP(Transmission Control Protocol 传输控制协议)是一种面向连接的、可靠的、基于字节流的。为了通过IP数据报实现可靠性传输,需要考虑很多事情,侧如数据的破坏、丢包、重复以及分片顺序混乱等问题。如不能解决这些问题,也就无从谈起可靠传输。TCP通过校验和、序列号、确认应答、重发控制、连接管理、以及窗口控制等机制来实现可靠性传输。TCP建立连接的实质是,主机A和主机B告知彼此的第一个发送字节的初始序列号,建立连接后对每一个发送的字节都需要以初始序列号为基点进行编号,需要对方来确认每一个字节编号都已经成功接收,双方初始序列号是由操作系统动态生成的随机的值,一般每个TCP 会话都会有不一样的初始序列号,占四个字节。


TCP通过肯定的确认应答(ACK) 实现可靠的数据传输。当发送端将数据发出之后会等待对端的确认应答。如果有确认应答,说明数据已经成功到达对端。反之,则数据丢失的可能性很大。

在一定时间内没有等到确认应答,发送端就可以认为数据已经丢失,并进行重发由此,即使产生了丢包,仍然能够保证数据能够到达对端,实现可靠传输。如果数据被重发之后若还是收不到确认应答,则进行再次发送。此时确认应答的时间将会以2倍、4信的指数函数延长。

达到一定次数后,如果任没有任何确认应答返回,就会判断为网络发生异常,强制关闭连接,并且通知应用通信异常强行终止。


发送端根据自己的实际情况发送数据。但是,接收端可能收到的是一个毫无

关系的数据包又可能会在处理其他问题上花费一些时间。因此在为这个数据包做其他处理时会耗费一些时间,甚至在高负荷的情况下无法接收任何数据。

如此一来,如果接收端将本应该接收的数据丢弃的话,就又会触发重发机制,从而导致网络流量的无端浪费。为了防止这种现象的发生,TCP

提供一种机制可以让发送端根据接收端的实际接收能力控制发送的数据量。这就是所谓的

流控制。它的具体操作是,接收端主机向发送端主机通知自己可以接收数据的大小,于是发送端会发送不超过这个限度的数据。该大小限度就被称作窗口大小。在前面6.4.6 节中所介绍的窗口大

小的值就是由接收端主机决定的。TCP 首部中,专门有一个字段用来通知窗口大小。接收主机将自己可以接收的缓冲区大小放人这个字段中通知给发送端。这个字段的值越大,说明网络的吞吐量越高。不过,接收端的这个缓冲区一旦面临数据溢出时,窗口大小的值也会随之被设置为一个更小的值通知给发送端,从而控制数据发送量。

也就是说,发送端主机会根据接收端主机的指示,对发送数据的量进行控制。这也就形成了一个完整的TCP 流控制(流量控制)。


因为 TCP 的窗口控制,收发主机之间即使不再以一个数据段为单位发送确认应答,也能够连续发送大量数据包。然而,如果在通信刚开始时就发送大量数据,也可能会引发其他问题。

一般来说,计算机网络都处在一个共享的环境。因此也有可能会因为其他主机之间的通信使得网络拥堵。在网络出现拥堵时,如果突然发送一个较大量的数据,极有可能会导致整个网络的瘫痪。TCP 为了防止该问题的出现,在通信一开始时就会通过一个叫做慢启动的算法得出的数值,对发送数据量进行控制

。首先,为了在发送端调节所要发送数据的量,定义了一个叫做“拥塞窗口”的概念。于是在慢启动的时候,将这个拥塞窗口的大小设置为1个数据段发送数据,之后每收到一次确认应答(ACK),拥塞窗口的值就加1MSS。在发送数据包时,将拥塞窗D的大小与接收端主机通知的窗口大小做比较,然后按照它们当中较小那个值,发送比其还要小的数据量。

如果重发采用超时机制,那么拥塞窗口的初始值可以设置为1以后再进行慢启动修正。有了上述这些机制,就可以有效地减少通信开始时连续发包导致的网络拥堵,还可以避免网络拥塞情况的发生。


慢启动算法的基本思想是当TCP开始在一个网络中传输数据或发现数据丢失并开始重发时,首先慢慢的对网路实际容量进行试探,避免由于发送了过量的数据而导致阻塞。主机发送了一个报文后就要停下来等待应答,每收到一个应答,拥塞窗口就增加一段长度,直至等于设定的阈值。

2 个包,这

2 个被 ack 之后再发

4 个包,以此类推,让一次所发的包数量慢慢增加,这就是慢启动。


谈 TCP 离不开 窗口的概念,有 congestion window,receive window,sliding window 等等。window 是以 tcp segment 数量为单位,我们可以说当前 window 值由几个 tcp 包构成,而当我们说 window size 的时候,又是在说一个 window 所包含的字节数。

window size 除了和 tcp segment 的数量有关之外,还和单个 tcp segment 的最大 size 有关,即 MSS 值。发送方的 Window 大小称之为 CWND(congestion window),接收方的 Window 大小称之为 RWND(receiver window,或 advertised window)。

CWND 表示当前发送方可以发送多少个 TCP 包,而 RWND 表示当前接收方还能接收多少个 TCP 包。

是一个发送方本地的值,并不会在网络上传输。而 RWND 则是由接收方告知发送方的,是存在于 TCP 包的协议中,会通过网络传输。

8192 自己数据可能会因为A主机的接收缓冲区满而被丢弃,所以B主机会严格遵守A的 RWND 的大小,如果A主机通告它的window大小为

0,则B主机一定不会发送数据。TCP首部中 Window Size 占两个byte,最大值为65535。


MTU: Maximum Transmit Unit,最大传输单元,即物理接口(数据链路层)提供给其上层(通常是IP层)最大一次传输数据的大小;以普遍使用的以太网接口为例,缺省MTU=1500 Byte,这是以太网接口对IP层的约束,如果IP层有<=1500 byte 需要发送,只需要一个IP包就可以完成发送任务;如果IP层有>

1500 byte 数据需要发送,需要分片才能完成发送,这些分片有一个共同点,即IP Header ID相同。


MSS:Maximum Segment Size ,TCP提交给IP层最大分段大小,不包含TCP Header和 TCP Option,只包含TCP Payload ,MSS是TCP用来限制application层最大的发送字节数。如果底层物理接口MTU=

1500 byte,则 MSS =

1500- 20(IP Header)

-20 (TCP Header) =

1460 byte,如果application 有2000 byte发送,需要两个segment才可以完成发送,第一个TCP segment =

1460,第二个TCP segment =

540。


Persist Timer: 用于周期探测对方receiver window size 是否依然为0的定时器。比如,A主机通告它的window大小为

0,则B一定不会发送数据。B主机也不会一直等下去,如果一直等下去则会发生死锁。为了防止这种情况的死锁发生,发送者使用了一个持续计时器(persiet timer)来周期性的询问接收者是否已增加了窗口。从发送者发出的这些段称为窗口探测(window probes)。


在iOS设备上抓包比较方便,除了常用的,如:Charles、Paw 等软件外,我们还可以使用tcpdump。以下是抓包的步骤:





(待续)

以上就是关于「tcp如何实现拥塞控制」的全部内容,本文讲解到这里啦,希望对大家有所帮助。如果你还想了解更多这方面的信息,记得收藏关注本站~

『★此文为Win10系统之家文②章,未经允许不得转载!』

相关文章

  • tcp如何实现拥塞控制

    tcp如何实现拥塞控制

    1.跪求TCP拥塞控制原理演示系统9.9需要说明的问题。传输控制协议(TransmissionControlProtocol)在这一部分中,我们将讨论TCP拥塞的非常情况,以说明拥塞控制原理的实现,包括添加到传输协议产品中的一些细节。9.1缓慢启...
  • 消防联动如何实现

    消防联动如何实现

    1.门禁系统的消防联动如何做?1、如果你的门禁系统是统一供电的,只要消防模块加一个继电器就可以了,通过继电器控制门禁系统电源,当遇到消防报警时自动就把门禁电源切断了所有门都打开了。2、如果门禁不是统一供电那只有...
  • 内存如何实现双通道

    内存如何实现双通道

    1.怎样设置双通道内存这个不用设置,只要将内存插在正确的插槽中就可以实现双通道内存的模式了,这些规范说明一般都是都在主板的说明上有详细的说明的,建议仔细阅读说明书,主板上一般会有两种颜色的内存卡槽,安装双通...
  • 如何实现自身价值

    如何实现自身价值

    1.怎么实现自己的人生价值一、了解自己并接受自己。自卑的人看不起自己,自恋的人太看重自己,自狂的人不能正视自己,自满的人忽视潜在的自己,惟我独尊的人迷失了自己,自甘堕落的人抛弃了自己,自杀的人接受不了自己,这一...