TCP有四个要点,一是连接,二是可靠传输,三是数据按到达,四是端到端的流量控制。注意TCP在设计的时候只是保证了这四点。这时候虽然有些问题,但是很简单。但是,更大的问题很快就会出现,需要考虑IP网络相关的问题,比如公平性。效率,所以加了拥塞控制,让TCP变成现在这个样子。为什么要进行拥塞控制要回答这个问题,首先要知道TCP什么时候发生拥塞。TCP作为端到端的传输层协议,不关心双方在物理链路上会经过多少个路由器和交换机,也不关心报文传输的路径和下一个路径。这是IP层应该考虑的。然而在实际网络应用中,TCP连接的两端可能远隔千山万水,数据包也需要经过多个路由器和交换机的转发。开关设备的性能不是无限的!当多个入接口的报文从同一个出接口转发时,如果出接口的转发速率达到限制,报文将开始在交换设备入接口的缓冲队列中堆积。但是,队列的长度也是有限的。当队列满时,后续的输入包只能被丢弃。对于TCP的发送端,看到的是发送超时丢失。网络资源由每个连接共享,使每个人都可以完成数据传输。因此,TCP在感知到传输拥塞时需要降低发送速率,等待拥塞解决。如何进行拥塞控制Congestionwindowcwnd首先需要明确的是,TCP是在发送端进行拥塞控制的。TCP为每个连接准备了一个变量cwnd1来记录拥塞窗口的大小,它限制了本地TCP可以向network2发送的最大数据包数。显然,该值越大,连接的吞吐量越高,但也更容易造成网络拥塞。所以TCP拥塞控制的本质就是根据丢包情况调整cwnd,让传输吞吐率尽可能的大!而且不同的拥塞控制算法对cwnd的调整方式不同!注1:本文中的cwnd是根据发送方的最大报文段长度SMSS来的。注2:这个数字也受对端通告的窗口大小的限制。Linux用户可以使用ss--tcp--info查看链路拥塞控制算法的cwnd值TCP从诞生之日起就有多种拥塞控制算法,到现在还在不断提出新的!其中,TCPTahoe(1988)和TCPReno(1990)是最早出现的两种算法。虽然看起来很古老,但Reno算法直到现在仍然被广泛使用。Tahoe在Tahoe的基础上提出了1)慢启动,2)拥塞避免,3)快速重传Reno增加了4)快速恢复。Tahoe算法的基本思想是在没有丢包的情况下,先设置一个合理的初始窗口值,慢慢增大窗口大小,逐渐逼近吞吐量的上界。当出现丢包时,迅速缩小窗口大小,等待拥塞消除。Tahoe拥塞避免(congestion-avoidance)当我们理解拥塞控制算法时,我们可以假设发送方一次性发送出整个拥塞窗口大小的消息,然后等待响应。Tahoe使用AdditiveIncrease,MultiplicativeDecrease(AIMD)的方法来完成拥塞窗口的缓慢增加和快速减少:发送方发送整个窗口的数据:如果没有丢包,则cwnd=cwnd+1如果有a丢包,那么cwnd=cwnd/2为什么丢包后除以2呢?这里的2其实是一个折衷值!用下面的例子来解释吧!物理传输路径会有延迟。这种延迟也让传输链路有了传输容量(transitcapacity)的概念。同时,我们称交换设备的队列容量为队列容量(queuecapacity)。例如下面的连接,传输容量为M,队列容量为N。当cwnd小于M时,R的队列将不会被使用,此时不会发生拥塞;当cwnd继续增加的时候,R的队列就会开始被使用,其实已经是阻塞了!但是A是感知不到的,因为没有丢包!当cwnd继续增加到M+N时,如果cwnd再次增加,就会出现丢包。这时候拥塞控制算法需要减少cwnd,那么应该减少多少呢?当然,减少到不使用R的缓存,或者使cwnd=M,可以快速解除阻塞。这是最理想的情况!实际情况是A并不知道M和N有多大(或者是什么关系),它只知道当cwnd超过M+N时,就会出现丢包!所以我们妥协,假设M=N,那么当cwnd=2N是丢包的临界点,为了解封,让cwnd=cwnd/2=N可以解封3!所以cwnd的变化趋势如上,图中上方的红色曲线表示丢包。这种稳定状态也称为拥塞避免阶段(congestion-avoidancephase)。在实际的算法实现中,拥塞避免阶段的cwnd在每次收到ACK时更新:cwnd+=1/cwnd。如果你仔细计算一下,你会发现这比更新整个窗口的cwnd+=1略显不足!注3:后面会提到,此时Tahoe会将cwnd设置为1,然后快速恢复到cwnd/2Tahoe慢启动(SlowStart)Tahoe需要选择一个cwnd的初始值,但是发送方并不知道cwnd是多少是合适的。所以我们只能从1开始加到4,如果这个时候开始加法增加,那就太慢了。例如,假设一个连接将发送5050条MSS大小的消息,根据加法增加,将需要100RTT才能完成传输(1+2+3+...+100=5050)。因此,Tahoe和Reno使用称为慢启动的算法快速增加cwnd。即只要不丢包,每次发送一整窗口的数据,cwnd=2Xcwnd。也就是说,在慢启动阶段(slow-startphase),当发送方收到ACK,令cwnd=cwnd+1注4RFC2581已经允许cwnd的初始值最大为2,RFC3390已经允许cwndcwnd的初始值最大为4,RFC6928已经允许cwnd的初始值最大为10。那么,慢启动阶段什么时候停止呢?或者什么时候进入前面的拥塞避免阶段?Tahoe算法定义了一个慢启动阈值(slow-startthreshold)变量。当cwnd
