上一篇文章《从时序图看TCP:有关MSS分析技巧,让故障排查事半功倍》深入探讨了TCP的EOP、NOP、MSS选项在CSNAS时序图中的分析方法,本文将继续围绕时序图和大家探讨TCP选项相关话题。
什么是TCP接收窗口?
在TCP协议中,接收窗口(Receive Window,简称RWND)是一个重要的概念,它的主要作用是防止发送方发送的数据量超过接收方的处理能力。接收窗口由TCP协议包头中的“窗口大小”字段描述,该字段的数值用来通告当前自己的接收窗口大小,即当前能够接收的数据字节量。

图1 TCP“窗口大小”字段
接收窗口的大小是动态调整的,它取决于接收方的处理能力。如果接收方的缓冲区满了,它可以通过减小接收窗口的大小来告诉发送方减少发送数据。如果接收方的缓冲区满了,它可以将接受窗口大小设置为0,告诉发送方暂时停止发送数据。
什么是WSOPT选项?
如图1所示,窗口大小字段的长度为16位,这意味着接收方能通告的最大窗口大小为2¹⁶,即65535字节,64KB。在高速网络中,64KB的缓冲空间显然是不够用的。因此,WSOPT(Window Scale Option,窗口扩大选项)用于扩展TCP窗口的大小,WSOPT最大能将通告窗口扩充14位,最大扩充至230,即1GB,从而适应高速网络环境。
WSOPT如何实现扩充窗口大小?假设客户端窗口扩大因子为4,那么在客户端后续声明的窗口中,所有关于窗口的数值计算应当在尾部增加4个0。这有点类似在我们的银行存款余额尾部追加4个0,这种扩充是非常刺激的,因为银行存款余额是十进制,追加4个0即扩大了104=1000倍,而计算机是二进制的,所以窗口扩充追加4个0仅扩充2⁴=16倍
WSOPT通过在TCP握手阶段的SYN包和SYN+ACK包携带,通告是否支持此功能,以及窗口扩大因子数是多少。WSOPT选项需要双方支持才会生效。
如何分析WSOPT选项?
WSOPT的长度为3个字节,包括类型(值为3)、长度(值为3)和扩大因子系数字段,其中扩大因子系数表示窗口扩大的位数:

图2:客户端通过SYN包声明支持WSOPT,系数为8(扩大2⁸=256倍)

图3:服务器通过SYN/ACK包声明支持WSOPT,系数为4(扩大2⁴=16倍)
经过SYN包和SYN/ACK包的交互,双方在本会话后续所有“窗口大小”都要按照窗口扩大系数来扩充。
例如会话进行到第7个数据包时,服务器声明自己的窗口大小为980,实际窗口大小扩大16倍后,为980*16=15680字节

图4:原始传输的服务器接收窗口

图5:原始传输的客户端接收窗口
会话进行到第8个数据包时,客户端声明自己的窗口大小为513,实际窗口大小扩大256倍后,为131328字节。
“TCP流分析”视图下的时序图中只展示了原始传输的窗口大小数值,若要观察经过计算的窗口大小,可以到“TCP会话”视图下的时序图中进行观察。

图6:经过计算的客户端和服务器接收窗口
在TCP会话的时序图中,可以看到客户端和服务器的窗口变化趋势。这里可以注意观察,SYN包和SYN/ACK包的窗口大小和其它包有所不同,这是由于SYN包与SYN/ACK包只负责通告和协商WSOPT,而不参与WSOPT的计算。
在TCP会话视图,可以通过右键点击会话,选择“TCP流图形—窗口大小”来对窗口波动趋势进行观察

图7:客户端→服务器方向,即服务器接收窗口波动趋势
趋势图上方的绿线表示服务器的接收窗口一直徘徊在16000左右,非常平稳,说明窗口“够用”
点击右下方的“切换方向”,可以观察另一方的窗口趋势图

图8:服务器→客户端方向,即客户端接收窗口波动趋势
另一方向,趋势图上方的绿线表示客户端的接收窗口一直徘徊在130000左右,同样“够用”。
窗口是如何影响接收速率的?
这是一条和窗口异常有关的会话,观察这条会话:

图9:接收窗口异常的会话(序号80数据包解码)
会话第80号包是客户端发送的ACK,该包通告当前接收窗口大小为1460字节,且该包之前有数据包丢失(丢包情况不在本文讨论范围内,可忽略)。

图10:接收窗口异常的会话
随后,81号包为服务器发送的一个携带TCP载荷的包,载荷长度为1460,这些载荷刚好填满客户端的1460字节接收窗口,因此软件标记了“TCP Window Full”,意为“当这个包发往对方后,对方的窗口将会满载”

图11:接收窗口异常的会话(序号82数据包解码)
果然,在第82号包,客户端发送了一个ACK,且窗口大小为0,软件将此包标记为“TCP ZeroWindow”,意为“客户端窗口已满,请服务器暂停发送数据”。
在82号包过后的一段时间里,服务器暂停了数据发送。504ms后,客户端再次发送了一个ACK包,声明自己的窗口大小更新至65535:

图12:接收窗口异常的会话(序号83数据包解码)
由此,客户端和服务器完成了一次“客户端窗口将满→客户端窗口满并通知服务器→服务器等待→客户端窗口恢复→客户端发包通知服务器”。该流程从80号包至83号包,耗时700ms左右。
接收窗口满了以后,TCP发送方如何处理?
刚才的示例中,客户端接收窗口恢复花费了约700ms,这是实实在在的由于窗口原因导致的时延。通常,发送0窗口通知的接收方设备,存在硬件性能不足的问题,如果性能不足设备使用的存储是网络挂载的,那么则需要考虑主机与存储之间的交互情况。
假设另一种情况,客户端发送0窗口后,窗口一直没有恢复,或者客户端通知窗口恢复的数据包发生了丢包,服务器将如何处理?这时,坚持计时器就派上了用场:
当TCP接收方发来零窗口通知时,发送方就会启动坚持计时器。当计时器的期限到达时,发送端就会主动发送一个探测包,这个探测包只有1个字节的载荷数据,且无需被确认。若第一次发送探测包仍未收到回信,再等待双倍的时间发送第二次探测包,若再无回信,则再双倍时间等待,以此类推,最长60秒发送一次探测包。坚持计时器的时间与超时重传计时器RTO的时间相同,关于RTO计时器,后续文章会进行详细描述。
简单来说,发送方不会一味等待接收方恢复窗口,而是会“隔一会儿问一句:好了吗?”
关于坚持计时器的时序图,如下图所示:

图13:坚持计时器
如上图所示,服务器第249号包被标记为“TCP Window Full”,表示此包将填满接收方(客户端)的接收窗口。44ms后,客户端发送第250号零窗口包,该包被标记为“TCP ZeroWindow”,服务器进入零窗口等待,坚持计时器开始计时。302ms后,服务器发送第251号数据包,该包为探测包,该包的有效载荷长度为1字节(这1字节实际是重复发送第249号包的最后一个有效载荷),客户端第252号数据包回复“TCP ZeroWindowProbeAck”,表示回应第251号包,但窗口暂未恢复。最后,客户端通过第253号数据包通知窗口已恢复,服务器第254号包继续发送数据。
WSOPT可能导致的故障有哪些?有什么分析方法?
如果TCP会话中任意一方在SYN包或SYN/ACK包中不携带WSOPT选项,将导致双方WSOPT协商启用失败。未启用WSOPT的会话TCP窗口只有默认65535字节,可能影响传输效率,导致会话频繁出现ZeroWindow数据包。
要分析此类故障,主要依靠对TCP会话的三次握手包,分析判断WSOPT是否协商成功,若无三次握手包捕获,则观察接收方的相邻两个数据包的RWND,结合发送方已发送的payload,观察接收方RWND的变化,也可以通过数值计算出双方的会话是否存在WSOPT,以及WSOPT的倍数是多少。需要注意的是,如果双方WSOPT协商失败了,窗口最大为64K,这大大限制了双方的数据传输速度。
若WSOPT协商成功,会话的任意一方仍经常发送ZeroWindow数据包,则考虑发送ZeroWindow数据包的一方存在性能问题。
简而言之,谁发送ZeroWindow,谁的主机性能就一定存在或多或少的问题。
典型的故障实例
放一张图,大家可以分析下这个图,尝试分析故障:

图14:故障流量的TCP窗口大小趋势图
该图为CSNA系统中关于TCP窗口大小的TCP流图形,图中可见,通信中一方的TCP接收窗口时而触底,时而触顶,且顶部最高数值为60000+字节,该会话中存在什么样的问题?
关于此故障的详细描述和讲解,可参考如下视频:
本文介绍了TCP的WSOPT选项,深入探讨了WSOPT的分析,TCP零窗口,坚持计时器等窗口问题在CSNAS时序图中的分析方法,通过深入理解和掌握窗口和WSOPT的分析技巧,能够提升流量分析工程师在工作中快速分析解决此类故障的能力。