MySQL預(yù)編譯語句過多告警排查及解決方案
業(yè)務(wù)背景
在使用Spring Cloud Alibaba搭建的微服務(wù)架構(gòu)中,項(xiàng)目采用ShardingSphere進(jìn)行分庫分表,MyBatis-Plus作為持久層。線上環(huán)境突發(fā)大量預(yù)編譯語句過多
的數(shù)據(jù)庫告警,導(dǎo)致系統(tǒng)性能下降。
排查過程
1. 初步排查:聯(lián)系云數(shù)據(jù)庫廠商
首先,聯(lián)系云數(shù)據(jù)庫服務(wù)廠商協(xié)助排查,確認(rèn)問題是由于預(yù)編譯緩存未被釋放,導(dǎo)致占用過多數(shù)據(jù)庫資源。
2. 排查連接池配置
懷疑問題與連接池有關(guān),特別是考慮到線上負(fù)載較高的高峰時段。經(jīng)過檢查,項(xiàng)目使用的是HikariCP連接池,相關(guān)配置如下:
特別關(guān)注兩個參數(shù):
maxLifetime
: 連接池最大生命周期idleTimeout
: 連接池空閑超時時間
在進(jìn)行斷點(diǎn)調(diào)試后,由于項(xiàng)目使用了Sharding-JDBC,某些參數(shù)并未按照Hikari的默認(rèn)值生效,而是被Sharding進(jìn)行初始化配置。Sharding的相關(guān)代碼如下:
此時可以初步排除連接池配置問題,因?yàn)镾harding已將idleTimeout配置為60秒。
3. 分析HikariCP源碼與Statement Cache問題
深入分析HikariCP源碼,查找與PreparedStatement緩存相關(guān)的內(nèi)容,發(fā)現(xiàn)README.md關(guān)鍵描述:
Statement Cache
HikariCP與其他連接池(如Apache DBCP、Vibur、c3p0等)在處理PreparedStatement
緩存時的區(qū)別:
- HikariCP: 不提供
PreparedStatement
緩存,原因是連接池層級緩存PreparedStatement
只能按連接緩存,導(dǎo)致內(nèi)存占用過大。 - 其他連接池: 許多連接池提供
PreparedStatement
緩存,但這會導(dǎo)致大量PreparedStatement
對象及相關(guān)執(zhí)行計劃在內(nèi)存中存儲,影響性能。
HikariCP并不緩存PreparedStatement
,因?yàn)槎鄶?shù)數(shù)據(jù)庫JDBC驅(qū)動已經(jīng)內(nèi)置緩存機(jī)制,可以跨連接共享執(zhí)行計劃,避免重復(fù)占用內(nèi)存。
要點(diǎn):
- 連接池層級的
PreparedStatement
緩存問題:在連接池層緩存會導(dǎo)致大量內(nèi)存占用,且不支持跨連接共享。 - 數(shù)據(jù)庫驅(qū)動緩存的優(yōu)勢:數(shù)據(jù)庫驅(qū)動層提供的緩存更高效,能夠共享執(zhí)行計劃,減少內(nèi)存占用。
- 反模式:在連接池層進(jìn)行緩存
PreparedStatement
是性能反模式。
4. MySQL驅(qū)動配置分析
進(jìn)一步排查MySQL驅(qū)動,發(fā)現(xiàn)項(xiàng)目使用的mysql-connector-j:8.3.0驅(qū)動,關(guān)鍵配置useServerPrepStmts默認(rèn)為true,即開啟服務(wù)端的預(yù)編譯緩存。而在同一項(xiàng)目中,其他服務(wù)使用的是mysql-connector-java:8.0.16,該版本的默認(rèn)配置為false。
核心代碼:
通過對比,確認(rèn)開啟服務(wù)端預(yù)編譯緩存是導(dǎo)致告警的根本原因。
解決方案
通過排查,最終確定問題原因是服務(wù)端的預(yù)編譯緩存未關(guān)閉。由于項(xiàng)目采用分庫分表,并且在同一數(shù)據(jù)庫實(shí)例中創(chuàng)建了多個Schema,默認(rèn)開啟的服務(wù)端預(yù)編譯緩存容易導(dǎo)致資源占用過高。
解決步驟:
在JDBC連接字符串中添加配置&useServerPrepStmts=false
,關(guān)閉MySQL的服務(wù)端預(yù)編譯緩存。
例如,JDBC連接URL修改如下:
jdbc:mysql://localhost:3306/dbname?useServerPrepStmts=false
配置完成后,重新啟動服務(wù),觀察效果。關(guān)閉服務(wù)端預(yù)編譯緩存后,數(shù)據(jù)庫告警明顯減少,系統(tǒng)性能得到提升。
總結(jié)
通過排查,我們確認(rèn)了預(yù)編譯語句過多
告警的根本原因是MySQL服務(wù)端開啟了預(yù)編譯緩存,導(dǎo)致過多的執(zhí)行計劃占用資源。解決方案是關(guān)閉服務(wù)端的PreparedStatement
緩存,減少系統(tǒng)負(fù)載并提升性能。
到此這篇關(guān)于MySQL預(yù)編譯語句過多告警排查及解決方案的文章就介紹到這了,更多相關(guān)MySQL預(yù)編譯語句過多告警內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
關(guān)于MySQL中“Insert into select“ 的死鎖情況分析
這篇文章主要介紹了關(guān)于MySQL中“Insert into select“ 的死鎖情況分析,死鎖是指兩個或者多個事務(wù)在同一資源上的相互占用,并請求鎖定對方占用的資源,從而導(dǎo)致惡性循環(huán)的現(xiàn)象,需要的朋友可以參考下2023-05-05Mysql select in 按id排序?qū)崿F(xiàn)方法
有時候我們在后臺選擇了一系列的id,我們想安裝填寫id的順序進(jìn)行排序,那么就需要下面的order by方法,測試通過2013-03-03