参考
拥塞控制
当某一路由器在单位时间内接收到的数据量多于其可发送的数据量时,他就把多余的部分存储起来。假如这种情况持续,存储资源将会耗尽,最后路由器不得不丢弃一部分数据,这种现象成为拥塞
。在TCP的两端看到的就是丢包现象,为避免或在一定情况下缓解这种情况,TCP通信的每一方都实行拥塞控制
机制。TCP是全双工通信,每一方都可能发送数据,途经路由器,所以两个发送方(server/client)都应该支持拥塞控制,而上一篇文章的滑动窗口
是接收方主动的一种行为。
说明
- Tahoe 提出了
慢启动
拥塞避免
超时重传
- Reno 在Tahoe的基础上增加了
快速重传
快速恢复
- 谷歌BBR
TCP的发送窗口
wnd = min(rwnd, cwnd*mss)
rwnd:接收方的窗口大小
cwnd:发送方的窗口大小
RTT/RTO
RTT(Round Trip Time)
一个连接的往返时间,即数据发送时刻到接收到确认的时刻的差值;
RTO(Retransmission Time Out)
重传超时时间,即从数据发送时刻算起,超过这个时间便执行重传, RTO协议实现值最小1s
状态切换
当cwnd < ssthresh,执行慢启动
当cwnd > ssthresh, 执行拥塞避免
当cwnd = ssthresh, 执行慢启动/拥塞避免的一种
当超过RTO时间,触发超时重传
当收到3个以上的重复ACK,就进入快速重传
图片来源
TCP 拥塞控制算法
慢启动
慢启动的时机
- 当一个新的TCP连接建立
- 检测到由重传超时(RTO)导致的丢包时
- TCP发送端长时间处于空闲状态
慢启动的目的
使TCP在用拥塞避免探寻更多可用带宽之前得到CWND(拥塞窗口)值,以及帮助TCP建立ACK时钟。
cwnd变化
在慢启动拥塞控制中,TCP快速增加窗口的大小(指数增加),以尽快达到最大传输速率(指数)
每当收到一个ACK,cwnd + 1;
每当过了一个RTT,cwnd = cwnd*2;
不考虑ack丢失的情况,则是2,4,8的指数增加
图片来源
TCP复习拥塞控制
拥塞避免
当达到阈值,迅速调整发送速率
If cwnd < ssthresh then
Each time an Ack is received:
cwnd = cwnd + 1
else /* cwnd > ssthresh */
Each time an Ack is received:
cwnd = cwnd + 1 / [ cwnd ]
endif
每当收到一个ACK,cwnd = cwnd + 1 / cwnd;
每当过了一个RTT,cwnd = cwnd + 1;
超时重传
最为早期的TCP Tahoe算法使用下面的算法,但效率较差
- 由于发生丢包,将慢启动阈值ssthresh设置为当前cwnd的一半,即ssthresh = cwnd / 2.
- cwnd重置为1
- 进入慢启动过程
图片来源
TCP复习拥塞控制
快速重传
Reno算法在超时重传的基础上,对于收到三次以上的重复ack后,直接进行处理,不用等待定时器超时(RTO),并且处理策略也进行了优化
- cwnd大小缩小为当前的一半
- ssthresh设置为缩小后的cwnd大小
- 然后进入快速恢复算法Fast Recovery。
快速恢复
Reno引入了快速恢复算法
- cwnd = cwnd + 3 * MSS,加3 * MSS的原因是因为收到3个重复的ACK。
- 重传DACKs(重复确认)指定的数据包。
- 如果再收到DACKs,那么cwnd大小增加一。
- 如果收到新的ACK,表明重传的包成功了,那么退出快速恢复算法。将cwnd设置为ssthresh,然后进入拥塞避免算法。
图片来源
TCP 拥塞控制算法
收到第三个重复ack后
ssthresh=cwnd=6/2=3(快速重传)
cwnd=3+3=6(快速恢复)
如果继续收到ack5,则cwnd++
重传pkt5数据包
如果收到新的ack,则cwnd=ssthresh,进入拥塞避免
快速恢复cwnd>ssthresh属于裸奔
状态,是特事特办,在重传的同时可以发送新的包,在重传结束,需要快速切换回拥塞避免状态