我发现一个问题,即特定情况组合导致发送 TCP 重复 ACK。这发生在托管在 Ubuntu Server 20.04 上的服务上。
我有一个 Web 服务,它接受使用 multipart/form-data 的上传。在新服务器上设置新版本的服务时,我发现它运行缓慢,最终出现了以下问题。
我有两台电脑要测试。当从 Windows 10 电脑向它发送请求时,某些数据包会被两次确认或无序确认,然后重新传输。以下是 Wireshark 在发送包含随机字节的 25 MB 文件时对 TCP 窗口缩放的分析截图- 由于频繁(大约每 10-20 个数据包)重复 ACK 或无序 ACK 以及相应的重新传输,窗口永远不会大到足以保持吞吐量。因此,传输文件大约需要 55 秒。
当从 macOS 10.15 计算机向其发送请求时,我没有看到这种行为。以下是 Wireshark 的 TCP 窗口缩放分析的屏幕截图- 窗口快速增大,并且所有数据在几秒钟内按应有的方式传输。
使用相同版本的 Chrome 和 Firefox,以及 Mac 上的 Safari 和 Windows 上的(旧版)Edge,行为是相同的 - 每台计算机上的所有浏览器都受到相同(各自)行为的影响。在我看来,这表明需要进行某种 TCP 参数调整。
为了隔离我正在使用的 Web 堆栈,我在 Node.js v12 中编写了一个最小测试程序,它接受使用 multipart/form-data 的上传,并且我得到了相同的行为 - 在 Windows 上的行为不好,在 Mac 上的行为很好。Node.js 使用 libuv,另一个堆栈是使用 Kestrel 服务器的 ASP.NET Core,该服务器配置了非 libuv 传输,因此它们的网络在操作系统套接字之上没有任何共同之处。
据我所知,通过 nginx 反向代理(添加 TLS 终止)时,良好行为和不良行为均保持不变。
您可能会说这与我这边的网络有关。两台计算机都位于同一路由器后面的同一无线网络中,并且 Linux 服务器托管在不同的国家/地区,但当我尝试使用不在我的网络内的计算机或通过蜂窝数据时,我也看到了类似的行为。
作为最后一个参数,当在 Mac 上托管测试程序或 Web 服务并从 Windows 计算机发送类似的上传请求时,我得到了良好、快速的行为。换句话说,与 Mac 相比,Windows 计算机不仅仅是受到限制或充斥着数据包丢失 - 它可以工作,但不知何故当连接到 Linux 服务器时它最终无法工作。(Windows 计算机和 Mac 在带宽测试中发布类似的分数。)
因此,所有这些似乎都在告诉我,当 Ubuntu 20.04 的 TCP 设置(或它们在我的主机上的配置方式或受主机环境影响的方式)与 Windows TCP 堆栈的设置相遇时,会出现某种糟糕的结果。什么可能导致这些情况,我可以在服务器上进行哪些更改以期强制实现良好的行为?
(这可能更像是一个通用的 Linux 网络问题——我在这里发布它是因为我在 Ubuntu Server 20.04 上遇到了它。)