Druid鏈接Impala持續失敗緣由調查

一個使用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()方法實現的,調用的時機和方式有如下幾種:服務器

  • 初始化時直接調用
  • CreateConnectionThread 線程實例調用
  • CreateConnectionTask 任務實例調用

當用戶沒有設置 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()方法調用過一次,即鏈接建立線程數量爲 1socket

同時,在項目的配置以下: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線程會一直保持被阻塞狀態,沒有恢復(取消本地端口監聽能夠時線程脫離阻塞狀態)。

那麼如何解決這個問題呢?主要是避免建連線程一直阻塞,有幾個方向:

  • 設置建連過程的超時:此類參數是Driver的鏈接參數,有read timeoutsocket timeout
  • 設置createScheduler變量,避免單線程建連

TODO HiveDriver 建連代碼分析

相關文章
相關標籤/搜索