一個使用Druid
鏈接Impala
的服務項目實例拋出了一個com.alibaba.druid.pool.GetConnectionTimeoutException
異常,當時的鏈接池監控數據以下:java
wait millis 5000, active 0, maxActive 50, creating 1
複製代碼
看似是普通的獲取鏈接超時的問題,但該實例在隨後一直保持對Impala
獲取鏈接失敗的狀態,同一個項目下的其餘實例並無發生相似的鏈接問題,能夠排除Impala
服務器端的問題,問題定位範圍是在通信網絡或者Impala
客戶端(項目實例)上。apache
持續不斷的運行日誌打印都現實creating 1
這個信息,這表示Druid
一直保持建立(物理/TCP)鏈接的狀態,這裏須要先說明一下Druid
建立鏈接的機制。bash
Druid
創建底層鏈接的方法是調用DruidDataSource.createPhysicalConnection()
方法實現的,調用的時機和方式有如下幾種:服務器
當用戶沒有設置 createScheduler
, 即 createScheduler == null
時, 後續全部鏈接的建立工做是由 CreateConnectionThread 線程實例去完成。該線程的建立只出如今一個方法中:網絡
protected void createAndStartCreatorThread() {
if (createScheduler == null) {
String threadName = "Druid-ConnectionPool-Create-" + System.identityHashCode(this);
createConnectionThread = new CreateConnectionThread(threadName);
createConnectionThread.start();
return;
}
initedLatch.countDown();
}
複製代碼
該方法僅在初始化DruidDataSource.init()
方法調用過一次,即鏈接建立線程數量爲 1。socket
同時,在項目的配置以下:ide
initialSize = 0
minIdle = 0
minEvictableIdleTimeMillis = 0
maxEvictableIdleTimeMillis = 0
maxActive = 50
maxWait = 5000
isTestOnBorrow = false
isLogAbandoned
isRemoveAbandoned = true
removeAbandonedTimeout = 60 * 10
複製代碼
針對鏈接超時的配置僅有maxActive
參數,表示獲取鏈接的最長時間,該參數在Druid
實現,是獲取鏈接的主線程等待鏈接返回而循環休眠的最大時長。ui
在項目中,使用jstack
命令查看CreateConnectionThread
線程的狀態this
"Druid-ConnectionPool-Create-1942750238" #122 daemon prio=5 os_prio=31 tid=0x00007ff2ba81c000 nid=0x8907 runnable [0x0000700009ec7000]
java.lang.Thread.State: RUNNABLE
at java.net.SocketInputStream.socketRead0(Native Method)
at java.net.SocketInputStream.socketRead(SocketInputStream.java:116)
at java.net.SocketInputStream.read(SocketInputStream.java:171)
at java.net.SocketInputStream.read(SocketInputStream.java:141)
at java.io.BufferedInputStream.fill(BufferedInputStream.java:246)
at java.io.BufferedInputStream.read1(BufferedInputStream.java:286)
at java.io.BufferedInputStream.read(BufferedInputStream.java:345)
- locked <0x00000007b01c1240> (a java.io.BufferedInputStream)
at org.apache.thrift.transport.TIOStreamTransport.read(TIOStreamTransport.java:127)
複製代碼
該線程被阻塞在了一個方法上,問題就在這裏:建立鏈接的線程被阻塞在等待與Impala
建連的通信數據上,後續全部鏈接的獲取都必然會天然等待到超時。那麼該線程的狀態能夠恢復嗎?url
模擬一下這種異常狀況,使用nc -l ${impala-port}
監聽本地的端口,同時用將鏈接url的地址host到本地,運行程序。由於本地不存在Impala
服務,因此天然響應不了這個建連過程,同時咱們將url修改host至正確的Impala
地址,會發現CreateConnectionThread
線程會一直保持被阻塞狀態,沒有恢復(取消本地端口監聽能夠時線程脫離阻塞狀態)。
那麼如何解決這個問題呢?主要是避免建連線程一直阻塞,有幾個方向:
read timeout
、socket timeout
createScheduler
變量,避免單線程建連TODO HiveDriver 建連代碼分析