原文:
TCP重点系列之sack介绍
发表于 2017-03-01 | 分类于 TCP/IP | |
在早期的TCP拥塞控制中都是通过收到duplicate ack(默认3个)来trigger fast retransmition,但是当有多个丢包时,这样每次重传一个包,收到重传包的ack后,再通过 duplicate ack trigger retransmit下一个包,容易造成timeout,于是有人提出了sack来解决这个问题。
什么是sack
sack的全称是selective acknowledgment,也就是选择性确认,添加sack功能需要在TCP包
头加两个选项,一个是开启选项(enabling option),另一个是sack选项(sack option)本身。开启sack选项后,receiver会将自己收到了哪些包,没收到哪些包的信息记录在sack段中告诉给sender,这样sender便可以一次性重传所有的丢包。
enabling option
enabling option是一个占两字节的选项,在建立连接时通过SYN来告诉对方自己是否支持sack。
1 2 3 4 5 | TCP Sack-Permitted Option Kind: 4 +-----------+------------+ | Kind = 4 | Length = 2 | +-----------+------------+ |
sack option
开启sack后,从receiver向sender发送的ack会在sack option字段中携带一些确认信息,
而不是单纯的duplicate ack。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | TCP SACK Option Kind: 5 Length: Variable +-------------+-------------+ | Kind = 5 | Length | +------------+------------+-------------+-------------+ | Left Edge of list Block | +------------+------------+-------------+-------------+ | Right Edge of list Block | +------------+------------+-------------+-------------+ | | / . . . / | | +------------+------------+-------------+-------------+ | Left Edge of list Block | +------------+------------+-------------+-------------+ | Right Edge of list Block | +------------+------------+-------------+-------------+ |
sack选项一般占40字节,其中kind占4字节,length占4字节,剩下32字节,每8字节为一个sack段,一个sack段用来记录一个连续block的开始序号和结束序号,所以最多只能记录4段连续的block。在实际情况中,经常会最多只有三段block,因为sack会经常与时间戳选项结合,用于测量RTT,这需要占用额外的8字节。
为什么要引入sack
在早期的TCP拥塞控制中,通过收到duplicate ack(默认为3个),连续三次ack某一个包来告诉sender某个丢包了,然后进入fast retransmition state,sender重传这个包,当receiver收到这个重传包后,便会发一个ack(ack新的包)给sender,告诉sender下一个要发送的包是哪一个。可以看到,通过duplicate ack每次只能重传一个包,如果有多个丢包,在等待重传过程中,很容易timeout,造成带宽利用率下降(underutilized)。
而如果开启sack,每一个sack段记录的是已经收到的连续的包,sack段与sack段之间断片的,也就是还没收到的(可能已经丢失,也可能是reorder)。通过sack段便可以知道多个可能已经丢失的包,这样便可以一次性的重传,而不是一个一个重传,避免因等待时间长造成的timeout问题。
要注意的是开启sack选项,也是有弊端的,因为丢包意味着网络很可能已经拥塞,这时如果一次重传多个包,很可能会造成网络更加拥塞。
参考文献
RFC 2018 TCP Selective Acknowledgment Options