实战网络问题排查(六) -- 利用 wireshark 排查 TCP 空窗口问题

2022-06-27 15:02:40 浏览数 (2)

1. 引言

上一篇文章中,我们看到了如何通过 wireshark 排查 TCP 重复 ACK 特别是由此引发的快速重发问题:

实战网络问题排查(五) -- 利用 wireshark 排查 TCP 快速重传问题

然而,在 TCP 众多流量控制算法中,滑动窗口协议显然是最重要的机制。

本文,我们就来利用 wireshark 来排查和定位 TCP 滑动窗口协议相关的问题。

2. 滑动窗口协议

此前我写过一篇文章详细介绍了滑动窗口协议,可以参看:

Nagle 算法与滑动窗口协议

简单的来说,TCP 的滑动窗口机制是这样的:

  • TCP 协议中,通信的双方都有一个用来缓存自己已发送数据的缓冲区,被称为“窗口”。
  • TCP 头的第 15 和 16 字节标识了发送方的剩余窗口大小。
  • 当接收方发送 ACK 时,发送方就会将小于 ACK 序列号的所有数据从窗口中清除。
  • 这一过程持续下去,发送方向窗口中填入数据,接收方发送确认信息清空发送方窗口中的数据,这就是 TCP 滑动窗口机制。

3. wireshark 滑动窗口问题相关的报文

3.1 零窗口

wireshark 的分析结果中,可能出现以下几个零窗口的情况:

  1. TCP ZeroWindow
  2. TCP ZeroWindowProbe
  3. TCP ZeroWindowViolation

下面来一一进行分析。

3.1.1 TCP ZeroWindow

TCP ZeroWindow 报文用来告知接收方停止发送数据,因为此时发送方缓存已满。

这说明发送方进程的内存不足,也可能是接收方 ACK 不及时造成的。

3.1.2 TCP ZeroWindowProbe

当通信的一方接收到 TCP ZeroWindow 报文后,会定时发送 TCP ZeroWindowProbe 报文进行探测。

探测报文是需要发送的下一字节数据,通过接收方的响应,可以判断是否接收方窗口仍然为 0,如果接收方回复窗口大小仍然为零,则发送方的探测计时器加倍。

3.1.3 TCP ZeroWindowViolation

这个报文是在接收方已经向对端发送过零窗口报文之后,仍然收到的报文。这表示对端违反了 TCP 的滑动窗口协议。

此时需要排查该报文发送方的 TCP 实现。

3.2 TCP WindowUpdate

TCP 协议允许随时改变窗口的大小,并且通过发送标识有 TCP WindowUpdate 的报文通知对端。

有两种情况可能导致收到该报文:

  1. TCP接收方从零窗口中恢复,告知发送方重新发送数据。这一情况下,无需进行处理,只需检查导致先前零窗口问题的原因。
  2. TCP接收方频繁更改窗口大小。该情况下检查接收方被干扰的原因。可能是应用问题、内存问题、或者终端设备上的其他问题。

3.3 TCP WindowFull

当 wireshark 识别到某条消息发送后会完全填满接收方的窗口,这条消息就会被标识为 TCP WindowFull。

这之后,接收方一般都会发送 TCP ZeroWindow 报文给发送方,以便让发送方暂停发送。

4. 问题排查

如下图所示,是一个典型的空窗口问题的例子:

  1. 报文 183816 是 192.168.2.138 在 192.168.1.58 窗口占满之前的最后一条数据,因此被标记为 TCP WindowFull。
  2. 接着,192.168.1.58 发送一个报文给 192.168.2.138,告知对方停止发送数据。这是一个零窗口信号。
  3. 192.168.2.138 反复发送 TCP ZeroWindowProbe 报文探测 192.168.1.58 的窗口。
  4. 该连接上持续无数据时间达到阈值后,192.168.2.138 发送 RST 报文断开连接。

除了检查内存分配以外,很有可能问题出在接收方处理能力不足,可以结合实际业务进一步进行排查。

除此之外,可以打开 wireshark 的 TCP 吞吐量图表查看吞吐情况:

如图所示,上面一行显示了窗口大小,与下面一行的距离表明窗口的剩余大小,如果两条线重合,就说明出现了零窗口问题,两条线之间维持一个固定距离表明接收方工作良好。

5. RST 强制断开

我们知道,通常 TCP 连接是通过四次挥手断开连接的:

  1. 主动断开方发送 FIN 报文;
  2. 被动断开方发送 ACK 报文;
  3. 被动断开方完成最后的处理后,发送 FIN 报文;
  4. 主动断开方发送 ACK 报文完成断开。

这是标准的做法,但当你打开一个网页,可能同时打开了数十个连接(主页,新闻,广告,定期更新的图片等),要关闭所有这些有时需要数百个FIN和FIN-ACK报文。

为了防止这样的情况发生,web 服务器在很多情况下会在发送请求数据之后通过发送 RST 报文强制断开连接,但更多的情况下,RST 报文标志着有故障发生:

5.1 防火墙发送的 reset

正如我们在此前的文章中已经介绍过的,如果每次发送 SYN 报文后都只收到了 RST 报文,那么这是典型的防火墙强制断开连接的情况。

5.2 故障导致的 RST

故障导致的 RST 报文的情况非常多,常见的有:

  1. 当发送方发送了五个连续没有收到 ACK 回复的重传,他就会发送一个 RST 来强制断开连接。
  2. 连接之上几分钟都没有任何数据,打开连接的一方通常就会发送 RST,具体的时间阈值与行为依赖于具体的系统实现。

参考资料

《Network Analysis Using Wireshark Cookbook》

0 人点赞