TCP系列40—拥塞控制—3、慢启动和拥塞避免概述
本篇中先介绍一下慢启动和拥塞避免的大概过程,下一篇中将会给出多个linux下reno拥塞控制算法的wireshark示例,并详细解释慢启动和拥塞避免的过程。
一、慢启动(slow start)
一个TCP连接启动的时候并不知道cwnd应该取多大的值适合当前的网络状况,因此TCP发送方会从一个较小的初始值指数抬升cwnd到某一个值,这个cwnd抬升的过程就叫做慢启动。除了初始建立tcp连接(SYN包交换后)后的数据发送使用慢启动外,在TCP超时重传、TCP空闲一段时间后重新开始数据发送这些场景下也会触发慢启动过程。
在TCP连接的慢启动过程中,cwnd的初始值为IW(initial window)。IW的原始值为1个SMSS的大小,但是RCF5681协议允许IW按照如下设置(RFC3390中也有详细的设置原则描述和讨论)
SMSS>2190bytes时,IW=2*SMSS 且最大不能超过2个报文段
2190bytes>=SMSS>1095bytes时,IW=3*SMSS 且最大不能超过3个报文段
其他场景下,IW=4*SMSS 且最大不能超过4个报文段
为了接下来描述方便,我们取cwnd=IW=1*SMSS。其中SMSS一般为min(接收方的MSS,扣除header的path MTU)。假设没有丢包发生并且接收方每接收一个包就反馈一个ACK,则每当发送方接收到一个Good ACK的时候,发送方就会调整cwnd=cwnd+min(N,SMSS),其中N表示这个Good ACK反馈确认的接收方新收到的数据量,单位为byte。比如之前收到的最大ACK Number为1000,新收到的Good ACK中ACK Number为2000,则这个Good ACK指示接收方新收到了1000byte的数据,这种场景下N=1000bytes。当发送端以SMSS大小发送数据报文,接收方对每个报文都立即回复ACK的时候,简洁的整理以下算法流程如下
1)连接建好的开始先初始化cwnd = 1,表明可以传一个SMSS大小的数据。
2)每当收到一个ACK,cwnd++; 呈线性上升
3)每当过了一个RTT,cwnd = cwnd*2; 呈指数让升
4)还有一个慢启动门限ssthresh(slow start threshold),是一个上限,当cwnd >= ssthresh时,就会进入拥塞避免。
5)当遇到RTO超时重传时会触发cwnd和ssthresh的调整,ssthresh=max(cwnd/2, 2),cwnd=1,然后重新开始慢启动过程。
连接初始建立场景下可以设置ssthresh为一个很大的值,然后开始慢启动流程后,直到发送速率一直增大,最终触发RTO超时或者快速重传,然后根据cwnd设置ssthresh从而得到一个有效的ssthresh值。这里我们暂时只考虑RTO超时场景,后面会介绍快速重传、ECN等场景下的处理。
慢启动流程示意图如下

从上图可以看到每过一个RTT,cwnd就会增加一倍,因此TCP的慢启动是指数增长的(慢启动的"慢"是指TCP的发送端不能直接以接收方通告的awnd为窗口进行发送,而要有一个启动过程,因此叫做慢启动)。当发送端使用delay ACK时,慢启动的cwnd仍然是指数增长的,但是增长速度会稍微慢一些。因此有一些TCP实现会等TCP连接完成慢启动过程后在使用delay ACK,例如linux中在连接初始建立时候的quick ACK模式。
二、拥塞避免(congestion avoidance)
从慢启动可以看到,cwnd可以很快的增长上来,从而最大程度利用网络带宽资源,但是cwnd不能一直这样无限增长下去,一定需要某个限制。TCP使 用了一个叫慢启动门限(ssthresh)的变量,当cwnd超过该值后,慢启动过程结束,进入拥塞避免阶段。慢启动门限 ssthresh 的用法如下:
当 cwnd < ssthresh 时,使用慢开始算法。
当 cwnd > ssthresh 时,停止使用慢开始算法而改用拥塞避免算法。
当 cwnd = ssthresh 时,既可使用慢开始算法,也可使用拥塞避免算法。
拥塞避免算法的思路是让拥塞窗口 cwnd 缓慢地增大,假设cwnd=k*SMSS,当发送端收到一个包的ACK反馈的时候,按照cwnd=cwnd+(1/k)*SMSS。这样每经过一个RTT发送k个数据包的时候,cwnd增长了大约一个SMSS,通常上我们即描述为每经过一个往返时间 RTT 就把发送方的拥塞窗口 cwnd 加 1,使拥塞窗口 cwnd 按接近线性规律缓慢增长。这种增长方式叫做“加法增大”(Additive Increase)。另外当接收方使用delay ACK时,cwnd的增长仍然是接近线性的,只不过增长速度相对慢一些。总结如下
1)收到一个ACK时,cwnd = cwnd + 1/cwnd
2)当每过一个RTT时,cwnd = cwnd + 1
简单图示如下

无论在慢开始阶段还是在拥塞避免阶段,在Tahoe版本中,只要发送方判断网络出现拥塞(其根据就是触发了快速重传或者RTO重传),就要更新慢开始门限 ssthresh =max(flight size/2,2*SMSS),因为一般情况下flight size接近或者等于cwnd,所以也可以认为更新ssthresh =max(cwnd/2,2*SMSS),这个过程叫做“乘法减小”(Multiplicative Decrease)。加法增大与乘法减小常常合称为AIMD算法。另外,Windows中的实现据传为ssthresh =max(min(cwnd, awnd)/2, 2*SMSS) 。总结如下
- sshthresh = max(cwnd/2,2*SMSS) (一般来说当发生丢包的时候 cwnd一般都是大于等于4的,所以也可以认为ssthresh =max(cwnd/2,2*SMSS)=cwnd/2)
- cwnd 重置为 1
- 进入慢启动过程
三、拥塞控制示例
上面所讲解的慢启动和拥塞避免就是Tahoe版本的TCP实现,这个也是带有拥塞控制功能的第一个TCP版本,随着4.2 BSD UNIX一起发布。同时Tahoe版本是支持快速重传的,但是Tahoe版本对于快速重传和RTO重传的处理是一致(Reno版本的TCP对于快速重传和RTO重传的处理略有不同,接下来的拥塞控制系列会讲解)。
下面我们看一个图解示例以加深理解,下图中横坐标以RTT为单位,纵坐标cwnd用报文段为单位(可以看成SMSS大小为单位),我们假设接收端通告的窗口足够大,只考虑cwnd的变化。

分别对图中标示的箭头做如下说明
1、在标号为1的箭头处,TCP初始连接进行数据交换,开始慢启动,初始cwnd=IW=1,ssthresh=16,在传输轮次0-4阶段进行慢启动过程,cwnd按照1-2-4-8-16的顺序进行指数增长
2、在标号为2的箭头处,cwnd=16=ssthresh,此时触发拥塞避免过程,开始线性增长,在传输轮次4-12阶段,cwnd按照16-17-18-19-20-21-22-23-24进行线性增长。
3、在标号为3的箭头处,TCP发生了RTO重传,认为网络发生拥塞,于是设置ssthresh=cwnd/2=12,cwnd=1重新进行慢启动过程
4、在标号为4的箭头处,TCP从cwnd=1开始重新开始慢启动过程
5、在标号为5的箭头处,当 cwnd = 12 时改为执行拥塞避免算法,拥塞窗口按按线性规律增长,每经过一个往返时延就增加一个 MSS 的大小。
附件列表
TCP系列40—拥塞控制—3、慢启动和拥塞避免概述的更多相关文章
- TCP系列41—拥塞控制—4、Linux中的慢启动和拥塞避免(一)
一.Linux中的慢启动和拥塞避免 Linux中采用了Google论文的建议把IW初始化成了10了.在linux中一般有三种场景会触发慢启动过程 1.连接初始建立发送数据的时候,此时cwnd初始化为1 ...
- TCP系列54—拥塞控制—17、AQM及ECN
一.概述 ECN的相关内容是在RFC3168中定义的,这里我简单描述一下RFC3168涉及的主要内容. 1.AQM和RED 目前TCP中多数的拥塞控制算法都是通过缓慢增加拥塞窗口直到检测到丢包来进行慢 ...
- TCP系列44—拥塞控制—7、SACK关闭的快速恢复
) return; delta = ssthresh - in_flight; prr_delivered += newly_acked_sacked; if (delta < 0 ...
- TCP系列43—拥塞控制—6、Congestion Window Validation(CWV)
一.概述 在RFC2861中,区分了TCP连接数据传输的三种状态 After sending a data segment: If tcpnow - T_last >= RTO ...
- TCP系列39—拥塞控制—2、拥塞相关算法及基础知识
一.拥塞控制的相关算法 早期的TCP协议只有基于窗口的流控(flow control)机制而没有拥塞控制机制,因而易导致网络拥塞.1988年Jacobson针对TCP在网络拥塞控制方面的不足,提出了& ...
- TCP系列55—拥塞控制—18、其他拥塞控制算法及相关内容概述
前面我们演示分析了100+个wireshark TCP实例,拥塞控制部分也介绍常见的拥塞处理场景以及4种拥塞撤销机制,但是我们一直使用的都是reno拥塞控制算法.实际上拥塞控制发展到今天已经有了各种各 ...
- TCP系列42—拥塞控制—5、Linux中的慢启动和拥塞避免(二)
在本篇中我们继续上一篇文章wireshark的示例讲解,上一篇介绍了一个综合示例后,本篇介绍一些简单的示例,在读本篇前建议先把上一篇读完,为了节省篇幅,本篇只针对一些特殊的场景点报文进行讲解,不会像上 ...
- TCP系列51—拥塞控制—14、TLP、ER与拥塞控制
一.概述 这里的重点是介绍TLP.ER与拥塞控制并不是介绍TLP和ER本身,因此TLP和ER的详细内容请翻前文. 在TLP与拥塞控制的交互中有几个点需要注意 1.TLP触发的重传后,TCP仍然处于Op ...
- TCP系列48—拥塞控制—11、FRTO拥塞撤销
一.概述 FRTO虚假超时重传检测我们之前重传章节的文章已经介绍过了,这里不再重复介绍,针对后面的示例在说明两点 1.FRTO只能用于虚假超时重传的探测,不能用于虚假快速重传的探测. 2.延迟ER重传 ...
随机推荐
- Thinkphp5 对接百度云对象存储 BOS (上传、删除)
首先下载SDK包可以在 官网下载,或者在项目根目录使用composer . composer require baidubce/bce-sdk-php 压缩包里面有五个文件,实际运用到只有两个,然后放 ...
- PHP基础3--文件加载-错误处理
主要: 1-文件加载 2-错误处理 文件加载 文件加载语句 1) 4个文件加载语句:include, require, include_once, require_once 2) 使用形式 ...
- 使用PHPExcel 读取 表格数据, 发现中文全变成 FALSE??
出现这样的情况, 你可以看看你的表格是不是 CSV 格式的. 如果是, 那就赶紧另保存为 xls.xlsx 等格式的表格 . 因为 PHPExcel 对 Csv 的表格不感冒....
- 帆软SQL报异常:多表连接的时候出现错误:未明确定义列
我刚开始的代码: select dm_veh_jdcgz_mx.DAY_ID ,--日期 dm_veh_jdcgz_mx.GLBM ,--管理部门ID dm_veh_jdcgz_mx.SFZMHM , ...
- python网络编程之协程
本节的主题是基于单线程来实现并发,即只用一个主线程(很明显可利用的cpu只有一个)情况下实现并发,为此我们需要先回顾下并发的本质:切换+保存状态 cpu正在运行一个任务,会在两种情况下切走去执行其他的 ...
- 北京Uber优步司机奖励政策(11月2日~11月8日)
用户组:优步北京人民优步A组(适用于11月2日-11月8日) 滴快车单单2.5倍,注册地址:http://www.udache.com/ 如何注册Uber司机(全国版最新最详细注册流程)/月入2万/不 ...
- IOI 2017 Practice Contest mountains
Mountains 题面 题意: 选最多的点使得两两看不见. 分析: 分治,solve(l,r)为区间[l,r]的答案.那么如果不选最高点,分治两边即可,选了最高点,那么在最高点看不见的区间里分治. ...
- LeetCode: 58. Length of Last Word(Easy)
1. 原题链接 https://leetcode.com/problems/length-of-last-word/description/ 2. 题目要求 给定一个String类型的字符串,字符串中 ...
- Python之数据处理
一.CSV数据处理 CSV文件格式:逗号分隔值(Comma-Separated Value,CSV,有时也称为字符分隔值,因为分隔符也可以不是逗号),其文件以纯文本形式存储表格数据(数字和文本).纯文 ...
- sqlite helper
//-------------------------------------------------------------------------- // // Copyright (c) BUS ...