近期遇到一个非常奇怪的问题,也不知道改了什么,tomcat启动非常慢,以前几秒就启动好了,现在要30秒左右。
而且,通过jdbc连接oracle数据库也非常慢,以前建立一个连接只要几十毫秒,现在也要10秒左右。
折腾了好几天,终于解决了,记录下来,帮助大家少走弯路。
遇到这个问题时,最初以为是random策略问题,以前遇到过,通过修改随机数策略可以解决,参照我的这篇文章:
https://www.cnblogs.com/lavezhang/p/6106356.html
但是,修改后发现问题没有解决,只能继续排查。
怀疑是jdk自动寻找proxy的问题,于是设置ProxySelector.setDefault(null),还是没有解决。
怀疑是tomcat版本问题,从tomat8到tomcat8.5,到tomcat9,都试了一遍,还是没解决。
怀疑是jdk的问题,从openjdk换成了oraclejdk,还是没解决。
最后,这种疑难问题,还是依赖Tomcat堆栈数据来分析。
于是导出tomcat堆栈信息
> pgrep java
> 21257
> jstack 21257 > thread_data1
注意:默认通过yum安装的是openjdk,没有jstack这个工具,得安装特殊的包才有,办法去网上搜吧。
最简单的办法是,直接换成oracle jdk,因为openjdk的jstack工具有坑!
开始分析堆栈数据,发现tomcat启动,以及Oracle连接,都是卡在一个地方:
"main" #1 prio=5 os_prio=0 tid=0x00007f812000a000 nid=0x5813 runnable [0x00007f8126dee000]
java.lang.Thread.State: RUNNABLE
at java.net.Inet4AddressImpl.getLocalHostName(Native Method)
at java.net.InetAddress.getLocalHost(InetAddress.java:1474)
at sun.management.VMManagementImpl.getVmId(VMManagementImpl.java:140)
at sun.management.RuntimeImpl.getName(RuntimeImpl.java:59)
at org.springframework.boot.system.ApplicationPid.getPid(ApplicationPid.java:55)
at org.springframework.boot.system.ApplicationPid.<init>(ApplicationPid.java:46)
------------------------------------------------------------------------------------------
"http-nio-8082-exec-4" #23 daemon prio=5 os_prio=0 tid=0x00007fa7fc77a800 nid=0x5438 runnable [0x00007fa7b97d1000]
java.lang.Thread.State: RUNNABLE
at java.net.Inet4AddressImpl.lookupAllHostAddr(Native Method)
at java.net.InetAddress$2.lookupAllHostAddr(InetAddress.java:928)
at java.net.InetAddress.getAddressesFromNameService(InetAddress.java:1323)
at java.net.InetAddress.getLocalHost(InetAddress.java:1500)
- locked <0x0000000688fca748> (a java.lang.Object)
at oracle.jdbc.driver.T4CTTIoauthenticate.setSessionFields(T4CTTIoauthenticate.java:1118)
at oracle.jdbc.driver.T4CTTIoauthenticate.<init>(T4CTTIoauthenticate.java:265)
at oracle.jdbc.driver.T4CConnection.logon(T4CConnection.java:579)
at oracle.jdbc.driver.PhysicalConnection.connect(PhysicalConnection.java:666)
at oracle.jdbc.driver.T4CDriverExtension.getConnection(T4CDriverExtension.java:32)
at oracle.jdbc.driver.OracleDriver.connect(OracleDriver.java:566)
at java.sql.DriverManager.getConnection(DriverManager.java:664)
at java.sql.DriverManager.getConnection(DriverManager.java:247)
查了一下,这行代码是检索/etc/hosts文件,获取当前机器名对应的IP地址,如果没有明确配置机器名和IP的映射关系,就会在这里卡10秒左右,其实就是在局域网内去ping了。
打开/etc/hosts,果然没有配置,赶紧补上,如下:
> vi /etc/hosts
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4 prd_web1
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6 prd_web1
其中,prd_web1就是手工设置的机器名。
至此,问题得以解决!
总结,走了很大一段弯路,其实对于这种程序卡死的现象,最佳解决方案就是分析tomcat堆栈,其它办法都是靠猜测,不靠谱。
另外,这个现象并不是在所有机器上都存在,在有些机器上,即使没有在hosts文件中配置自定义hostname的映射,程序也会正常运行,可能是jdk内部还依赖别的环境配置吧,这个等待其它小伙伴去探究。