Java 请求9秒超时问题分析

相关工具

    Windows PowerShell ping curl nmap/nc tcpdump wireshark iptables nginx

问题描述

平台项目上线的时候,有个部署在 Windows 的第三方 Java 回调业务, 请求平台的地址一直显示超时失败,但是在这台 Windows 上,用浏览器又能正常打开这个回调链接

排查思路

先登录服务器,复现问题并观察下情况 之前有说起来在排查防火墙问题,就先试一下,结果请求还是超时,没有效果

打开 Windows PowerShell,使用 curl 命令来测试

curl http://x.x.x.x:8080/path

观察结果,请求确实成功了,但是这个过程很慢, 接着重复执行一次 curl ,又发现请求在1秒内就可以成功。

关闭shell窗口再打开,重新执行命令,会看到第一次请求成功还是需要9秒, 这个现象比较好理解,说明耗时只是花在了tcp连接首次建立的时候, 后续请求会复用之前建立好的链路,可以用 netstat 简单看下链接情况

netstat -aonp tcp | findstr x.x.x.x

再用系统自带的 ping 命令测试下

ping -n 1 x.x.x.x

响应也很快,说明 icmp 协议不受影响,可能只是 tcp 协议会被限制

从上面的情况能看出,请求慢的原因并不是在第三方的 Java 程序上, 只不过一般 Java 在做这种请求时都会有配置超时时间; 这里首次响应成功需要的时间,应该已经超过了 Java 配置的超时时间, 导致请求在没成功时就直接被判定超时杀掉了,后续的重试策略也一直重复着这一步。

上面是测试了第三方和平台之间的连接,比较慢,我们还测试了另外三种情况:

    自己电脑和平台服务器的 http 连接 公司测试服务器和云平台服务器的 http 连接 第三方服务器和测试服务器的 http 连接

最后选择通过 nginx 针对这个端口做代理请求,算是临时解决了这个问题。

另一种场景

几天后,又收到另外一个问题反馈:说是一个文件预览功能缓慢, 这个文件预览服务也是部署在那台 Windows 服务器上,预览的是平台的文件。 问题本质跟上面是一样的,只不过是业务和请求的端口号变了。

考虑到这种问题场景可能还会增加,再用临时方案也不好,所以决定排查下问题的根本原因, 先在 Windows 上安装 nmap 、wireshark 程序,方便分析网络数据包。

基于之前的分析结果,打开 wireshark,监听两个服务器之间的网络测试包, 测试几次,发现在[SYN]请求发出之后,都会有两次重传,注意这里头部的[ECN]和[CWR]标识

接下来用 nmap 来做 ping 测试

# 这里不再使用 icmp ,改成 tcp 模式来测试
.
ping.exe --tcp -p 8080 -c 1 x.x.x.x

结果能正常快速地收到响应,再给请求加上 [ECN]和[CWR]标识位测试几次,和预期一样,请求会失败。

.
ping.exe --tcp --flags SEC -p 8080 -c 1 x.x.x.x

结合这些情况查找一下资料,也看到了这个案例:

最后

解决方式大致就是两种: 禁用 Windows 的 ecn 配置或者让 linux 服务器支持 ecn , 这里选择先禁用 Windows 的 ecn 配置,至于网络协议里的相关知识, 大家感兴趣的话可以再自己了解下

经验分享 程序员 微信小程序 职场和发展