天天看點

解決centos下tomcat啟動太慢 & JDBC連接配接oracle太慢的問題

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

作者:Lave Zhang

出處:http://www.cnblogs.com/lavezhang/

本文版權歸作者所有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接配接,否則保留追究法律責任的權利。