近期遇到一個非常奇怪的問題,也不知道改了什么,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內部還依賴別的環境配置吧,這個等待其它小伙伴去探究。