druid discard long time none received connection問題解析


最新項目中用的druid連接數據庫遇到一個困擾很久的問題

1 開始用的druid版本是1.1.22版本,由於業務需求,單個連接需要執行很久,理論上不需要用到自動回收,但為了安全,還是加了自動回收,時間設置的2個小時。

隨着程序運行,程序經常報The last packet successfully received from the server was XXXXX milliseconds ago.  The last packet sent successfully to the server was 0 mill
iseconds ago錯誤,網上搜索了下答案,有說配置項,改數據庫事件設置,試過都沒有解決,后續看到https://cloud.tencent.com/developer/article/1397508 分析,覺得有一定道理,就開始后續之路

2.druid包升級到1.2.2,原來的問題是沒有了,新的問題出現了,discard long time none received connection,又繼續網上搜索答案,出來的結果一塌糊塗,很多說版本回退到1.1.22,心里不由的說wc,這...

有點扯,繼續進行搜索測試,修改配置項validationQuery,修改testWhileIdle,修改...繼續測試,問題依舊,又搜索到運行時添加druid.mysql.usePingMethod=false,但是沒說怎樣添加,沒辦法下載源碼進行查看,導入源碼后發現如下:

 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;
                        }
                    }
                }

這在配置中加timeBetweenEvictionRunsMillis:1800000 就可以了,個人理解是一次操作數據庫大於這個時間就會被清除,更直觀些就是查詢或其他操作在數據庫執行時間,這里單位是毫秒。

緊接着查看源碼druid.mysql.usePingMethod=false這個設置,既然網上有人說,就看看好使不,源碼如下:

 configFromProperties(System.getProperties());
    }

    @Override
    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);
        }
    }

druid加載System.getProperties(),查看屬性中的druid.mysql.usePingMethod的對應值,如果false,就不用ping方法,否者用ping方法,進一步查看不用ping方法就是用默認select 1,System.getProperties()查看了下一般是系統的一些參數,但是可以put(key,value),程序啟動時間加載進去就可以,項目中用到了定時器(根據自己項目寫就可以,加載一次就ok了),就在初始化時間設置了具體值,代碼如下:

public void contextInitialized(ServletContextEvent arg0) {
        try {
            System.getProperties().put("druid.mysql.usePingMethod", "false");
            // 獲取Scheduler實例
            scheduler = new StdSchedulerFactory().getScheduler();
...

然后取消timeBetweenEvictionRunsMillis設置進行測試,程序跑1個小時沒有任何問題,到此問題解決。

druid個人使用總結:

1.The last packet successfully received from the server was問題升級jar包,我是升級到1.2.2版本

2.discard long time none received connection問題不改程序情況下設置timeBetweenEvictionRunsMillis參數(注意是毫秒),改程序下加System.getProperties().put("druid.mysql.usePingMethod", "false")

druid默認使用usePingMethod方法,此方法並不會更新連接返回時間,導致lastPacketReceivedTimeMs大於timeBetweenEvictionRunsMillis

網上其他的方法感覺要不理解太深,沒有給出具體實現,要不就是復制粘貼的,希望對遇到此問題的人有所幫助。

--------------------------------------------------------分割線---------------------------------------------------------------------------

本以為到此就ok了,運行了一段時間,日志查看又報The last packet successfully received from the server was XXXX  。。。。

這次崩潰了,看來這個問題不是druid版本的問題,經過了兩天的搜索和各種測試,在測試環境下終於100%還原了生產的錯誤,直接說結果,就是沒有解決,重新修改了代碼邏輯。

你沒有看錯,就是沒有找到解決方法,接下來說下我測試的各種方法,首先是修改druid配置參數

minIdle=10
validationQuery=select 1
testWhileIdle=true
testOnBorrow=false
testOnReturn=false
keepAlive=true

  這些參數的各種組合我基本上都試過來了,我的測試場景是用druid獲取連接,執行一次查詢,當前線程停N分鍾,當N>15分鍾時間,以上各種組合都報The last packet successfully received from the server was XXXX錯誤,只有一種情況例外,就是運行程序和數據庫在同一台服務器上,例如連接的數據庫是127.0.0.1,並且在網上搜索發現,有人給出過這個解決方案,就是用localhost或者127.0.0.1。但是我所遇到的是在不同服務器上,最后是修改了邏輯,A模塊運行完成后關閉服務,等待B模塊運行完成后再重新getconnection。

最終的總結和疑問:

 1.項目和數據庫在同一台服務器上時,可以用127.0.0.1去連接本機數據庫避免這個問題的出現。

 2.不在同一服務器上時,修改代碼邏輯,數據庫連接空閑時間控制在10分鍾以內不會報這個錯誤。

疑問:

 1.用c3p0測試,同樣出現這個問題,這個錯誤應該是數據庫拋出的異常,並非是jar拋出的?

 2.druid有keepAlive=true設置,不明白為什么沒有去執行,或者執行的效果和我測試想到的不一致?

 3.我個人想的是連接空閑10分鍾后jar去發送一個select 1的查詢,更新下最后包返回的事件,但是這樣會出現一個問題,會不會影響實際應用單個執行大於10分鍾的應用效果,比如查詢4,5張表的關聯數據報表,用時20分鍾,如果發送select 1去查詢,返回的結果是1顯然不符合實際業務,但是又沒有找到合適的方法去保持連接,由於實際應用沒有用到,等到碰到后再進行測試總結,以后有新的進展再進行更新。


免責聲明!

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



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