Druid配置參數(shù)詳解-removeAbandoned,logAbandoned,removeAbandonedTimeoutMillis

Druid配置參數(shù)詳解-removeAbandoned,logAbandoned,removeAbandonedTimeoutMillis

Druid是一個(gè)由阿里開(kāi)源的數(shù)據(jù)庫(kù)連接池,Druid的配置非常豐富,但是設(shè)置不當(dāng)會(huì)對(duì)生產(chǎn)環(huán)境造成嚴(yán)重影響,網(wǎng)上Druid的資料雖多,但大部分都是互相復(fù)制粘貼,有很多不準(zhǔn)確甚至完全錯(cuò)誤的描述,Druid已經(jīng)開(kāi)源很久,而且作者WenShao的工作重心也已經(jīng)不在Druid上,有些功能估計(jì)他自己都不太了解了。本系列將從源代碼的角度分析Druid目前的最新版本(1.1.21)各個(gè)常用的配置項(xiàng)的具體含義以及是怎么起作用的。

畫(huà)外音:目前Druid在開(kāi)源中國(guó)舉辦的2019年度最受歡迎中國(guó)開(kāi)源軟件中排名第7名,支持Druid的朋友可以去投票哇。2019年度最受歡迎中國(guó)開(kāi)源軟件

removeAbandoned,logAbandoned,removeAbandonedTimeoutMillis是什么意思?

removeAbandoned:如果連接泄露,是否需要回收泄露的連接,默認(rèn)false;
logAbandoned:如果回收了泄露的連接,是否要打印一條log,默認(rèn)false;
removeAbandonedTimeoutMillis:連接回收的超時(shí)時(shí)間,默認(rèn)5分鐘;

畫(huà)外音:這兩個(gè)參數(shù)筆者認(rèn)為非常重要,但是不知為何,Druid默認(rèn)是不開(kāi)啟的,并且官方的配置例子中也沒(méi)有配置這兩個(gè)參數(shù):Druid官方配置筆者就因?yàn)闆](méi)有配置這兩個(gè)參數(shù),曾經(jīng)吃過(guò)大虧

removeAbandoned,logAbandoned,removeAbandonedTimeoutMillis有什么用?

舉個(gè)栗子:筆者當(dāng)初做過(guò)單個(gè)事務(wù)使用多數(shù)據(jù)源的功能,重寫(xiě)了Spring的ConnectionHolder,由于筆者的疏忽,每次從ConnectionHolder中獲取連接時(shí)都獲取到了兩條連接,但是只是使用了其中的一條,相當(dāng)于另一條連接只是從連接池中拿出來(lái)了,但是再也不會(huì)還回去了,這樣就導(dǎo)致了連接池中的連接很快就消耗光了,即activeCount=maxActive。

如果當(dāng)時(shí)我設(shè)置了removeAbandoned就不會(huì)出現(xiàn)這個(gè)問(wèn)題,應(yīng)該Druid會(huì)定期檢查池中借出去的連接是否處于運(yùn)行狀態(tài),如果不是處于運(yùn)行狀態(tài),并且借出時(shí)間超過(guò)removeAbandonedTimeoutMillis(默認(rèn)5分鐘)就會(huì)回收該連接。

連接是怎么回收的?

Druid每隔timeBetweenEvictionRunsMillis(默認(rèn)1分鐘)會(huì)調(diào)用DestroyTask,在這里會(huì)判斷是否可以回收泄露的連接

    public class DestroyTask implements Runnable {
        public DestroyTask() {

        }

        @Override
        public void run() {
            shrink(true, keepAlive);
            //判斷removeAbandoned是否為true,默認(rèn)是false,不知為何
            if (isRemoveAbandoned()) {
                removeAbandoned();
            }
        }

    }

            for (; iter.hasNext();) {
                DruidPooledConnection pooledConnection = iter.next();
                
                //判斷該連接是否還在運(yùn)行,只回收不運(yùn)行的連接
                //Druid會(huì)在連接執(zhí)行query,update的時(shí)候設(shè)置為正在運(yùn)行,
                // 并在回收后設(shè)置為不運(yùn)行
                if (pooledConnection.isRunning()) {
                    continue;
                }

                long timeMillis = (currrentNanos - pooledConnection.getConnectedTimeNano()) / (1000 * 1000);
                
                //判斷連接借出去的時(shí)間大小
                if (timeMillis >= removeAbandonedTimeoutMillis) {
                    iter.remove();
                    pooledConnection.setTraceEnable(false);
                    abandonedList.add(pooledConnection);
                }
            }
                //判斷是否要記錄連接回收日志,這個(gè)很重要,可以及時(shí)發(fā)現(xiàn)項(xiàng)目中是否有連接泄露
                if (isLogAbandoned()) {
                    StringBuilder buf = new StringBuilder();
                    buf.append("abandon connection, owner thread: ");
                    buf.append(pooledConnection.getOwnerThread().getName());
                    buf.append(", connected at : ");
                    buf.append(pooledConnection.getConnectedTimeMillis());
                    buf.append(", open stackTrace\n");
                }

總結(jié)

筆者認(rèn)為這三個(gè)參數(shù)非常重要,但是官方默認(rèn)是不開(kāi)啟的,建議使用Druid的項(xiàng)目都設(shè)置這三個(gè)參數(shù),這樣可以有效的發(fā)現(xiàn)代碼中是否有連接泄露。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容