简介
tcp要解决一个很大的事情,就是要在一个网络根据不同的情况来动态调整自己的发包速度—小则让自己更稳定,大则让整个网络更稳定
tcp的rtt算法
timeout 太大->重发慢->丢了半天重发-> 没效率->性能差
timeout 太小->可能没有丢就重发->重发就快、增加网络拥堵,导致更多超时 (恶性循环导致更多重发)
- RTT:round trip time 就是一个数据包从发出去到回来的时间。这样发送端就可以设置RTO
- RTO:retransmission timeout 重传超时
- SRTT:smoothed RTT 平滑RTT
tcp滑动窗口
tcp必须解决的可靠传输以及包乱序问题,所以tcp必须知道网络实际的数据处理带宽或者数据处理的速度,这样才不会引起网络拥塞,导致丢包
所以tcp,引入了一些技术做网络流控,sliding window是其中的一个技术,tcp里面有一个字段叫做window,又叫Advertised-window,这个字段是接收端告诉发送端自己还有多少缓冲区可以接收数据。于是发送端就可以根据这个接收端的处理能力发送数据,而不会导致接收端处理不过来。
Zero Window
接收端可能没有多余的窗口了,那么当恢复到足够的窗口大小时,怎么通知发送端呢?
解决这个问题使用了Zero Window Probe,缩写为zwp,也就是说,发送端在窗口的值变成0后,会发zwp的包给接收方,让接收方来ack他的window,一般这个值会设置3次,第三次大约30-60s,如果3次过后还是0的话,tcp就会发RST把连接断掉
Silly Window Syndrome
糊涂窗口综合征,接收方太忙了,来不及取走Receive window里的数据,那么,会导致发送方越来越小,到最后,如果接收方有几个字节并告诉发送方,那么发送方会义无反顾发送几个字节。
- MTU:以太网 MTU是1500字节,出去TCP+IP头的40个字节,真正的数据传输为1460,这就是MSS,Maximum Transmission Unit,MTU
- MSS:max segment size 最大tcp包大小
TCP的拥塞处理 – Congestion Handling
TCP不是一个自私的协议,当拥塞发生的时候,要做自我牺牲。就像交通阻塞一样,每个车都应该把路让出来,而不要再去抢路了
拥塞处理的四种算法:
1)慢启动,2)拥塞避免,3)拥塞发生,4)快速恢复
首先,我们来看一下TCP的慢热启动。慢启动的意思是,刚刚加入网络的连接,一点一点地提速,不要一上来就像那些特权车一样霸道地把路占满。新同学上高速还是要慢一点,不要把已经在高速上的秩序给搞乱了。
慢启动的算法如下(cwnd全称Congestion Window):
1)连接建好的开始先初始化cwnd = 1,表明可以传一个MSS大小的数据。
2)每当收到一个ACK,cwnd++; 呈线性上升
3)每当过了一个RTT,cwnd = cwnd*2; 呈指数让升
4)还有一个ssthresh(slow start threshold),是一个上限,当cwnd >= ssthresh时,就会进入“拥塞避免算法”(后面会说这个算法)
所以,我们可以看到,如果网速很快的话,ACK也会返回得快,RTT也会短,那么,这个慢启动就一点也不慢。下图说明了这个过程。
拥塞避免算法 – Congestion Avoidance
前面说过,还有一个ssthresh(slow start threshold),是一个上限,当cwnd >= ssthresh时,就会进入“拥塞避免算法”。一般来说ssthresh的值是65535,单位是字节,当cwnd达到这个值时后,算法如下:
1)收到一个ACK时,cwnd = cwnd + 1/cwnd
2)当每过一个RTT时,cwnd = cwnd + 1
这样就可以避免增长过快导致网络拥塞,慢慢的增加调整到网络的最佳值。很明显,是一个线性上升的算法。
前面我们说过,当丢包的时候,会有两种情况:
1)等到RTO超时,重传数据包。TCP认为这种情况太糟糕,反应也很强烈。1
2
3
4
5
6
7
8
9
10
11sshthresh = cwnd /2
cwnd 重置为 1
进入慢启动过程
2)Fast Retransmit算法,也就是在收到3个duplicate ACK时就开启重传,而不用等到RTO超时。
TCP Tahoe的实现和RTO超时一样。
TCP Reno的实现是:
cwnd = cwnd /2
sshthresh = cwnd
进入快速恢复算法——Fast Recovery
上面我们可以看到RTO超时后,sshthresh会变成cwnd的一半,这意味着,如果cwnd<=sshthresh时出现的丢包,那么TCP的sshthresh就会减了一半,然后等cwnd又很快地以指数级增涨爬到这个地方时,就会成慢慢的线性增涨。我们可以看到,TCP是怎么通过这种强烈地震荡快速而小心得找到网站流量的平衡点的。
快速恢复算法 – Fast Recovery
TCP Reno
这个算法定义在RFC5681。快速重传和快速恢复算法一般同时使用。快速恢复算法是认为,你还有3个Duplicated Acks说明网络也不那么糟糕,所以没有必要像RTO超时那么强烈。 注意,正如前面所说,进入Fast Recovery之前,cwnd 和 sshthresh已被更新:1
2
3
4
5
6
7
8
9
10
11cwnd = cwnd /2
sshthresh = cwnd
然后,真正的Fast Recovery算法如下:
cwnd = sshthresh + 3 * MSS (3的意思是确认有3个数据包被收到了)
重传Duplicated ACKs指定的数据包
如果再收到 duplicated Acks,那么cwnd = cwnd +1
如果收到了新的Ack,那么,cwnd = sshthresh ,然后就进入了拥塞避免的算法了。
如果你仔细思考一下上面的这个算法,你就会知道,上面这个算法也有问题,那就是——它依赖于3个重复的Acks。注意,3个重复的Acks并不代表只丢了一个数据包,很有可能是丢了好多包。但这个算法只会重传一个,而剩下的那些包只能等到RTO超时,于是,进入了恶梦模式——超时一个窗口就减半一下,多个超时会超成TCP的传输速度呈级数下降,而且也不会触发Fast Recovery算法了。
通常来说,正如我们前面所说的,SACK或D-SACK的方法可以让Fast Recovery或Sender在做决定时更聪明一些,但是并不是所有的TCP的实现都支持SACK(SACK需要两端都支持),所以,需要一个没有SACK的解决方案。而通过SACK进行拥塞控制的算法是FACK(后面会讲)