一个使用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 建连代码分析