奇怪的问题。我在达拉斯有服务器“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.
有人见过这样的情况吗?
也许是 MTU/MSS 问题?小的初始数据包通过,大的(数据传输)在某处被杀死?
一种解决方法是将 MTU(两侧)从 1500 减少到 1450,例如,或者
TCPMSS
仅对受影响的连接使用 Netfilter 目标(或以不同方式用于单独的连接)。但真正的解决方案是让路径 MTU 发现再次工作。所以检查ICMP数据包(需要分片:Type 3,Code 4)是否被阻塞。用于
tcpdump -i $ifname -n icmp
查看此类数据包是否到达。确实发生了碎片整理。这就是 IPTABLES 检查数据包所做的。它必须重新组合它们以验证内容。
就我而言,当我在 CentOS 7 系统上浏览网页时,我会看到周期性的 ping 丢失和网络浏览器停止,或者我在 Windows 上的 PuttY 会话会神秘地挂起——永久挂起。
我使用了 Mick 提供的一种变体方法来确定 MTU 大小。该方法的问题在于,如果您将 MTU 大小设置得很小,您会得到关于碎片的错误读数。因此,将大小设置得较大(巨型帧/9000),然后开始 ping 探测。
将 MTU 设置为 1472(我确定的值是正确的)后,浏览时的 ping 问题消失了。希望当我下一次从 Windows 进行 ssh 时,它也能正常工作。
我的第一个猜测是这是一个 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
编辑:漏了一个字。