欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

druid連接泄露故障全面分析

 更新時間:2023年12月18日 09:48:41   作者:人工博客  
這篇文章主要介紹了druid連接泄露故障全面分析,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教

1、問題的如何發(fā)生的

1.1、應(yīng)用功能介紹

系統(tǒng)是一個雙數(shù)據(jù)源雙寫單獨的服務(wù)。

(兩個數(shù)據(jù)源是不同的存儲,所以無法使用主從復(fù)制的模式,是一個切換存儲介質(zhì)的過渡態(tài))。

歷史代碼有個更新邏輯update xx set a=b where m=n。

但是這個表中的記錄超10億。遇到需要更新的記錄比較多的場景下存在問題。

故對這個進(jìn)行了sql優(yōu)化。采用的邏輯是查詢出需要更新的記錄id,然后分頁更新。

1.2、關(guān)鍵代碼

雙數(shù)據(jù)源操作

private Object runSql(List<String> sqlSessionFactotyBeanNameList, MethodInvocation invocation)
            throws InvocationTargetException, IllegalAccessException {
        List<SqlSession> sqlSessionList = Lists.newArrayList();
        Object result = null;
        try {
            for (String sessionFactotyBeanName : sqlSessionFactotyBeanNameList) {
                SqlSessionFactory sqlSessionFactory =
                        RgApplicationContextUtil.getBean(
                                sessionFactotyBeanName, SqlSessionFactory.class);
                SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
                Object mapper = sqlSession.getMapper(invocation.getMethod().getDeclaringClass());
                Object[] param = invocation.getArguments();
                result = invocation.getMethod().invoke(mapper, param);
                sqlSessionList.add(sqlSession);//問題代碼,注意!!!!
                sqlSession.commit();
            }
        } catch (Exception ex) {
            sqlSessionList.stream()
                    .forEach(
                            x -> {
                                x.rollback();
                            });
        } finally {
            sqlSessionList.stream()
                    .forEach(
                            x -> {
                                x.close();
                            });
        }
        return result;
    }

問題的sql

<select id="getBatchIdWithLimit" resultType="java.lang.Long">
	SELECT x.id FROM context x WHERE x.oid = #{oid} ORDER BY id ASC
	LIMIT #{offset}, #{limit}
</select>

關(guān)鍵的配置

maxWait 獲取連接時最大等待時間,單位毫秒。配置了maxWait之后,缺省啟用公平鎖,并發(fā)效率會有所下降,如果需要可以通過配置useUnfairLock屬性為true使用非公平鎖。

當(dāng)前系統(tǒng)此參數(shù)未進(jìn)行配置,所以會無限等待,使用的是公平鎖

1.3、問題出現(xiàn)的步驟

  • sql中存在問題,部分?jǐn)?shù)據(jù)的長度超過Integer的最大值(2147483647),映射存在問題。
  • 雙數(shù)據(jù)源代碼存在bug。 List的代碼結(jié)合的 add 位置過于落后,導(dǎo)致反射出現(xiàn)異常的時候。當(dāng)次的SqlSession未關(guān)聯(lián)到待處理的集合中,進(jìn)而也就未rollback和close。造成鏈接泄露。
  • 當(dāng)出現(xiàn)問題的數(shù)據(jù)的時候,結(jié)合雙數(shù)據(jù)源的代碼的bug。會造成List為空,所以未進(jìn)行釋放操作,(鏈接泄露了)
  • 當(dāng)前系統(tǒng)最大的連接數(shù)是100,出現(xiàn)了100次這樣的數(shù)據(jù),這個服務(wù)就回?zé)o盡的等待獲取鏈接中的狀態(tài)。

1.4、問題的表象

image-20210601165753462

代碼的問題點

2、如何復(fù)現(xiàn)問題

2.1、問題數(shù)據(jù)復(fù)現(xiàn)

  • 把數(shù)據(jù)庫的最大連接數(shù)調(diào)整成1,maxWaitTime不設(shè)置
  • 構(gòu)造一條id大于2147483647的數(shù)據(jù)
  • 使用api 觸發(fā)調(diào)用到這個邏輯
  • 結(jié)果是:第一次調(diào)用報錯,第二次調(diào)用會卡的客戶端設(shè)置的超時時間。

2.2、數(shù)據(jù)庫連接異常復(fù)現(xiàn)

還有一種路徑是代碼都沒問題,但是由于高并發(fā)造成數(shù)據(jù)庫是鎖。mybatis是可以設(shè)置sql的執(zhí)行時長的。一旦出現(xiàn)了這種場景。問題也是會出現(xiàn)的。

但是這種場景比較難以復(fù)現(xiàn),那么有沒有一種手段可以高效的偽造這個場景。

準(zhǔn)備知識

set autocommit=0;  //關(guān)閉數(shù)據(jù)的事務(wù)自動提交
SELECT * FROM xxx a WHERE a.id='111' for update; //獲取數(shù)據(jù)庫的行鎖
commit;//提交事務(wù)

數(shù)據(jù)默認(rèn)是自動提交的,所以前置set autocommit=0;這個操作不要忘記了,踩過幾次坑。完成后執(zhí)行commit;進(jìn)行解鎖。

測試完畢記得set autocommit=1;來恢復(fù)數(shù)據(jù)庫的事務(wù)自動提交的特性。

  • 準(zhǔn)備一條接口測試用的數(shù)據(jù)
  • 執(zhí)行sql select …for update 進(jìn)行行記錄鎖定
  • 接口調(diào)用使用同一個id進(jìn)行請求。因為記錄鎖定了,所以api的更新是失敗了,成功的偽造了高并發(fā)形成了行鎖造成的sql問題

3、問題總結(jié)

  • 數(shù)據(jù)庫的保護(hù)配置:maxActive、maxWait都配置上,相當(dāng)于熔斷保護(hù)
  • mybatis對象映射需要關(guān)注數(shù)據(jù)的范圍
  • 利用select for update制造行鎖偽造高并發(fā)造成的數(shù)據(jù)問題

以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • SpringBoot實現(xiàn)統(tǒng)一封裝返回前端結(jié)果集的示例代碼

    SpringBoot實現(xiàn)統(tǒng)一封裝返回前端結(jié)果集的示例代碼

    在實際項目開發(fā)過程中,我們經(jīng)常將返回數(shù)據(jù)的基本形式統(tǒng)一為JSON格式的數(shù)據(jù)。但項目可能是由很多人開發(fā)的,所以我們最好將返回的結(jié)果統(tǒng)一起來。本文介紹了SpringBoot實現(xiàn)統(tǒng)一封裝返回前端結(jié)果集的示例代碼,需要的可以參考一下
    2022-06-06
  • 在Java中如何避免創(chuàng)建不必要的對象

    在Java中如何避免創(chuàng)建不必要的對象

    作為Java開發(fā)者,我們每天創(chuàng)建很多對象,但如何才能避免創(chuàng)建不必要的對象呢?這需要我們好好學(xué)習(xí),這篇文章主要給大家介紹了關(guān)于在Java中如何避免創(chuàng)建不必要對象的相關(guān)資料,需要的朋友可以參考下
    2021-10-10
  • java 調(diào)用wsdl協(xié)議接口簡單實用方法最新推薦

    java 調(diào)用wsdl協(xié)議接口簡單實用方法最新推薦

    文章介紹了如何使用POM導(dǎo)入依賴,并編寫一個測試類來調(diào)用不同的Web服務(wù)接口,通過訪問接口地址,我們可以獲取請求和返回的body,并進(jìn)一步解析返回的JSON結(jié)果,感興趣的朋友一起看看吧
    2025-03-03
  • Spring Boot 快速入門指南

    Spring Boot 快速入門指南

    Spring 框架是非常著名的 Java 開源框架,歷經(jīng)十多年的發(fā)展,整個生態(tài)系統(tǒng)已經(jīng)非常完善甚至是繁雜,Spring Boot 正是為了解決這個問題而開發(fā)的,為 Spring 平臺和第三方庫提供了開箱即用的設(shè)置,只需要很少的配置就可以開始一個 Spring 項目
    2017-03-03
  • 記錄jdk21連接SQLServer因為TLS協(xié)議報錯問題

    記錄jdk21連接SQLServer因為TLS協(xié)議報錯問題

    在使用Druid連接池連接SQL Server時,可能會遇到因TLS版本不匹配導(dǎo)致的連接失敗問題,具體表現(xiàn)為客戶端使用TLS1.3或TLS1.2,而SQL Server僅支持TLS1.0,導(dǎo)致無法建立安全連接,解決方法是修改JDK的安全配置,啟用TLS1.0
    2024-10-10
  • Java獲取UTC時間的方法詳解

    Java獲取UTC時間的方法詳解

    這篇文章主要介紹了Java獲取UTC時間的方法,結(jié)合具體實例形式詳細(xì)分析了Java針對時區(qū)、本地時間、時間偏移量等相關(guān)操作技巧,需要的朋友可以參考下
    2017-04-04
  • Java學(xué)習(xí)關(guān)于循環(huán)和數(shù)組練習(xí)題整理

    Java學(xué)習(xí)關(guān)于循環(huán)和數(shù)組練習(xí)題整理

    在本篇文章里小編給各位整理了關(guān)于Java學(xué)習(xí)關(guān)于循環(huán)和數(shù)組練習(xí)題相關(guān)內(nèi)容,有興趣的朋友們跟著參考學(xué)習(xí)下。
    2019-07-07
  • SpringCloud Netfilx Ribbon負(fù)載均衡工具使用方法介紹

    SpringCloud Netfilx Ribbon負(fù)載均衡工具使用方法介紹

    Ribbon是Netflix的組件之一,負(fù)責(zé)注冊中心的負(fù)載均衡,有助于控制HTTP和TCP客戶端行為。Spring Cloud Netflix Ribbon一般配合Ribbon進(jìn)行使用,利用在Eureka中讀取的服務(wù)信息,在調(diào)用服務(wù)節(jié)點時合理進(jìn)行負(fù)載
    2022-12-12
  • Javassist用法詳解

    Javassist用法詳解

    這篇文章主要介紹了Javassist用法的相關(guān)資料,幫助大家更好的理解和學(xué)習(xí)使用Java,感興趣的朋友可以了解下
    2021-02-02
  • 詳解SpringBoot整合RabbitMQ如何實現(xiàn)消息確認(rèn)

    詳解SpringBoot整合RabbitMQ如何實現(xiàn)消息確認(rèn)

    這篇文章主要介紹了SpringBoot整合RabbitMQ是如何實現(xiàn)消息確認(rèn)的,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-05-05

最新評論