凌晨3点,某电商平台突发流量高峰,服务器频繁丢包导致支付失败。运维团队排查发现,问题竟源于一个被忽视的TCP选项——SACK。这个看似微小的配置,如何成为压垮系统的最后一根稻草?- 当TCP发送方计划发送①-⑥这六个数据包,目前已经连续发送了①②③④⑤号数据包
发送方发现③丢包并重传③ 那么,接下来,发送方应该继续发送④,还是继续发送⑥?由于TCP累积确认的机制存在,接收方可以在收到③的重传后,通过确认③或确认⑤来声明自己接收到哪些数据包。本文讨论的情况,是发送方暂未接收到针对③的ACK包时的情况,如下图所示:在发送方未接收到针对③的ACK时,继续发送④或继续发送⑥都是盲目且不合适的。问题的关键在于,发送方是否能够获知④和⑤是否已经被接收方收到?针对上述情况,如果有一种机制,能够让接收方只收到①②④⑤的情况下,先对②进行累积确认,同时声明④和⑤已经正确收到的情况,那么发送方就可以正确决定该继续发④或⑥了。由于每个TCP数据包只有一个ACK字段,并且ACK字段默认是累积确认的,这就导致接收方无法在未收到③的时候去确认④和⑤。SACK(Selective
Acknowledgment)选项的出现正是为了弥补这一问题,其通过TCP选项的方式传输,实现允许接收方对非连续的TCP段进行单独确认,使发送方只重传丢失的片段。SACK选项能够在乱序和丢包的情况下提高TCP传输的效率。结合前文的例子来说,SACK允许接收方使用TCP ACK字段确认②,并通过TCP SACK选项确认④和⑤。SACK是如何实现该功能的?首先,该功能需要通信双方支持。在连接建立的SYN包和SYN/ACK包中,需要双方声明自己支持SACK,会话才会启用SACK功能。在启用了SACK功能的会话中,如果出现了丢包,那么一般会触发重复ACK。在重复ACK包中,接收方会使用另一种TCP选项声明已经接收到的“④和⑤”。因此,SACK实际是两种选项,一种选项为SACK允许选项(Sack-Permitted),选项类型为04,用于声明自己支持SACK功能,如果双方都支持SACK,那么在后续的连接通信过程中就可以使用SACK选项;另一种选项为SACK本身,选项类型为05,用于进行“选择性确认”。选项04的SACK允许,在实际流量分析中,如下图所示:选项05的SACK,一般出现在重复ACK中,如下图所示:通过图2、3可以看出,“SACK允许”选项的格式相对简单,选项类型为04,选项长度为02字节,仅用于声明支持此功能。通过图4可以看出,“SACK”选项的格式相对复杂,选项类型为05,长度为10字节,块左边界长度为4字节,块右边界长度为4字节。块左边界和块右边界的概念,是前文中示例的④+⑤数据包的左边界和右边界。左边界为④的Seq,右边界为⑤的Seq+Len。由于④和⑤是连续的两个包,因此两个包被合并为同一个块。图中①-⑥数据包的长度均为100,起始Seq号为100,并模拟了发送方③丢包和接收方SACK的情况。当接收方收到①②④⑤时,可以用ACK号300来表示接收到了Seq为300之前的数据,即①和②;同时使用SACK表示接收到了Seq为400-499,500-599这两个包的数据,即④和⑤;由于④和⑤是连续的数据,在SACK中可以合并为一个块。因此SACK块左边界为400,块右边界为600。“SACK”选项包含了具体的SACK信息,它告诉对方已经接收哪些数据,发送方可以根据这些信息判断具体丢了哪些包。接下来看一个SACK在TCP会话中的实际应用过程:
服务器发送了序号为429、430、431的三个数据包,其中430号数据包发生了丢包。客户端通过432号包进行确认,Ack号为3589769219,仅对429号包进行了确认。同时客户端通过SACK的块左边界3589770679和块右边界3589772139声明已经收到了431号包。随后服务器又连续发送了序号为433、434、435、436这4个数据包,客户端正常收到了这4个数据包,但由于累积确认的存在,客户端不能确认这4个数据包,只能利用437、438、439、440号数据包重复对432号数据包的确认。客户端发送的4个数据包均携带SACK,观察客户端发送的440号,如下图所示:
440号数据包携带SACK选项,块左边界为3589770679,块右边界为3589777979,结合服务器之前发送的数据包看,这正巧是服务器发送的431、433、434、435、436这五个连续的数据。
过了约34ms,服务器又发送了441号、442号数据包,并通过443号数据包重传了丢失的430号数据包。随后,服务器通过444号数据包继续发送442号数据包后的数据。结合之前的示例,本例中的429即为①②数据包,430即为③,431、433、434、435、436、441、442即为④⑤数据包,444即为⑥。服务器在重传③后,继续发送了⑥,而非继续发送④,这全是SACK的作用。通过SACK选项,接收方可以通知发送方哪些数据块已经收到,哪些数据块丢失,从而避免发送方重传已经成功接收的数据块,减少不必要的网络拥塞和提高传输效率。放一张图,你能否从这张图中看出导致网络故障的端倪?
本文介绍了TCP的SACK选项,深入探讨了SACK选项的作用、工作方法,以及在科来网络分析系统中的TCP时序图功能中的分析方法,通过深入SACK选项的分析技巧,能够提升流量分析工程师在工作中快速分析解决此类故障的能力。• 如果接收方SACK块缓冲区溢出,会发生什么? • SACK能否完全替代快速重传(Fast Retransmit)?
|