TCP拥塞原理
TCP是典型的point to point的拥塞控制,网络不提供任何的辅助信息,它通过自己的感知进行判断是否发生了拥塞,从而采取相应的措施。
TCP采用发送方所感知到的网络阻塞程度,来控制发送方发送的速率。也就是说如果网络畅通,则增加发送速率,反之降低速率。
对于TCP为了防止拥塞采用的方式我们有如下几点疑问:
- TCP如何限制发送方的发送速率?
- TCP如何通过自己感知线路是否阻塞?
- 当TCP感知线路阻塞,采用何种算法来改变发送速率?
通过这三个问题,我们一起认识一下TCP。
TCP如何限制发送方的发送速率?
TCP的连接的每一端的组成都包含接收缓存、发送缓存和一些变量,其中有cwnd,对发送方的发送速率进行控制,它是根据网络拥塞情况动态控制的。
rwnd是指我能承受得最大报文数量。rwnd不是用来控制网络拥塞的,只表示接收端的能力。
在三次握手的过程中,接收方会将rwnd的值传给发送端。
在一个发送方中发送的数据量不能超过cwnd和rwnd的最小值。即
L a s t B y t e S e n t − L a s t B y t e A c k e d ≤ m i n { c w n d , r w n d } LastByteSent - LastByteAcked ≤ min\{cwnd, rwnd\} LastByteSent−LastByteAcked≤min{cwnd,rwnd}
当TCP感知线路阻塞,采用何种算法来改变发送速率?
- 慢启动
- 拥塞避免
- 快速恢复
慢启动
慢启动简而言之,就是按部就班的提高发送数据包的数量。
当一条TCP连接开始时,cwnd的值通常会设置为1,代表一个MMS值。
那么它的初始速率 ≈ MMS/RTT,例如MSS = 500byte,RTT = 200ms ,初始速率为20kbps ≈ 500byte/200ms。
然后我们通过一个例子来说明cwnd是以何种规律进行增长:
- 连接建立初始化cwnd = 1,代表可以发送一个MSS;
- 发送方接收到1个ACK,cwnd = cwnd+1,cwnd为2;
- 发送方接收到2个ACK,cwnd = cwnd+2,cwnd为4;
- 发送方接收到4个ACK,cwnd = cwnd+4,cwnd为8;
显而易见cwnd呈现指数增长的趋势。但是它总归是不能无限制增长的,那么在何时结束呢?
在了解这个之前我们先来了解以下ssthresh变量
TCP中有一个状态变量ssthresh(慢启动阈值)
- 如果检测到丢包事件,TCO发送方将cwnd重置为1,将ssthresh设置为cwnd/2,并且重新开始【慢启动】;
- 当发送方接收到3个冗余的ACK时,TCP会执行快速重传并进入【快速恢复】;
拥塞避免
一旦进入拥塞避免状态下,并且对于cwnd值的增加将采用非常保守的方法。每个RTT只会将cwnd的值增加1个MSS,即每当收到一个ACK时,cwnd增加1/cwnd。
阻塞发生
当网络出现拥塞,出现数据包丢失,那么就会发生数据包重传,重传机制主要有两种:
- 超时重传
当发生了【超时重传】,则就会使用拥塞发生算法。
ssthresh
设为cwnd/2
,cwnd
重置为1
,接着,就重新开始【慢启动】。
- 快速重传
当发送方接收到三次冗余的ACK,那么就不必等待超时重传,直接进入【快速恢复】。
快速恢复
当丢包事件被3次冗余的ACK事件触发,此时会进入快速恢复状态,因为TCP认为还能收到3个重复的ACK,网络并没有那么糟糕,所有反应也没有那么强烈。
然后进入快速恢复算法:
- 重传丢失的数据包;
- 如果收到新数据的 ACK 后,把 cwnd 设置为cwnd(发生三次冗余ACK时cwnd) / 2 + 接收到冗余ACK的数量 ,
ssthresh
= cwnd(发生三次冗余ACK时cwnd) / 2,原因是该 ACK 确认了新的数据,说明从 duplicated ACK 时的数据都已收到,该恢复过程已经结束,再次进入【拥塞避免】;
拥塞算法示意图
快速重传这里还是有一个疑问,在11次RTT时的cwnd值不理解。之后可以参考【RFC 5681】
巨人的肩膀
30张图解: TCP 重传、滑动窗口、流量控制、拥塞控制发愁
《计算机网络自顶向下方法第7版》