上一篇文章中,我们看到了如何通过 wireshark 排查 TCP 重复 ACK 特别是由此引发的快速重发问题:
实战网络问题排查(五) -- 利用 wireshark 排查 TCP 快速重传问题
然而,在 TCP 众多流量控制算法中,滑动窗口协议显然是最重要的机制。
本文,我们就来利用 wireshark 来排查和定位 TCP 滑动窗口协议相关的问题。
此前我写过一篇文章详细介绍了滑动窗口协议,可以参看:
简单的来说,TCP 的滑动窗口机制是这样的:
wireshark 的分析结果中,可能出现以下几个零窗口的情况:
下面来一一进行分析。
TCP ZeroWindow 报文用来告知接收方停止发送数据,因为此时发送方缓存已满。
这说明发送方进程的内存不足,也可能是接收方 ACK 不及时造成的。
当通信的一方接收到 TCP ZeroWindow 报文后,会定时发送 TCP ZeroWindowProbe 报文进行探测。
探测报文是需要发送的下一字节数据,通过接收方的响应,可以判断是否接收方窗口仍然为 0,如果接收方回复窗口大小仍然为零,则发送方的探测计时器加倍。
这个报文是在接收方已经向对端发送过零窗口报文之后,仍然收到的报文。这表示对端违反了 TCP 的滑动窗口协议。
此时需要排查该报文发送方的 TCP 实现。
TCP 协议允许随时改变窗口的大小,并且通过发送标识有 TCP WindowUpdate 的报文通知对端。
有两种情况可能导致收到该报文:
当 wireshark 识别到某条消息发送后会完全填满接收方的窗口,这条消息就会被标识为 TCP WindowFull。
这之后,接收方一般都会发送 TCP ZeroWindow 报文给发送方,以便让发送方暂停发送。
如下图所示,是一个典型的空窗口问题的例子:
除了检查内存分配以外,很有可能问题出在接收方处理能力不足,可以结合实际业务进一步进行排查。
除此之外,可以打开 wireshark 的 TCP 吞吐量图表查看吞吐情况:
如图所示,上面一行显示了窗口大小,与下面一行的距离表明窗口的剩余大小,如果两条线重合,就说明出现了零窗口问题,两条线之间维持一个固定距离表明接收方工作良好。
我们知道,通常 TCP 连接是通过四次挥手断开连接的:
这是标准的做法,但当你打开一个网页,可能同时打开了数十个连接(主页,新闻,广告,定期更新的图片等),要关闭所有这些有时需要数百个FIN和FIN-ACK报文。
为了防止这样的情况发生,web 服务器在很多情况下会在发送请求数据之后通过发送 RST 报文强制断开连接,但更多的情况下,RST 报文标志着有故障发生:
正如我们在此前的文章中已经介绍过的,如果每次发送 SYN 报文后都只收到了 RST 报文,那么这是典型的防火墙强制断开连接的情况。
故障导致的 RST 报文的情况非常多,常见的有:
《Network Analysis Using Wireshark Cookbook》