Last Updated: 2023-05-25 09:18:50 Thursday
-- TOC --
TCP依靠重传来实现在不可靠网络上可靠的数据传输。
TCP实现可靠传输的方式是通过序列号与确认应答。在TCP中,当发送端的数据到达接收主机时,接收端主机会返回一个确认应答消息,表示已收到消息。(实际上,ACK中确认的序列号,表示后续希望接收到的起始序列号)
TCP的重传,包括:
当数据包丢失
,或者ACK丢失
的时候,发送方的定时器超时,没有收到ACK,此时重传数据包。(没有人会重传ACK)
两个概念:
RTT
:Round Trip Time (TCP协议栈实时测量,动态变化)RTO
:Retransmission Time Out (根据RTT设定)当超时时间RTO较大时,重传的发生就慢,丢了老半天才重发,没有效率,性能差。当超时时间RTO较小时,会导致可能并没有丢包就重传,重传的发生虽快,但可能会增加网络拥塞,导致更多的超时,更多的超时导致更多的重发...
精确的测量RTT时间对设定RTO的值是非常重要的,这可让TCP的重传机制更高效。根据上述的两种情况,我们可以得知,超时重传时间 RTO 的值应该略大于报文往返 RTT 的值。
具体计算RTO的值还是很复杂的,参考RFC6289
,涉及到SRTT
概念,平滑的RTT。
RTTM
:RTT Measure,表示本次测量的RTT值。
如果超时重发的数据,再次超时的时候,又需要再次重传的时候,TCP的策略是超时间隔加倍。也就是每当遇到一次超时重传的时候,都会将下一次超时时间间隔设为先前值的两倍
。两次超时,就说明网络环境差,不宜频繁反复发送。
TCP timestamps的设计目的,是为了记录数据包的发送时间,进而计算RTT,过程如下:
TSval
;TSecr
字段;当前时间 - ack中的TSecr时间戳
,就可以得到精确的RTT。这个option结构如下:
Kind: 8 // 标记唯一的选项类型,比如window scale是3
Length: 10 bytes // 标记Timestamps选项的字节数
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
| Kind=8 | Length=10 | TS Value (TSval) | TS ECho Reply (TSecr) |
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 1 4 4
tcp_timestamps必须需要双方都要开启方可生效,这是前提条件,如果有一方没有开启则双方进行数据发送接收时该功能不起作用(比如client端发送的SYN包中带有timestamp选项,但server端并没有开启该选项。则回复的SYN-ACK将不带timestamp选项,同时client后续回复的ACK也不会带有timestamp选项。当然,如果client发送的SYN包中就不带timestamp,双向都将停用timestamp)
如果没有tcp_timestamps,RTT是如何计算的?
但如果发生丢包事件后,该如何计算?
但是RTT应该是 (recv_time - send_time1)呢,还是(recv_time - send_time2)呢?
以上两种方式都不可取!因为无法判断出recv_time对应的ACK是确认第一次数据包的发送还是确认重传数据包。因此TCP协议栈只能选择非重传数据包进行RTT采样。但是当出现严重丢包(比如整个窗口全部丢失)时,就完全没有数据包可以用于RTT采样。这样后续计算SRTT和RTO就会出现较大的偏差。
tcp_timestamps选项很好的解决了上述问题,因为ACK包里面带的TSecr值,一定是触发这个ACK的数据包在发送端发送的时间。不管数据包是否重传都能准确的计算RTT(前提是TSecr遵循RTTM中的计算原则)。
当然timestamp不仅解决了RTT计算的问题,还很好的为PAWS机制提供的信息依据。
PAWS(Protect Againest Wrapped Sequence numbers)
,目的是解决在高带宽,高流速情况下,TCP序号重复排列带来的问题。解决这个问题,也是依赖tcp timestamps。
PAWS的做法是,如果收到的一个TCP数据包的timestamp值小于TS.Recnt(接收方最后确认收到的数据的timestampe),则会丢弃该数据包。
数据中心现在普遍100G互联,对应100G网口,只需要0.34秒,就可以完成4294967296字节的发送。这种LFN长肥网络,时延稍微增大,就可能出现相同seq的还在传输中的tcp报文。
>>> 0xFFFFFFFF*8/10**11
0.3435973836
TCP还有另外一种快速重传(Fast Retransmit)机制,它不以时间为驱动,而是以数据驱动重传。
快速重传的工作方式是当收到三个相同的 ACK 报文时,会在定时器超时之前,直接重传丢失的报文段。由于不再等待超时,因此冠以快速。
快速重传存在一个小问题,发送方在收到三个相同ACK之后,除了ACK直接指向的那个segment,其后的segment是否也要重传呢?发送方无法判断,因此就引入了SACK机制,Selective Acknowledgement,有选择的确认。
这种方式需要在 TCP 头部「选项」字段里加一个 SACK 的东西,它可以将缓存的地图发送给发送方,这样发送方就可以知道哪些数据收到了,哪些数据没收到,知道了这些信息,就可以只重传丢失的数据。
此功能默认开启,对应内核参数net.ipv4.tcp_sack
DSACK,Duplicated SACK,主要作用是使用了 SACK 来告诉「发送方」有哪些数据被重复接收了。
DSACK报文特征是 SACK 中标识的序列号小于ACK确认的序列号,这表示收到了重复数据。此时,发送方可以判断,是对方的ACK报文丢失,或者网络延迟导致超时重发后,对方收到多次,或者网络将发送方的数据包复制了。
此功能默认开启,对应内核参数net.ipv4.tcp_dsack
本文链接:https://cs.pynote.net/net/tcp/202303234/
-- EOF --
-- MORE --