1. 案例
成某三甲醫預約系統, 該專案在2024年初進行上線測試,在正常執行了兩天後,業務系統報錯:The connection pool has been exhausted, either raise MaxPoolSize (currently 800) or Timeout (currently 15 seconds)。金倉開發人員跟進分析,具體排查步驟如下:
1.1 是否是高併發導致的問題
首先是對業務系統進行了梳理,使用者業務系統圖如下:
透過對使用者現場業務系統的分析,錯誤是業務系統報出的,業務系統處理第三方訊息平臺傳送的請求,第三方訊息平臺收集簽到機和其它裝置傳送的請求。業務系統高峰期時,同時請求的請求可以達到10條左右。併發量並不大,排除併發量導致的連線池爆池;
1.2 查詢伺服器端的連線數
金倉資料庫系統表:sys_stat_activity中,記錄了每個連線的資訊,可以透過如下的語句來查詢具體業務的連線數:
select state,query from pg_stat_activity where application_name=‘ksql’;
透過加入定時命令,每隔1秒鐘都會查詢一下對應業務開啟的資料庫連線數。在業務量最大時,查詢到的連線數達到了800個。並且大多數連線的狀態為:Idle in transcation,意味著有大量連線開啟了事務,但沒有任何操作。是因為連線數池上限過小的問題嗎?繼續將連線池的上限修改,修改為所允許的最大值。結果連線數依舊可以達到連線上限1200。上述現象不符合驅動kdbndp連線池的迴圈使用機制。這裡需要介紹一下金倉驅動kdbndp的連線池機制:
1.2.1 Kdbndp連線池-連線池狀態
連線池有三個計數器:
Idle:空閒連線計數器
Busy:正在使用連線計數器
Waiting:等待獲取連線物件計數器
1.2.2 連線池中無連線-申請連線流程
1.2.3 連線池已經存在連線-申請連線流程
1.2.4 連線池釋放連線—應用退出
1.2.5 連線池釋放連線—連線空閒達到設定時間(預設5分鐘)
1.2.6 連線池滿-處理流程
1.2.7 連線池引數介紹
Pooling:
是否開啟連線池,true:開發連線池,false:關閉連線池,預設值:true
Minimum Pool Size
連線池保持最小連線數,預設值:0
Maximum Pool Size
連線池可以建立連線額最大數,預設值:100
Connection Idle Lifetime
空閒連線空閒時間達到的時間值,到達該時間值時,可以回收該連線,預設值:300(秒)
Connection Pruning Interval
空閒連線回收之前等待時間,預設值:10(秒)
從連線池設計的機制來看,一般連線使用結束之後,是釋放回到連線池中;而現場問題中存在大量建立物理連線,將連線池撐爆的現象存在。而且大量物理連線的狀態為:Idle in transcation,至此,我們找到了導致連線池爆池的原因。
1.3 分析Idle in transcation
Idle in transcation:當資料連線處於“Idle in transcation”狀態時,意味著連線已經開啟了事物,但沒有任何操作(如提交或回滾)來結束這個事務。我們將KingbaseES+sugar框架的結構圖梳理出來,進一步的定位問題,結果圖如下:
業務流程訪問資料庫的資料經過了如下步驟:
1> 定義實體資料模型,實體模型模型是編寫程式的依據;
2>業務系統呼叫SqlSugar介面,建立物件時,業務程式碼編寫人員可以指定使用SqlSugar的模式,推薦使用的是單例模式SqlSugarScope,該模式是執行緒安全的。在建立物件的時候,指定訪問的資料庫是哪一家的,DbType。Kdbndp中有一個引數DbModeType,指定使用哪種資料庫模式,兩者有異曲同工之妙;這個時候,我們也指定了我們訪問的資料庫,訪問資料庫使用的連線引數等資訊;
3>還是呼叫SqlSugar介面,SqlSugar會將對應介面的操作,對映、翻譯為對應的sql語句,呼叫Kdbndp的執行介面,將語句傳送到伺服器端;
4>伺服器端執行之後,執行結果又透過Kdbndp的功能介面,回到SqlSugar,根據對映關係,將結果存放至模型物件中,業務系統透過獲取模型物件中的資料,完成業務資料展示的處理流程。
上述流程中,步驟二中,建立單例模式的訪問物件,這個引起了sugar開發人員和金倉開發人員的關注。在SqlSugar建立單例模式時,整個的建立使用流程如下:
在建立單例項模式中,開始了事務,在使用結束之後,需要提交事務,使用commit介面CommitTran(),提交事務,釋放Kdbndp連線物件;如果只是將sqlsugar單例項的物件釋放,不使用提交事務介面完成釋放的話,KdbndpConnection連線不會被釋放,這樣就導致了資料庫中連線處於:Idle in transcation的現象;再次呼叫建立單例項模式物件,採用同樣的流程,連線數開始逐漸的累加起來,直到出現爆池的錯誤。
分析之後,梳理使用者的業務程式碼,果然是在開啟事物之後,呼叫完成退出時沒有做commit操作,導致Kdbndp連線無法回到連線池,無法迴圈使用連線池中連線而導致爆池。
調整業務程式碼,在釋放sqlsugar單例項物件時,做事務提交退出操作。修改之後,連線池中的物理連線保持在20個左右,不再出現爆池的錯誤。迴圈使用連線池的連線,導致伺服器端相關資源消耗下降至原來的1/60。每次任務的提交速度提升了200ms。
現場問題解決了,此過程中,瞭解了kingbase+sugar的一些基礎,在進一步使用中您會發現,
如何避免問題總結
錯誤程式碼
db.BeginTran(); //海量程式碼 if (邏輯) { return;//導致事務沒有提交,寫return很容易漏寫 db.RollbackTran(); } //海量程式碼 db.CommitTran();
正確寫法
try { db.BeginTran(); if (邏輯) { throw new Exception("出錯"); } db.CommitTran();//保證所有出錯都進RollbackTran } catch (Exception) { db.RollbackTran(); }
SqlSugar和人大金倉優點:
1、 功能更新的及時性,因為兩家公司深入合作,彼此產品有新功能的推出,能在第一時間互相溝通,及時釋出;
2、 遮蔽差異化,採用該方案,可以在金倉的多個模式(pg、oracle、mysql)上開發,不用關注模式會帶來額外的配置;
3、 開發的高效性,採用ORM框架,縮短了開發週期,遮蔽了差異化,業務遷移和開發的成本都會降低;
4、 實時的技術支援,以在多個專案中得到驗證,雙方的高效合作,為使用者的定製開發、問題定位提供及時的技術支援。