我们一直在尝试解决一个非常奇怪的问题,我们可以从 solaris 10 上的 Apache 2.2.19 获取一个页面,并且一些请求的排列可靠地需要各种固定的时间长度才能响应。
它看起来是基于 TCP 套接字的关闭,从客户端的 tcpdump 来看,我们通常会看到服务器最后一次用其响应填充 TCP 窗口和服务器的最后一块数据与 FIN 之间的暂停。
因此,在线上它只是挂在 HTTP 响应的中间传输,但服务器上的 netstat 显示套接字处于 FIN_WAIT_1 状态。我们无法在服务器上执行 tcpdump 来澄清,但在我们看来,操作系统已将 TCP 对话交给硬件,因此相信它已启动 4 路关闭,但 NIC 从未放置该数据包,也没有放置未完成的数据包(可能是 1 或 2 个 @ 1500 字节和 400 个落后者或其他)。
这是我们能描绘的最清晰的画面,除了我们最近进行的一项令人惊奇的测试之外……apache 为一个 64076 字节的文件提供服务 - 最后一个数据包延迟 432 毫秒。我们向文件中添加一个字符,这导致创建了一个额外的数据包,53 字节也包含 FIN,而不是我们在稍小的文件(有延迟的文件)上看到的空的 52 字节 FIN。这个额外数据包的存在确实改变了 FIN 对话的发生方式,并使对话从近半秒缩短到几毫秒。
在我们调查的最典型情况中,这个延迟是 4.6 秒,我们再次看到窗口大小波动,SACK 在需要时会返回到 Apache,但是最后一次窗口满了,它会挂起 46 秒,然后返回最后的 2 或 3kb 数据,以及 Solaris 认为很久以前发送的 FIN。
我们的 tcpdump 位于 F5 BigIP 上,因此有一个用于传输流量的 ASIC,以及一个 Cisco 6509(仅 L2),但是在相邻的 Solaris 机器上执行 wget 时我们确实看到了相同的用户体验,所以不要相信 BigIP 正在做的任何黑魔法。
但这一切都与窗口大小和 MSS 等混淆在一起,但如果这听起来很熟悉,我们都会洗耳恭听!