亚洲综合原千岁中文字幕_国产精品99久久久久久久vr_无码人妻aⅴ一区二区三区浪潮_成人h动漫精品一区二区三

主頁 > 知識庫 > 低版本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導致線程阻塞、性能受限的相關信息資訊供網民參考!
  • 推薦文章
    亚飞与亚基在线观看| 亚洲天堂在线播放| 日韩在线观看视频免费| 精品国产一区二区三区久久久狼| 韩国三级香港三级日本三级| 青青久在线视频| 日本在线不卡免费视频一区| 日本特黄特色aa大片免费| 成人免费高清视频| 日韩免费片| 欧美a级片免费看| 午夜在线亚洲| 久久国产一区二区| 在线观看成人网 | 免费国产在线观看不卡| 亚洲爆爽| 香蕉视频久久| 欧美一级视频免费观看| 国产高清在线精品一区二区| 欧美另类videosbestsex视频| 可以免费在线看黄的网站| 99色播| 四虎影视库| 99久久精品国产麻豆| 香蕉视频一级| 国产一级强片在线观看| 欧美一区二区三区在线观看| 国产不卡在线播放| 欧美18性精品| 久草免费在线色站| 免费国产在线观看不卡| 九九干| 国产成人精品综合久久久| 久久精品大片| 久久国产精品自由自在| 欧美18性精品| 国产伦久视频免费观看 视频| 久久精品成人一区二区三区| 可以在线看黄的网站| 国产福利免费观看| 日韩中文字幕在线亚洲一区 | 午夜家庭影院| 色综合久久天天综合| 国产91精品一区二区| 香蕉视频一级| 日本久久久久久久 97久久精品一区二区三区 狠狠色噜噜狠狠狠狠97 日日干综合 五月天婷婷在线观看高清 九色福利视频 | 国产a视频精品免费观看| 一 级 黄 中国色 片| 精品视频在线看| 日韩一级黄色大片| 亚洲精品久久久中文字| 国产a视频| 日本久久久久久久 97久久精品一区二区三区 狠狠色噜噜狠狠狠狠97 日日干综合 五月天婷婷在线观看高清 九色福利视频 | 国产综合成人观看在线| 韩国毛片免费| 韩国毛片免费| 日韩av成人| 四虎影视库| 日本在线不卡免费视频一区| 国产91素人搭讪系列天堂| 国产成人精品影视| 四虎影视久久久| 亚欧成人乱码一区二区| 四虎影视久久久| 精品视频一区二区三区| 亚洲女初尝黑人巨高清在线观看| 一级女性全黄生活片免费| 91麻豆国产级在线| 亚洲第一色在线| 亚洲 国产精品 日韩| 精品国产一区二区三区久| 精品久久久久久中文字幕一区| 日本特黄特色aa大片免费| 九九久久国产精品| 九九久久国产精品大片| 中文字幕一区二区三区精彩视频| 亚洲爆爽| 久久福利影视| 欧美激情一区二区三区视频| 成人免费网站视频ww| 精品国产一区二区三区久 | 精品国产一区二区三区久久久蜜臀| 999久久久免费精品国产牛牛| 国产高清视频免费| 好男人天堂网 久久精品国产这里是免费 国产精品成人一区二区 男人天堂网2021 男人的天堂在线观看 丁香六月综合激情 | 日本在线不卡免费视频一区| 国产福利免费视频| 免费国产在线视频| 九九精品久久| 黄视频网站在线观看| 韩国三级视频在线观看| 毛片电影网| 精品视频在线看| 精品国产一级毛片| 青青久在线视频| 欧美另类videosbestsex高清| 国产高清在线精品一区a| 久草免费在线观看| 国产一级生活片| 亚欧成人乱码一区二区| 精品国产三级a| 成人高清护士在线播放| 久草免费在线色站| 国产精品自拍亚洲| 欧美另类videosbestsex视频| 精品视频在线观看一区二区三区| 日韩在线观看视频网站| 毛片成人永久免费视频| 国产高清视频免费| 亚洲 国产精品 日韩| 国产亚洲免费观看| 欧美激情一区二区三区视频 | 精品久久久久久影院免费| 91麻豆国产级在线| 久久国产精品自由自在| 亚久久伊人精品青青草原2020| 91麻豆国产| 国产亚洲精品aaa大片| 九九精品久久| 国产一区精品| 四虎久久影院| 日日夜人人澡人人澡人人看免| 一级女人毛片人一女人| 九九热国产视频| 青青久在线视频| 精品视频免费看| 久久国产影视免费精品| 国产福利免费观看| 国产91精品一区二区| 成人免费一级毛片在线播放视频| 久久精品道一区二区三区| 欧美日本二区| 欧美另类videosbestsex视频| 欧美一级视频高清片| 91麻豆tv| 免费国产在线视频| 国产精品免费精品自在线观看| 精品视频一区二区三区| 天天做日日爱夜夜爽| 日本伦理片网站| 亚洲精品影院| 精品久久久久久综合网| 欧美激情一区二区三区视频 | 欧美激情一区二区三区在线播放 | 国产一区二区精品久久| 韩国三级香港三级日本三级la| 成人在免费观看视频国产| 日日夜人人澡人人澡人人看免| 高清一级片| 午夜在线影院| 欧美一级视频免费观看| 国产亚洲男人的天堂在线观看| 国产不卡在线播放| 精品毛片视频| 韩国三级视频在线观看| 精品久久久久久中文字幕一区 | 久久福利影视| 亚洲女人国产香蕉久久精品| 日韩欧美一及在线播放| 亚飞与亚基在线观看| 欧美1卡一卡二卡三新区| 四虎影视库国产精品一区| 国产国语在线播放视频| 国产麻豆精品免费密入口| 国产亚洲男人的天堂在线观看| 久久国产一区二区| 欧美国产日韩久久久| 日日夜人人澡人人澡人人看免| 韩国三级香港三级日本三级la| 91麻豆精品国产综合久久久| 在线观看成人网 | 久久国产一区二区| 九九久久99| 国产91精品露脸国语对白| 在线观看成人网 | 香蕉视频久久| 99色视频在线观看| 91麻豆精品国产片在线观看| 欧美a级片免费看| 天天做人人爱夜夜爽2020 | 欧美激情一区二区三区视频 | 四虎影视久久久| 成人a大片高清在线观看| 精品久久久久久中文字幕一区 | 日韩中文字幕一区二区不卡| 久久国产影院| 国产一区二区精品| 午夜激情视频在线播放| 99久久精品国产高清一区二区| 美女免费精品高清毛片在线视 | 天天色色色| 精品国产一区二区三区国产馆| 亚洲精品久久久中文字| 欧美大片a一级毛片视频| 国产国语对白一级毛片| 欧美日本二区| 亚洲 国产精品 日韩| 免费国产一级特黄aa大片在线| 欧美电影免费看大全| 香蕉视频久久|