Linux 中的 TCP 连接卡住

Linux 中的 TCP 连接卡住

奇怪的问题。我在达拉斯有服务器“ALPHA”,在香港有服务器“BETA”,两者之间的 ping 时间相差约 195 毫秒。ALPHA 以 1gbps 满速连接,BETA 以 10mbps 满速连接。有时,当他们通过 TCP 相互通信时,连接会挂起。最终 ALPHA 放弃并关闭连接,但 BETA 仍认为连接已建立,并等待很长时间,直到最终超时。

例子。

在测试版中,wget -O /dev/null ALPHA:50001/1mb.test

--2013-05-19 02:45:54--  http://ALPHA:50001/1mb.test Resolving dfw... ip.address.redacted Connecting to ALPHA|ip.address.redacted|:50001... connected. HTTP request sent, awaiting response... 200 OK Length: 1000000 (977K)
[application/octet-stream] Saving to: `/dev/null'

它在收到 0 字节时冻结。请注意,它确实从服务器获得了 200 OK,因此它们似乎成功握手。为了消除 wget 作为问题的一部分,我执行了 telnet:

telnet ALPHA 50001
Trying ip.address.redacted...
Connected to ALPHA.
Escape character is '^]'.
GET /1mb.test HTTP/1.0

HTTP/1.1 200 OK
Server: nginx
Date: Sun, 19 May 2013 22:43:48 GMT
Content-Type: application/octet-stream
Content-Length: 1000000
Last-Modified: Sat, 21 Jan 2012 21:47:29 GMT
Connection: close
ETag: "4f1b3271-f4240"
Accept-Ranges: bytes

此时它也会冻结。

两个服务器都有 iptables 规则-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT

这是上述 wget 冻结期间在 ALPHA 上运行的 tcpdump。 http://pastebin.com/axX7ap6T

这个问题偶尔会发生。有时它工作正常。实际上,如果我运行大约 3-5 个 wget,通常一切都会在第四次或第五次尝试时开始正常工作。

BETA 可以毫无问题地与 GAMMA、DELTA 和我的其他服务器通信。似乎只有在与 ALPHA 通信时才会发生这种情况。ICMP ping 显示没有数据包丢失,但即使有数据包丢失,也会减慢速度,而不是断开连接。两台机器都使用相同的 CentOS 6.4 64 位操作系统,内核为 2.6.32-358.6.2.el6.x86_64。/var/log 文件中没有记录任何有用的信息。ALPHA 使用 nginx-1.4.1-1.el6.ngx.x86_64 监听 50001。nginx 访问日志文件显示在冻结连接期间传送了 200(请求 OK)43440 字节。

这个问题似乎与 nginx 无关,因为我在同一天的通信过程中也遇到过 ssh 连接冻结的情况。其他服务器连接到该 nginx 时从未出现任何问题。

总而言之,这似乎是这次特定交流中发生的情况:

BETA -> ALPHA "SYN!"
ALPHA -> BETA "SYN Acknowledgement"
BETA -> ALPHA "ACK"
ALPHA -> BETA "Established"
BETA -> ALPHA "GET /file HTTP/1.0"
ALPHA -> BETA "200 OK, here's a bunch of data"
BETA freezes, gets no data.

有人见过这种情况吗?

答案1

可能是 MTU/MSS 问题?较小的初始数据包可以传输,较大的数据包(数据传输)在某处被终止?

解决方法是稍微减少 MTU(两侧),例如从 1500 减少到 1450,或者TCPMSS仅对受影响的连接使用 Netfilter 目标(或对单独的连接使用不同的目标)。

但真正的解决办法是路径 MTU 发现再次工作。因此请检查 ICMP 数据包(需要分片:类型 3,代码 4)是否被阻止。使用tcpdump -i $ifname -n icmp查看此类数据包是否到达。

答案2

确实发生了碎片整理。这就是 IPTABLES 检查数据包时所做的。它必须重新组装它们才能验证内容。

就我的情况而言,当我在 CentOS 7 系统上进行网页浏览时,我会看到周期性的 ping 丢失和网页浏览器停顿,或者我的 Windows PuttY 会话会神秘地永久挂起。

我使用了 Mick 提供的一种方法来确定 MTU 大小。该方法的问题是,如果您将 MTU 大小设置得较小,则会得到错误的碎片读数。因此,请将大小设置得较大(巨型帧/9000),然后开始 ping 探测。

将 MTU 设置为 1472(我确定这是正确的值)后,浏览时的 ping 问题就消失了。希望下次我从 Windows 进行 ssh 时,它也能正常工作。

答案3

我的第一个猜测是这是一个 TCP 窗口缩放问题:

https://en.wikipedia.org/wiki/TCP_window_scale_option#Possible_side_effects

在两端禁用它,看看问题是否消失。另一个选项(如 Hauke 所建议的)是正在进行碎片整理。

您可以使用 ping 来检查数据包碎片,这里有一个简单的 HOWTO:

http://muzso.hu/2009/05/17/how-to-determine-the-proper-mtu-size-with-icmp-pings

修改:漏了一个词。

相关内容