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重传 ...
随机推荐
- Spring security学习笔记(二)
对比两种承载认证信息的方式: session vs token token验证方案: session验证方案: session即会话是将用户信息保存在服务端,根据请求携带的session_id,从服务 ...
- asp.net在一般处理程序里面操作Session
1.要在一般处理程序中获取其他页面的session值,需要引用名空间: using System.Web.SessionState; 2.然后继承一个接口:IRequiresSessionState ...
- C语言实现''student a am i''字符串的正确排列
#define _CRT_SECURE_NO_WARNINGS #include<stdio.h> #include<stdlib.h> int Reverse(char a[ ...
- golang 并发执行函数func类型slice
golang的slice支持func.使用func slice要注意func要完整描述入参出参. 如果需要执行一系列类型相同(入参出参格式相同)的函数,可以动态添加到一个slice里面.range s ...
- 利用cross-entropy cost代替quadratic cost来获得更好的收敛
1.从方差代价函数说起(Quadratic cost) 代价函数经常用方差代价函数(即采用均方误差MSE),比如对于一个神经元(单输入单输出,sigmoid函数),定义其代价函数为: 其中y是我们期望 ...
- BZOJ3436_小K的农场_KEY
题目传送门 差分约束基础,对于每种关系建不同的边,求是否有负环. code: /************************************************************ ...
- TableView滑动时候出现的卡顿现象
分析 UITableView是UIScrollView的子类,因此它可以自动响应滚动事件(一般为上下滚动). 它内部包含0到多个UITableViewCell对象,每个table cell展示各自的 ...
- Ruby数据类型
数字类型 书写整数时,可以根据需要在整数之间任意加入下划线而不会影响数字的值 a=123_45_78 puts a # => 12345678 to_i 截掉小数点之后的数字取整 内置Math模 ...
- 解决CentOS下可以ping通ip ping不通域名
现象:1. ping不通域名,比如 www.qq.com 2. 可以ping通ip,比如 61.135.157.156 分析:1. 查看DNS配置文件 /etc/resolve.conf, 里面的服务 ...
- 利用JSON Schema校验JSON数据格式
最近笔者在工作中需要监控一批http接口,并对返回的JSON数据进行校验.正好之前在某前端大神的分享中得知这个神器的存在,调研一番之后应用在该项目中,并取得了不错的效果,特地在此分享给各位读者. 什么 ...