TCP Congestion Control
This RFC is release on 2009.09 obsoletes RFC2581 which is release on 1999.04
1. Introduction
介绍TCP四种交织在一起的拥塞控制算法:
- 慢启动(slow start)
- 拥塞避免(congestion avoidance)
- 快速重传(fast retransmit)
- 快速恢复(fast recovery)
TCP链接需要做什么,在一个长时间停当后,以及确定和澄清一些TCP ACK生成的问题
2. Definition
发送方最大分片大小(Sender Maximum Segment Size, SMSS)1
接收方最大分片大小(Receiver Maximum Segment Size, RMSS)2
最大段(Full Sized Segment)
接收方窗口(Receiver Window, rwnd)
拥塞窗口(Congestion Window, cwnd)3
初始窗口(Initial Window, IW)4
丢失窗口(Lost Window, LW)5
重启窗口(Restart Window, RW)6
飞行尺寸(FlightSize)7
重复确认(Duplicate Acknowledgement):
一个确认被认为是重复的如果:
a. ack的接收者有未完成的(outstanding)数据
b. 到来的ack没有携带数据
c. SYN 和 FIN的标志都没有被设置
d. ack number等于链接最大的ack number
e. 到来的ack广告的窗口大小等于上一次ack广告的窗口大小
f: 使用SACKs(Selective Acknownledgements)的TCP会利用SACK信息判断ack是否重复
3. Congestion Control Algorithm
本文提到的拥塞控制算法使用丢失或者ECN标记作为拥塞发生的信号
3.1 Slow Start and Congestion Avoidance
if SMSS > 2190 (bytes):
IW <= 2*SMSS and IM <= 2*SS(Segment Size)
else if 1095 < SMSS <= 2190:
IW <= 3*SMSS and IW <= 3*SS
ekse:
IW <= 4*SMSS and IW<= 4*SS
建立TCP链接的两个ACK不能用来增加cwnd的大小。等等IW设置详见RFC3390。
ssthresh的初始值可以任意高8
慢启动算法启动标准:cwnd < ssthresh
拥塞避免算法标准:cwnd > ssthresh
二选一都可以:cwnd = ssthresh
在慢启动的时候,每次ACK,cwnd的增加不超过SMSS bytes,当cwnd超过ssthresh
或者拥塞重新被检测到的时候,退出慢启动。
传统TCP实现每次正好增加SMSS,但是我们推荐使用: cwnd += min(N, SMSS)
,N是被新的ACK新确认的未确认数据的大小。9
在拥塞避免的时候,每过一个往返时间10,cwnd可以增加一个full-sized segment11大小;
应该(SHOULD)每一个来回的时间,增加min(N, SMSS)
但是不管怎样,每次cwnd不能增加超过SMSS。
或者每当收到一个不重复的ACK数据报,就增加一个SMSS * SMSS / cwnd
大小12;
还有的方法是增加新的被ACK确认的数据大小,直到cwnd增加到SMSS。13
同样地,当检测到拥塞发生的时候,算法终止。
ssthresh不应该超过max(FlightSize/2, 2*SMSS)
并且,一旦超时,cwnd必须被设为不超过LW,也就是1 full-sized segment。因此在重传被丢弃的包分片后,发送方使用慢启动来增加窗口的大小,从1 full-sized segment到新的ssthresh,在这时拥塞避免算法开始接管。
3.2 Fast Retransmit/Fast Recovery
当乱序的分片到达的时候,TCP接收端应该发送duplicate ack,通知发送方接收到的分片乱序以及应该收到的序列号。
从发送端的视角,当收到重复ack的时候,可能是几个网络原因:
- 分片丢失
- 网络把数据分片重新排序
- ack或网络分片的复制(replication)
In addition, a TCP receiver SHOULD send an immediate ACK when the incoming segment fills in (all or part) of a gap in the sequence space.
TCP发送方基于到来的重复ack,使用快速重传算法来探测和修复丢包。 快速重传算法使用3个重复ack作为直接启动的信号而不需要等重传计时器过时。 在快速是重传算法发送了可能丢失的分片后,快速恢复算法接管新数据的传输,直到一个非重复ack的到来。 不执行慢启动的理由是重复ack的收到不仅表明分片丢失,也表明分片很可能已经离开了网络(在缓冲区中)
快速重传和快速恢复算法一起实现如下:
-
在发送方收到第一个和第二个重复ack时,应该发送一个之前未发送数据的分片14
-
当收到第三个重复的ack时,一个TCP必须把ssthresh设置为不超过
max(FlightSize/2, 2*SMSS)
-
对于每一个额外的重复ACK(在第三个之后)cwnd必须增加SMSS。17
-
当之前未发送的数据可用,并且cwnd新值和接收方窗口允许时,TCP应该发送
1*SMSS
bytes数据。 -
当下一个ack到达并确认之前未确认的数据时,TCP必须将cwnd设置为ssthresh(set by step-2)1819
众所周知,这个算法通常无法有效地从单个数据包飞行中的多次丢失中恢复。
4. Additional Considerations
4.1. Restarting Idle Connections
4.2. Generating Acknowledgments
4.3. Loss Recovery Mechanisms
5. Security Considerations
这个per是什么鬼,还有这么用的,啥意思?并且TCP发送方不能改变cwnd来反映这两个分片。记住,使用SACK的发送方不能发送新数据除非到来的重复ack包含新的SACK信息
-
最大分片的负载大小,不包括TCP/IP headers。这个数值基于MTU、PMTUD、RMSS或者其他因素。 ↩
-
由TCP MSS option决定,如果没有设置,则为536 bytes(TCP安全最大值) ↩
-
限制TCP发送数据的状态变量,TCP发送数据的大小受cwnd和rwnd的双重限制 ↩
-
发送方的三次握手后的拥塞窗口 ↩
-
在重传计时器发现包的丢失时的拥塞窗口的大小 ↩
-
在一个慢启动算法里,在一段停当(idle)的时间后,启动重传时的拥塞窗口大小 ↩
-
已发送,但尚未被ack确认的数据数量,也就是“飞行中“的数据包 ↩
-
Slow Start Threshold ↩
-
这么做是为了增加鲁棒性针对一些行为不端的接收方方通过同一分片的多次的ACK响应(ACK Division),每个ack仅是数据的一部分,每个ACK都会使得发送方窗口增加SMSS,结果使得发送方使用过大的发送窗口 ↩
-
round-trip time, RTT ↩
-
包含当前允许发送的最大数据的分片,比如包含SMSS bytes的数据 ↩
-
当cwnd非常大的时候,比如比
SMSS*SMSS
还要大的时候,应该算为至少1 byte;同时更旧实现会增加一个额外常数,但这是错误的会导致性能损失 ↩ -
缺点是需要维护一个额外的状态变量 ↩
-
On the first and second duplicate ACKs received at a sender, a TCP SHOULD send a segment of previously unsent data per [RFC3042] provided that the receiver’s advertised window allows, the total FlightSize would remain less than or equal to cwnd plus 2*SMSS, and that new data is available for transmission ↩
-
Sender Unknowledge ↩
-
这人为地夸大了cwnd已经离开网络被接收方缓存3个分片 ↩
-
这人为地夸大了cwnd为了反映离开网络的额外分片。为了防止这一机制被接收方滥用,可以限制cwnd扩大的次数为未接收分片的数量。Note: When an advanced loss recovery mechanism (such as outlined in section 4.3) is not in use, this increase in FlightSize can cause equation (4) to slightly inflate cwnd and ssthresh, as some of the segments between SND.UNA and SND.NXT are assumed to have left the network but are still reflected in FlightSize. ↩
-
这被叫做窗口紧缩(deflating) ↩
-
这个ack应该是由step-3的重传引发的。除此之外,这个ack应该确认所有在丢失的分片和收到的第三个重复的分片发送的所有中间分片,如果中间没有丢失 ↩