校园春色亚洲色图_亚洲视频分类_中文字幕精品一区二区精品_麻豆一区区三区四区产品精品蜜桃

主頁 > 知識庫 > 低版本Druid連接池+MySQL驅動8.0導致線程阻塞、性能受限

低版本Druid連接池+MySQL驅動8.0導致線程阻塞、性能受限

熱門標簽:云南電商智能外呼系統價格 高清地圖標注道路 外東北地圖標注 話務外呼系統怎么樣 拉卡拉外呼系統 大眾點評星級酒店地圖標注 智能外呼系統復位 400電話可以辦理嗎 臨清電話機器人

現象

應用升級MySQL驅動8.0后,在并發量較高時,查看監控打點,Druid連接池拿到連接并執行SQL的時間大部分都超過200ms

對系統進行壓測,發現出現大量線程阻塞的情況,線程dump信息如下:

"http-nio-5366-exec-48" #210 daemon prio=5 os_prio=0 tid=0x00000000023d0800 nid=0x3be9 waiting for monitor entry [0x00007fa4c1400000]
   java.lang.Thread.State: BLOCKED (on object monitor)
        at org.springframework.boot.web.embedded.tomcat.TomcatEmbeddedWebappClassLoader.loadClass(TomcatEmbeddedWebappClassLoader.java:66)
        - waiting to lock 0x0000000775af0960> (a java.lang.Object)
        at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1186)
        at com.alibaba.druid.util.Utils.loadClass(Utils.java:220)
        at com.alibaba.druid.util.MySqlUtils.getLastPacketReceivedTimeMs(MySqlUtils.java:372)

根因分析

public class MySqlUtils {

    public static long getLastPacketReceivedTimeMs(Connection conn) throws SQLException {
        if (class_connectionImpl == null  !class_connectionImpl_Error) {
            try {
                class_connectionImpl = Utils.loadClass("com.mysql.jdbc.MySQLConnection");
            } catch (Throwable error){
                class_connectionImpl_Error = true;
            }
        }

        if (class_connectionImpl == null) {
            return -1;
        }

        if (method_getIO == null  !method_getIO_error) {
            try {
                method_getIO = class_connectionImpl.getMethod("getIO");
            } catch (Throwable error){
                method_getIO_error = true;
            }
        }

        if (method_getIO == null) {
            return -1;
        }

        if (class_MysqlIO == null  !class_MysqlIO_Error) {
            try {
                class_MysqlIO = Utils.loadClass("com.mysql.jdbc.MysqlIO");
            } catch (Throwable error){
                class_MysqlIO_Error = true;
            }
        }

        if (class_MysqlIO == null) {
            return -1;
        }

        if (method_getLastPacketReceivedTimeMs == null  !method_getLastPacketReceivedTimeMs_error) {
            try {
                Method method = class_MysqlIO.getDeclaredMethod("getLastPacketReceivedTimeMs");
                method.setAccessible(true);
                method_getLastPacketReceivedTimeMs = method;
            } catch (Throwable error){
                method_getLastPacketReceivedTimeMs_error = true;
            }
        }

        if (method_getLastPacketReceivedTimeMs == null) {
            return -1;
        }

        try {
            Object connImpl = conn.unwrap(class_connectionImpl);
            if (connImpl == null) {
                return -1;
            }

            Object mysqlio = method_getIO.invoke(connImpl);
            Long ms = (Long) method_getLastPacketReceivedTimeMs.invoke(mysqlio);
            return ms.longValue();
        } catch (IllegalArgumentException e) {
            throw new SQLException("getLastPacketReceivedTimeMs error", e);
        } catch (IllegalAccessException e) {
            throw new SQLException("getLastPacketReceivedTimeMs error", e);
        } catch (InvocationTargetException e) {
            throw new SQLException("getLastPacketReceivedTimeMs error", e);
        }
    }

MySqlUtils中的getLastPacketReceivedTimeMs()方法會加載com.mysql.jdbc.MySQLConnection這個類,但在MySQL驅動8.0中類名改為com.mysql.cj.jdbc.ConnectionImpl,所以MySQL驅動8.0中加載不到com.mysql.jdbc.MySQLConnection

getLastPacketReceivedTimeMs()方法實現中,如果Utils.loadClass("com.mysql.jdbc.MySQLConnection")加載不到類并拋出異常,會修改變量class_connectionImpl_Error,下次調用不會再進行加載

public class Utils {

    public static Class?> loadClass(String className) {
        Class?> clazz = null;

        if (className == null) {
            return null;
        }

        try {
            return Class.forName(className);
        } catch (ClassNotFoundException e) {
            // skip
        }

        ClassLoader ctxClassLoader = Thread.currentThread().getContextClassLoader();
        if (ctxClassLoader != null) {
            try {
                clazz = ctxClassLoader.loadClass(className);
            } catch (ClassNotFoundException e) {
                // skip
            }
        }

        return clazz;
    }

但是,在Utils的loadClass()方法中同樣catch了ClassNotFoundException,這就導致loadClass()在加載不到類的時候,并不會拋出異常,從而會導致每調用一次getLastPacketReceivedTimeMs()方法,就會加載一次MySQLConnection這個類

線程dump信息中可以看到是在調用TomcatEmbeddedWebappClassLoader的loadClass()方法時,導致線程阻塞的

public class TomcatEmbeddedWebappClassLoader extends ParallelWebappClassLoader {

 public Class?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
  synchronized (JreCompat.isGraalAvailable() ? this : getClassLoadingLock(name)) {
   Class?> result = findExistingLoadedClass(name);
   result = (result != null) ? result : doLoadClass(name);
   if (result == null) {
    throw new ClassNotFoundException(name);
   }
   return resolveIfNecessary(result, resolve);
  }
 }

這是因為TomcatEmbeddedWebappClassLoader在加載類的時候,會加synchronized鎖,這就導致每調用一次getLastPacketReceivedTimeMs()方法,就會加載一次com.mysql.jdbc.MySQLConnection,而又始終加載不到,在加載類的時候會加synchronized鎖,所以會出現線程阻塞,性能下降的現象

getLastPacketReceivedTimeMs()方法調用時機

public abstract class DruidAbstractDataSource extends WrapperAdapter implements DruidAbstractDataSourceMBean, DataSource, DataSourceProxy, Serializable {

    protected boolean testConnectionInternal(DruidConnectionHolder holder, Connection conn) {
        String sqlFile = JdbcSqlStat.getContextSqlFile();
        String sqlName = JdbcSqlStat.getContextSqlName();

        if (sqlFile != null) {
            JdbcSqlStat.setContextSqlFile(null);
        }
        if (sqlName != null) {
            JdbcSqlStat.setContextSqlName(null);
        }
        try {
            if (validConnectionChecker != null) {
                boolean valid = validConnectionChecker.isValidConnection(conn, validationQuery, validationQueryTimeout);
                long currentTimeMillis = System.currentTimeMillis();
                if (holder != null) {
                    holder.lastValidTimeMillis = currentTimeMillis;
                    holder.lastExecTimeMillis = currentTimeMillis;
                }

                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
                                    + ", jdbcUrl : " + jdbcUrl
                                    + ", lastPacketReceivedIdleMillis : " + mysqlIdleMillis;
                            LOG.error(errorMsg);
                            return false;
                        }
                    }
                }

                if (valid  onFatalError) {
                    lock.lock();
                    try {
                        if (onFatalError) {
                            onFatalError = false;
                        }
                    } finally {
                        lock.unlock();
                    }
                }

                return valid;
            }

            if (conn.isClosed()) {
                return false;
            }

            if (null == validationQuery) {
                return true;
            }

            Statement stmt = null;
            ResultSet rset = null;
            try {
                stmt = conn.createStatement();
                if (getValidationQueryTimeout() > 0) {
                    stmt.setQueryTimeout(validationQueryTimeout);
                }
                rset = stmt.executeQuery(validationQuery);
                if (!rset.next()) {
                    return false;
                }
            } finally {
                JdbcUtils.close(rset);
                JdbcUtils.close(stmt);
            }

            if (onFatalError) {
                lock.lock();
                try {
                    if (onFatalError) {
                        onFatalError = false;
                    }
                } finally {
                    lock.unlock();
                }
            }

            return true;
        } catch (Throwable ex) {
            // skip
            return false;
        } finally {
            if (sqlFile != null) {
                JdbcSqlStat.setContextSqlFile(sqlFile);
            }
            if (sqlName != null) {
                JdbcSqlStat.setContextSqlName(sqlName);
            }
        }
    }

只有DruidAbstractDataSource的testConnectionInternal()方法中會調用getLastPacketReceivedTimeMs()方法

testConnectionInternal()是用來檢測連接是否有效的,在獲取連接和歸還連接時都有可能會調用該方法,這取決于Druid檢測連接是否有效的參數

Druid檢測連接是否有效的參數:

  • testOnBorrow:每次獲取連接時執行validationQuery檢測連接是否有效(會影響性能)
  • testOnReturn:每次歸還連接時執行validationQuery檢測連接是否有效(會影響性能)
  • testWhileIdle:申請連接的時候檢測,如果空閑時間大于timeBetweenEvictionRunsMillis,執行validationQuery檢測連接是否有效
  • 應用中設置了testOnBorrow=true,每次獲取連接時,都會去搶占synchronized鎖,所以性能下降的很明顯

解決方案

經驗證,使用Druid 1.x版本=1.1.22會出現該bug,解決方案就是升級至Druid 1.x版本>=1.1.23或者Druid 1.2.x版本

GitHub issue:https://github.com/alibaba/druid/issues/3808

到此這篇關于低版本Druid連接池+MySQL驅動8.0導致線程阻塞、性能受限的文章就介紹到這了,更多相關MySQL驅動8.0低版本Druid連接池內容請搜索腳本之家以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持腳本之家!

您可能感興趣的文章:
  • MySQL 8.0 驅動與阿里druid版本兼容問題解決
  • MySql 8.0及對應驅動包匹配的注意點說明
  • 關于Mysql8.0版本驅動getTables返回所有庫的表問題淺析
  • 詳解Mybatis逆向工程中使用Mysql8.0版本驅動遇到的問題

標簽:三明 揚州 定西 阿里 無錫 溫州 山西 福州

巨人網絡通訊聲明:本文標題《低版本Druid連接池+MySQL驅動8.0導致線程阻塞、性能受限》,本文關鍵詞  低,版本,Druid,連接,池,+MySQL,;如發現本文內容存在版權問題,煩請提供相關信息告之我們,我們將及時溝通與處理。本站內容系統采集于網絡,涉及言論、版權與本站無關。
  • 相關文章
  • 下面列出與本文章《低版本Druid連接池+MySQL驅動8.0導致線程阻塞、性能受限》相關的同類信息!
  • 本頁收集關于低版本Druid連接池+MySQL驅動8.0導致線程阻塞、性能受限的相關信息資訊供網民參考!
  • 推薦文章
    校园春色亚洲色图_亚洲视频分类_中文字幕精品一区二区精品_麻豆一区区三区四区产品精品蜜桃
    天天av天天翘天天综合网| 日韩精品一区二区三区四区视频| 在线亚洲精品福利网址导航| 欧美日韩国产美| 国产亚洲制服色| 中文字幕乱码亚洲精品一区| 一区二区在线看| 精品制服美女久久| 91网站最新网址| 欧美成人a视频| 怡红院av一区二区三区| 精品一区二区在线播放| 91美女在线看| 精品国产乱码久久久久久夜甘婷婷 | 欧美日韩午夜在线视频| 久久久久九九视频| 亚洲亚洲人成综合网络| 国产裸体歌舞团一区二区| 色综合一区二区| 2021国产精品久久精品 | 欧美日韩精品综合在线| 久久精品水蜜桃av综合天堂| 亚洲一区二区影院| 国产精品自拍av| 欧美女孩性生活视频| 国产精品三级av| 另类欧美日韩国产在线| 色噜噜狠狠一区二区三区果冻| 精品国产乱子伦一区| 亚洲成人av一区二区| 成人精品免费网站| 欧美一区二区三区视频在线观看| 成人欧美一区二区三区在线播放| 久久精品国产久精国产| 欧美日韩在线观看一区二区 | 99精品热视频| 精品国精品国产尤物美女| 亚洲精品v日韩精品| 成人小视频在线观看| 日韩一区二区免费视频| 亚洲一区二区在线视频| 99在线热播精品免费| 久久精品人人爽人人爽| 另类调教123区| 欧美伦理影视网| 一区二区三区在线视频免费| www.亚洲免费av| 久久男人中文字幕资源站| 免费不卡在线视频| 欧美精品v国产精品v日韩精品 | 欧美优质美女网站| 中文字幕一区在线观看视频| 国产成人亚洲综合a∨婷婷| 欧美大片顶级少妇| 日本中文字幕一区二区视频| 精品婷婷伊人一区三区三| 亚洲三级电影全部在线观看高清| 国产.精品.日韩.另类.中文.在线.播放| 日韩免费一区二区三区在线播放| 肉丝袜脚交视频一区二区| 欧美日韩日日摸| 亚洲国产精品久久久久秋霞影院| 在线视频国内自拍亚洲视频| 亚洲乱码中文字幕| 色呦呦一区二区三区| 亚洲视频小说图片| 一本久久精品一区二区| 亚洲精品国产第一综合99久久 | 亚洲婷婷综合色高清在线| 成人福利电影精品一区二区在线观看| 久久伊99综合婷婷久久伊| 国产综合久久久久久鬼色 | 国模大尺度一区二区三区| 精品国产99国产精品| 国内外成人在线| 国产三级一区二区| 成人午夜av电影| 亚洲天堂成人在线观看| 一本久久a久久精品亚洲| 亚洲综合视频网| 欧美日本韩国一区二区三区视频| 午夜电影网亚洲视频| 91精品国产欧美一区二区18 | 久久一二三国产| 国产激情91久久精品导航 | 91麻豆文化传媒在线观看| 亚洲精品视频在线看| 欧美吻胸吃奶大尺度电影 | 日韩精品一区二区三区四区| 韩国欧美国产一区| 中文字幕欧美国产| 色综合久久久久久久久| 午夜精品一区二区三区电影天堂 | 天堂精品中文字幕在线| 日韩欧美视频在线| 国产成人h网站| 一区二区三区日韩在线观看| 欧美乱妇15p| 国产一区二区三区香蕉| 国产精品久久久久久久久图文区 | 男人的天堂久久精品| 精品成人在线观看| 99re视频这里只有精品| 午夜在线电影亚洲一区| xnxx国产精品| 色婷婷av一区二区三区软件 | 日韩欧美成人午夜| 国产凹凸在线观看一区二区| 亚洲精品国产高清久久伦理二区| 91精品国产综合久久久久久| 国产福利视频一区二区三区| 亚洲精选视频在线| 日韩精品中文字幕一区 | 亚洲欧洲成人av每日更新| 欧美日韩精品高清| 国产精品一区二区果冻传媒| 亚洲精品视频在线观看网站| 日韩欧美国产综合在线一区二区三区 | 91在线观看高清| 日韩电影在线免费| 国产精品激情偷乱一区二区∴| 欧美日韩一级视频| 国产精品夜夜爽| 亚洲成人自拍一区| 国产精品美女一区二区三区| 欧美精品乱人伦久久久久久| 成人精品gif动图一区| 日韩精品成人一区二区三区| 国产精品麻豆99久久久久久| 91精品在线麻豆| 97久久超碰国产精品| 精品一区二区三区久久久| 亚洲一区二区在线视频| 国产亚洲一二三区| 这里只有精品99re| 色综合久久中文综合久久牛| 国产一区二区精品久久91| 亚洲18色成人| 成人欧美一区二区三区白人| 日韩免费高清av| 欧美性感一区二区三区| 成人午夜激情影院| 精品一区二区三区视频在线观看| 亚洲午夜精品在线| 日韩一区在线看| 国产日产欧产精品推荐色| 日韩免费成人网| 欧美三级日韩三级国产三级| 波多野结衣的一区二区三区| 激情综合色播五月| 日本女人一区二区三区| 亚洲二区视频在线| 日韩伦理av电影| 国产精品视频看| 久久一区二区视频| 欧美成人三级在线| 91精品国产91热久久久做人人| 在线观看一区不卡| 91蜜桃传媒精品久久久一区二区| 风流少妇一区二区| 国产麻豆精品久久一二三| 久久精品国产久精国产| 日韩av不卡在线观看| 亚洲成人在线观看视频| 亚洲影视在线观看| 一区二区三区毛片| 亚洲欧洲综合另类| 亚洲私人黄色宅男| 亚洲欧洲成人自拍| 中文字幕中文字幕一区| 国产精品色在线| 国产精品热久久久久夜色精品三区 | 丝袜美腿成人在线| 日日摸夜夜添夜夜添国产精品 | 欧美中文字幕一区二区三区| 91丨九色porny丨蝌蚪| 99这里只有久久精品视频| 成人国产精品免费观看视频| 国产高清在线精品| 高清不卡一二三区| 成人app在线观看| 99精品视频一区二区| 91在线观看地址| 91麻豆国产精品久久| 在线亚洲高清视频| 欧美日本一区二区在线观看| 欧美疯狂性受xxxxx喷水图片| 欧美美女一区二区在线观看| 91精品国产一区二区三区| 日韩精品一区二区三区中文精品| 精品久久久网站| 久久亚洲精华国产精华液| 国产欧美一区二区精品忘忧草 | 99精品久久免费看蜜臀剧情介绍| www.欧美色图| 在线欧美日韩精品| 欧美中文字幕一区| 欧美一级日韩一级| 欧美精品一区二区三区高清aⅴ | 粉嫩欧美一区二区三区高清影视|