我在两台虚拟机上运行 Linux 内核 3.13(Ubuntu 14.04),每台虚拟机都在两台运行 ESXi 5.1 的不同服务器中运行。两台虚拟机之间运行着一个 zeromq 客户端-服务器应用程序。运行约 10-30 分钟后,由于无法重新传输丢失的数据包,此应用程序始终挂起。
当我在 Ubuntu 12.04(Linux 3.11)上运行相同的设置时,应用程序从未失败(更新:在 12.04 上也会失败,但需要更长时间)
如果您注意到下面,“党卫军“(套接字统计)显示丢失了 1 个数据包,sk_wmem_queued 为 14110(即 w14110)并且 rto 较高(120000)。
State Recv-Q Send-Q Local Address:Port Peer Address:Port
ESTAB 0 **12350** 192.168.2.122:41808 192.168.2.172:55550
timer:(on,16sec,10) uid:1000 ino:35042
sk:ffff880035bcb100 <->
skmem:(r0,rb648720,t0,tb1164800,f2274,**w14110**,o0,bl0) ts sack cubic wscale:7,7 rto:120000 rtt:7.5/3 ato:40 mss:8948 cwnd:1 ssthresh:21 send 9.5Mbps **unacked:1 retrans:1/10 lost:1** rcv_rtt:1476 rcv_space:37621
由于这种情况一直发生,我能够在 wireshark 中捕获 TCP 日志。我发现丢失的数据包确实会被重新传输,甚至会被其他操作系统中的 TCP 确认(序列号可在 ACK 中看到),但发送方似乎无法理解此 ACK 并继续重新传输。
两个虚拟机和整个路由上的 MTU 均为 9000。发送的数据包很大。
正如我之前所说,这不会发生在 Ubuntu 12.04(内核 3.11)上。因此,我对 14.04 和 12.04 之间的 TCP 配置选项(通过“sysctl -a |grep tcp ”查看)进行了比较,并发现了以下差异。
我还注意到两种配置中的 net.ipv4.tcp_mtu_probing=0。
左边是3.11,右边是3.13
<<net.ipv4.tcp_abc = 0
<<net.ipv4.tcp_cookie_size = 0
<<net.ipv4.tcp_dma_copybreak = 4096
14c11
<< net.ipv4.tcp_early_retrans = 2
---
>> net.ipv4.tcp_early_retrans = 3
17c14
<< net.ipv4.tcp_fastopen = 0
>> net.ipv4.tcp_fastopen = 1
20d16
<< net.ipv4.tcp_frto_response = 0
26,27c22
<< net.ipv4.tcp_max_orphans = 16384
<< net.ipv4.tcp_max_ssthresh = 0
>> net.ipv4.tcp_max_orphans = 4096
29,30c24,25
<< net.ipv4.tcp_max_tw_buckets = 16384
<< net.ipv4.tcp_mem = 94377 125837 188754
>> net.ipv4.tcp_max_tw_buckets = 4096
>> net.ipv4.tcp_mem = 23352 31138 46704
34a30
>> net.ipv4.tcp_notsent_lowat = -1
我对论坛上的网络专家的问题是:是否有任何其他调试工具或选项可以安装/启用,以便进一步探究为什么这种 TCP 重传失败如此频繁地发生?是否有任何配置更改可能导致这种奇怪的行为。
更新(对于那些以后可能遇到类似问题的人):我也能够在 3.11 上重现该问题,然后能够通过降低 MTU 来避免这个问题。
此处已报告了类似的问题https://serverfault.com/questions/488893/how-do-i-prevent-tcp-connection-freezes-over-an-openvpn-network。那里给出的描述与我看到的相符:
“不过,在 Ubuntu 客户端的某个时刻,远程端开始一遍又一遍地重新传输相同的 TCP 段(每次重新传输之间的传输延迟都会增加)。客户端在每次重新传输时都会发送看似有效的 TCP ACK,但远程端仍会继续定期传输相同的 TCP 段。”
可能相关文章:https://blogs.kent.ac.uk/unseenit/2013/10/18/stalled-scp-and-hanging-tcp-connections/
答案1
我们注意到了同样的问题:Ubuntu 12.04 上的 Linux 3.2 内核运行没有任何问题,Ubuntu 14.02 上的 Linux 3.13 也存在同样的问题。
我不确定这是否真的是内核中的错误,对我来说,这更像是选择性 ACK(SACK)的问题。您可以通过以下方式禁用 TCP SACK 来解决此问题:
sysctl net.ipv4.tcp_sack=0
这解决了问题。在我们的案例中,连接有损或距离较远的客户端(例如不同的数据中心、DSL 线路)不再能够下载大文件。下载大约几兆字节后,HTTP 连接停滞。TCDump 显示传输了大量选择性 ACK(SACK)。
是的,在 14.04 中启动 12.04 内核也有帮助。
我认为我们应该在 Ubuntu 中提出一个问题。我只是不确定问题是否只因我们的网络/路由器硬件而发生,但一般来说,TCP SACK 错误似乎是一个问题。