星期二我从公司内网访问测试机 Web 服务器上的 PHP 程序遇到了问题,记录下排查细节,最后定位了问题但不知道是如何解决的,但整个过程还是值得记录的。
整个访问情况如下图:
结构
设置 mail.sina.net Host 为内网地址,打开浏览器访问 http://mail.sina.net,一直没有反应(等待,慢,超时),现象基本上是这样的。
(1)第一个反应是不是服务器防火墙打开了,因为以前出现过类似的问题,防火墙屏蔽了客户端访问,将防火墙关闭后,还是出现同样的问题。
(2)查看了服务器 Apache 的 Access 日志,也没有日志出现(事后知道是误判,Access 日志最终生成了,而且是 200 状态码,就是 2 分钟以后才生成)。
(3)在客户端 telnet 服务器的 80 端口,链路也是通的。
为了更好的查询问题,我在客户端(Windows 10)上用 curl 测试了访问情况,如下图:
curl 访问
从图中,客户端执行了很长的时间,最后连接被主动关闭了。
思考了一会,拿出了 tcpdump 这把工具,从 TCP/IP 层面看看网络通信遇到了啥问题。
首先看一下客户端抓包,如下图,有几个现象:
客户端抓包
(1)客户端/服务器端成功完成了三次握手,进一步证明网络通信看起来是没问题的。
(2)客户端在接收具体响应的时候,出现了 Out-Of-Order,Google 了一下,代表客户端收到的 TCP 包序列号是乱的,客户端无法正常处理。
(3)客户端根据 TCP 协议的重试机制,客户端有重试了2次(每次 60秒),所以我们在客户端才感觉如此之慢。
(4)服务器端主动发送 RST 关闭了本次连接。
然后看一下服务器端抓包,如下图,有几个现象:
服务器抓包
(1)服务器在 HTTP 协议层面发送了响应。
(2)服务器由于没有接收到客户端 ACK 响应(非三次握手的 ACK 响应),多次进行了重试。
(3)万般无奈之下,服务器只能发送 RST,关闭了本次连接。
这时候一个同事提醒了我一下,服务器端程序输出内容小一点看看结果,很佩服他敏锐的分析能力,按照他说的,我修改了下程序(变更为 html 网页,且只输出 ok 字符串),然后再一次抓包,如下图:
服务器抓包2
请求一切正常。
此时情况已经很明了了,如果服务器输出的数据大于 1460 字节,TCP/IP 协议拆包发送,但客户端无法处理乱序的 TCP 包,导致最终不能成功处理。这个事情不是 Apache、PHP 的问题,只有从网络层解决。
最终网络组同事修改了内部交换机的配置,解决了该问题,当然我并不知道具体修改了什么参数。
作者:虞大胆
链接:https://www.jianshu.com/p/737915bc502a