Noa*_*ick 16 networking tcp network-protocols congestion-control
我一直在阅读"计算机网络:自上而下的方法"一书,并遇到了一个我似乎不理解的问题.
正如我所读到的,TCP拥塞控制有三种状态:慢启动,拥塞避免和快速恢复.我很了解慢启动和拥塞避免,但快速恢复非常模糊.该书声称TCP的行为方式如下:(cwnd =拥塞窗口)
我们来看下面的图表:
我们可以看到,在第16轮,发送方发送了42个段,并且因为拥塞窗口大小减半(+3),我们可以推断出有3个重复ACK.这个问题的答案声称 16到22之间的轮次处于拥塞避免状态.但为什么不快速恢复?我的意思是,在三次重复的ACK之后,TCP进入快速恢复并且每隔一次重复的ACK都应该增加拥塞窗口.为什么图表没有表示?我能想到的唯一合理的解释是,在这个图中,只有三个重复的ACK,并且之后收到的ACK不是重复的.
即使是这种情况,如果有超过3个重复的ACK,图表将如何显示?**
**我一直在努力回答这个问题很长一段时间.我会很高兴回复,谢谢!
更新这里是图像.我认为轮次定义为窗口中的所有段都被确认.在照片中,圆圈显示为圆圈.
为什么cwnd在快速恢复状态下呈指数级增长?(在图像中我偶然写了而不是指数地写)
Fil*_*ves 13
更新:我的原始答案与解决方案一致,但仔细考虑之后,我认为解决方案是错误的.这个答案是从头开始重写的; 请仔细阅读.我说明为什么在时间T = 16时进入快速恢复以及为什么协议保持在那里直到T = 22.图中的数据支持我的理论,所以我非常肯定解决方案是完全错误的.
让我们从直接设置开始:慢启动以指数方式增长; 拥塞避免线性增长,快速恢复线性增长,即使它使用与慢启动相同的公式来更新值cwnd
.
请允许我澄清一下.
为什么我们说慢启动cwnd
呈指数级增长?
注意,每收到的ACKcwnd
都会增加MSS
字节数.
我们来看一个例子吧.假设cwnd
初始化为1 MSS(MSS的值通常为1460字节,因此实际上这意味着cwnd
初始化为1460).此时,由于拥塞窗口大小只能容纳1个数据包,因此在确认此数据包之前,TCP不会发送新数据.假设ACK没有丢失,这意味着每RTT秒传输大约一个新数据包(回想一下RTT是往返时间),因为我们需要(1/2)*RTT来发送数据包,并且( 1/2)*ACK用于到达ACK.
因此,这导致大致MSS/RTT bps的发送速率.现在,请记住,每个ACK
,cwnd
增加MSS
.因此,一旦第一个ACK
到达,cwnd
变为2*MSS
,所以现在我们可以发送2个数据包.当这两个数据包被确认时,我们增加cwnd
两次,所以现在cwnd
是4*MSS
.大!我们可以发送4个数据包.这4个数据包被确认,所以我们增加了cwnd
4倍!所以我们有cwnd = 8*MSS
.然后我们得到cwnd = 16*MSS
.我们基本上cwnd
每个RTT秒加倍(这也解释了为什么cwnd = cwnd+MSS*(MSS/cwnd)
在拥塞避免导致线性增长)
是的,这很棘手,公式cwnd = cwnd+MSS
很容易让我们相信它是线性的 - 一种常见的误解,因为人们经常忘记这适用于每个已确认的数据包.
注意,在现实世界中,发送4个分组不一定产生4个ACK.它可能ACK
仅生成1 ,但由于TCP使用累积ACK,因此该单个ACK
仍然确认4个数据包.
为什么Fast Recovery是线性的?
该cwnd = cwnd+MSS
公式适用于慢启动和避免拥塞.有人会认为这导致两种状态都会引发指数增长.但是,快速恢复在不同的上下文中应用该公式:当收到重复的ACK时.其中存在差异:在慢速启动时,一个RTT确认了一大堆段,每个确认段对+ 1MSS贡献了新值cwnd
,而在快速恢复中,重复的ACK正在浪费RTT以确认丢失了单段,所以我们不是cwnd
每个RTT秒更新N次(其中N是传输的段数),我们正在为一个丢失的段更新cwnd
一次.所以我们只用一个段"浪费"一次往返,所以我们只增加cwnd
1.
关于拥塞避免 - 我将在下面分析图表时解释这一点.
分析图表
好的,让我们看看该图中到底发生了什么.你的照片在某种程度上是正确的.我先说清楚一些事情:
cwnd
从一个圆圈到下一个圆圈呈指数增长--1,2,4,8,16 ......cwnd
减半.这不是图表显示的:cwnd
从T = 6到T = 7 ,值不会减少到一半.好的,现在让我们看看每轮都会发生什么.请注意,图表中的时间单位是圆形.因此,如果在时间T = X,我们发送N个段,则假设在时间T = X + 1,这些N个段已被确认(假设它们当然没有丢失).
还要注意我们如何ssthresh
通过查看图表来判断价值.在T = 6时,cwnd
停止指数增长并开始线性增长,其值不会减少.从慢启动到不涉及减少的另一个状态的唯一可能的转变cwnd
是到拥塞避免的过渡,这在拥塞窗口大小等于时发生ssthresh
.我们可以在图中看到,当cwnd
32为32 时,会发生这种情况.因此,我们立即知道它ssthresh
被初始化为32 MSS.这本书在第276页(图3.53)显示了一个非常相似的图表,作者得出了类似的结论:
在正常情况下,这就是发生的情况 - 当TCP首次从指数增长切换到线性增长而不减小窗口大小时,总是因为它达到阈值并切换到拥塞避免.
最后,假设MSS
至少有1460个字节(通常是1460个字节,因为以太网有MTU = 1500字节,我们需要考虑TCP + IP头的大小,它们一起需要40个字节).这是看的时候很重要cwnd
超过ssthresh
,因为cwnd
的单位MSS
和ssthresh
以字节为单位表示.
所以我们走了:
T = 1:
cwnd = 1 MSS; ssthresh = 32 kB
传输1段
T = 2
1段确认
cwnd + = 1; ssthresh = 32 kB
cwnd的新价值:2
传输2段
T = 3
承认2个部分
cwnd + = 2; ssthresh = 32 kB
cwnd的新价值:4
传输4段
T = 4
承认了4个细分市场
cwnd + = 4; ssthresh = 32 kB
cwnd的新价值:8
传输8段
T = 5
承认了8个细分市场
cwnd + = 8; ssthresh = 32 kB
cwnd的新价值:16
传输16段
T = 6
承认了16个细分市场
cwnd + = 16; ssthresh = 32 kB
cwnd的新值:32
传输32段
好的,让我们看看现在发生了什么.cwnd
到达ssthresh
(32*1460 = 46720字节,大于32000).是时候改用拥塞避免了.注意这些值如何cwnd
在数轮之间呈指数增长,因为每个确认的数据包对新值的贡献为1 MSS cwnd
,并且在下一轮中确认发送的每个数据包.
切换到拥塞避免
现在,cwnd
不会成倍增加,因为每个人ACK
都不会再贡献1个MSS.相反,每个人都有所ACK
贡献MSS*(MSS/cwnd)
.因此,例如,如果MSS
是1460个字节,cwnd
是14600个字节(以便在每一轮的开始,我们正在发送10个段),那么每个ACK
(假设一个ACK
每段)将增加cwnd
由 1/10
MSS(146个字节).由于我们发送了10个分段,并且在本轮结束时我们假设每个分段都被确认,然后在回合结束时我们增加cwnd
了10 * 1/10 = 1
.换句话说,每个段贡献一小部分,cwnd
使得我们cwnd
每轮增加1 MSS.所以现在每轮增加cwnd
1而不是传递/确认的段数.
我们将保持拥塞避免,直到检测到一些丢失(3个重复的ACK或超时).
现在,让时钟恢复......
T = 7
承认了32个细分市场
cwnd + = 1; ssthresh = 32 kB
cwnd的新价值:33
传输33段
请注意cwnd
,即使确认了32个段,每个段也会从32个变为33个(ACK
因此每个段贡献1/32).如果我们在缓慢的开始,如在T = 6,我们会有cwnd += 32
.这个新值cwnd
也与我们在时间T = 7时在图中看到的一致.
T = 8
承认了33个细分市场
cwnd + = 1; ssthresh = 32 kB
cwnd的新价值:34
传输34段
T = 9
承认了34个细分市场
cwnd + = 1; ssthresh = 32 kB
cwnd的新价值:35
传输35个段
请注意,这与图表一致:在T = 9时,我们有cwnd = 35
.这种情况一直持续到T = 16 ......
T = 10
承认了35个细分市场
cwnd + = 1; ssthresh = 32 kB
cwnd的新价值:36
传输36段
T = 11
承认了36个细分市场
cwnd + = 1; ssthresh = 32 kB
cwnd的新价值:37
传输37段
T = 12
承认了37个细分市场
cwnd + = 1; ssthresh = 32 kB
cwnd的新价值:38
传输38段
T = 13
承认了38个细分市场
cwnd + = 1; ssthresh = 32 kB
cwnd的新价值:39
传输39个段
T = 14
承认了39个细分市场
cwnd + = 1; ssthresh = 32 kB
cwnd的新价值:40
传输40个段
T = 15
承认了40个细分市场
cwnd + = 1; ssthresh = 32 kB
cwnd的新价值:41
传输41段
T = 16
承认了41个细分市场
cwnd + = 1; ssthresh = 32 kB
cwnd的新价值:42
传输42段
暂停
现在发生了什么?该图显示拥塞窗口大小减小到其大小的大约一半,然后它再次成为线性增长.唯一的可能是有3个重复的ACK,协议切换到快速恢复.该图显示,它不切换至缓慢启动,因为这会带来cwnd
下降到1.所以唯一可能的过渡是快速恢复.
通过进入快速恢复,我们得到ssthresh = cwnd/2
.记住cwnd
的单位MSS
和ssthresh
以字节为单位,我们必须要小心这一点.因此,新的价值是ssthresh = cwnd*MSS/2 = 42*1460/2 = 30660
.
再次,这与图表对齐; 通知,ssthresh
在不久的将来,当cwnd
小于30 时会被击中(回想一下,当MSS = 1460时,该比率不完全是1:1,这就是为什么我们即使拥堵窗口大小略低于30也达到了阈值).
切换到拥塞避免也会引起新的价值的cwnd
是ssthresh+3MSS = 21+3 = 24
(记得要小心单位,在这里我转换ssthresh
成MSS再次因为我们的价值观cwnd
在MSS计数).
截至目前,我们正在避免拥堵,T = 17,ssthresh = 30660 bytes
并且cwnd = 24
.
在进入T = 18时,可能会发生两件事:要么我们收到重复的ACK,要么我们没有.如果我们不这样做(所以这是一个新的ACK),我们将过渡到拥塞避免.但这会cwnd
降低到ssthresh
21 的值.这与图表不匹配 - 图表显示cwnd
线性增长.此外,它不会切换到慢启动,因为这会cwnd
降低到1.这意味着不会留下快速恢复,我们正在获得重复的ACK.这发生在时间T = 22之前:
T = 18
到达重复的ACK
cwnd + = 1; ssthresh = 30660字节
cwnd的新价值:25
T = 19
到达重复的ACK
cwnd + = 1; ssthresh = 30660字节
cwnd的新价值:26
T = 20
到达重复的ACK
cwnd + = 1; ssthresh = 30660字节
cwnd的新价值:27
T = 21
到达重复的ACK
cwnd + = 1; ssthresh = 30660字节
cwnd的新价值:28
T = 22
到达重复的ACK
cwnd + = 1; ssthresh = 30660字节
cwnd的新价值:29
**暂停**
我们仍处于快速恢复状态,现在,突然cwnd
降至1.这表明它再次进入缓慢启动状态.新的价值ssthresh
将是29*1460/2 = 21170
和cwnd = 1
.这也意味着尽管我们努力重新传输该细分市场,但仍有一段时间.
T = 23
cwnd = 1; ssthresh = 21170字节
传输1段
T = 24
1段确认
cwnd + = 1; ssthresh = 21170字节
cwnd的新价值:2
传输2段
T = 25
承认2个部分
cwnd + = 2; ssthresh = 21170字节
cwnd的新价值:4
传输4段
T = 26
承认了4个细分市场
cwnd + = 4; ssthresh = 21170字节
cwnd的新价值:8
传输8段
...
我希望这说清楚.
归档时间: |
|
查看次数: |
9524 次 |
最近记录: |