【轉】Alibaba 的 druid 報錯 discard long time none received connection. 問題


https://blog.51cto.com/u_15101595/2625323

在使用了新版的 druid 以后,日志中一直在報 Error,內容是 discard long time none received connection. , jdbcUrl : 巴拉巴拉,但程序運行並沒有受到影響,但看着一大片錯誤就渾身難受,我決定去他們的源碼里看看到底是怎么回事。網上搜索到的解決方案是回退到1.1.22可解決,但我覺得這樣的解決方案有點傻X,不去想解決問題,而是倒車躲避。

 

看看源碼是誰在報錯

        進到源碼搜索這句「discard long time none received connection.」報錯,在「com.alibaba.druid.pool.DruidAbstractDataSource#testConnectionInternal(com.alibaba.druid.pool.DruidConnectionHolder, java.sql.Connection)」找到如下代碼:

if (valid && isMySql) { // unexcepted branch
    long lastPacketReceivedTimeMs = MySqlUtils.getLastPacketReceivedTimeMs(conn);
    if (lastPacketReceivedTimeMs > 0) {
        long mysqlIdleMillis = currentTimeMillis - lastPacketReceivedTimeMs;
        if (lastPacketReceivedTimeMs > 0 //
                && mysqlIdleMillis >= timeBetweenEvictionRunsMillis) {
            discardConnection(holder);
            String errorMsg = "discard long time none received connection. "
                    + ", jdbcUrl : " + jdbcUrl
                    + ", version : " + VERSION.getVersionNumber()
                    + ", lastPacketReceivedIdleMillis : " + mysqlIdleMillis;
            LOG.warn(errorMsg);
            return false;
        }
    }
}

 

        我來解釋一下,MySqlUtils.getLastPacketReceivedTimeMs(conn) 是獲取上一次使用的時間,mysqlIdleMillis 就是計算出來空閑的時間,timeBetweenEvictionRunsMillis 是個寫死的值 60秒,if (lastPacketReceivedTimeMs > 0 && mysqlIdleMillis >= timeBetweenEvictionRunsMillis) 就是如果連接空閑了 60秒以上,那就 discardConnection(holder) 丟棄這個舊連接並順帶打印了一個日志 LOG.warn(errorMsg)。

 

明白原理以后做點什么

         經過我Google查詢一通,有個人給出了一個方法,可以配置「druid.mysql.usePingMethod=false」原理是讓驗證空閑連接使用 select 1,而不是使用MySQL的Ping,這樣就刷新了上次使用時間,不會出現空閑 60秒以上的連接,在運行參數中增加:-Ddruid.mysql.usePingMethod=false

 

 

        查看valid變量賦值的地方,跟蹤源碼在MySqlValidConnectionChecker類的configFromProperties的方法中可以看到可以配置變量druid.mysql.usePingMethod=false,這樣就不會通過ping的方式去檢查鏈接的有效性,從而不會打印該error log。durid版本1.2.1

    public void configFromProperties(Properties properties) {
        String property = properties.getProperty("druid.mysql.usePingMethod");
        if ("true".equals(property)) {
            setUsePingMethod(true);
        } else if ("false".equals(property)) {
            setUsePingMethod(false);
        }
    }

 

阿里他們為什么要清空空閑60秒以上的連接

        我猜測,阿里他們給數據庫設置的數據庫空閑等待時間是60秒,mysql數據庫到了空閑等待時間將關閉空閑的連接,以提升數據庫服務器的處理能力。MySQL的默認空閑等待時間是8小時,就是「wait_timeout」的配置值。如果數據庫主動關閉了空閑的連接,而連接池並不知道,還在使用這個連接,就會產生異常。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM