?背景
我們公司正在處于某個項目的維護階段,領導對資源告警比較重視,服務器資源告警的就不說了,運維同學每隔一小時都會檢測線上環境的應用服務信息,例如:網關日志響應時間告警/nginx日志接口響應時間告警/日志關鍵字異常日志告警等,每周都需要對告警信息的排查分析~
都是通過郵件發送給干系人~
?例如,這個是郵件信息截圖~
?排查思路
日志--【檢索】->traceId--【skywaling】->完整的調用鏈信息
1.從日志中查到TraceId。
2.通過TraceId獲取調用鏈
通過traceId在skywalking中的可視化界面上可以看出獲取數據庫鏈接就花費了7百多毫秒
大家無需糾結接口花費了6s多,而本次卻在重點說獲取鏈接池的情況。其他的可以從代碼或者sql進行入手優化~~只是獲取數據庫鏈接耗時較多,所以著重進行了分析。
3.查看該應用的數據庫鏈接池配置
druid:# 初始化時建立物理連接的個數initial-size: 20# 最大連接池數量max-active: 100# 最小連接池數量min-idle: 20# 獲取連接時最大等待時間max-wait: 60000# 是否緩存preparedStatement,也就是PSCache。pool-prepared-statements: false# 要啟用PSCache,必須配置大于0,當大于0時,poolPreparedStatements自動觸發修改為true。max-pool-prepared-statement-per-connection-size: -1# 用來檢測連接是否有效的sql,要求是一個查詢語句,常用select 'x'。validation-query: SELECT 'x'# 單位:秒,檢測連接是否有效的超時時間。validation-query-timeout: 1# 申請連接時執行validationQuery檢測連接是否有效,做了這個配置會降低性能。test-on-borrow: false# 歸還連接時執行validationQuery檢測連接是否有效,做了這個配置會降低性能。test-on-return: false# 建議配置為true,不影響性能,并且保證安全性。申請連接的時候檢測,如果空閑時間大于timeBetweenEvictionRunsMillis,執行validationQuery檢測連接是否有效。test-while-idle: true# 有兩個含義:1) Destroy線程會檢測連接的間隔時間,如果連接空閑時間大于等于minEvictableIdleTimeMillis則關閉物理連接。2) testWhileIdle的判斷依據,詳細看testWhileIdle屬性的說明time-between-eviction-runs-millis: 6000# 連接保持空閑而不被驅逐的最小時間min-evictable-idle-time-millis: 1200000max-evictable-idle-time-millis: 1800000# 監控頁面相關配置stat-view-servlet:url-pattern: /druid/*allow: ""enabled: true
4.獲取該應用數據庫鏈接池的監控(需要對應的時間段)
從圖中可以看出PoolingCount在這個時刻突然下降,突然下降可能表示有突發流量
詳細解釋(poolingCount
?)
在數據庫連接池監控中,poolingCount
?是一個重要的監控指標,它表示當前連接池中空閑的、可用的數據庫連接數量。
含義
poolingCount
?表示連接池中當前處于空閑狀態、可以被應用程序直接獲取使用的連接數量這些連接已經創建并與數據庫建立了連接,但暫時沒有被應用程序使用
它是連接池中"準備好的"連接的數量
相關指標對比
在常見的連接池實現中,通常會有以下相關指標:
指標名稱 | 含義 |
---|---|
poolingCount | 當前空閑連接數 |
activeCount | 當前活躍連接數(正在被使用的連接) |
maxActive | 連接池最大允許的連接數 |
minIdle | 連接池保持的最小空閑連接數 |
maxIdle | 連接池允許的最大空閑連接數 |
監控意義
性能調優依據:
如果?
poolingCount
?經常為0,可能表明連接池配置過小如果?
poolingCount
?長期很高,可能表明配置過大
問題診斷:
poolingCount
?突然下降可能表示有突發流量poolingCount
?長期低位可能表示連接泄漏
容量規劃:
結合?
activeCount
?和?poolingCount
?可以評估連接池使用情況幫助確定合適的?
maxActive
?和?minIdle
?參數
? 圖表匯總分析(監控時間:近6小時)
1. IdleConnection(空閑連接)
大部分時間維持在 20 左右,直到接近 14:00 時突然拉升。
說明:
min-idle: 20
已經生效,Druid 正在努力維持至少 20 個空閑連接。
2. PoolingCount(連接池中的連接總數)
長期穩定在 5~10 左右,你說的問題驗證了。
但注意這個指標來源標注為
TotalConnection(...)
,它并非嚴格意義的“空閑連接數”,可能是連接池當前存在的連接總數(和 Idle + Active 的關系要確認 exporter 定義)。
3. ActiveConnection(活躍連接數)
絕大多數時間活躍連接在 0~2 之間;
即使接近 14:00 的高峰期,也只有少量連接(<10)在活躍使用;
? 說明系統當前數據庫并發負載是低的。
4. ThreadsAwaitingConnection(等待獲取連接的線程數)
全程為 0;
? 說明連接池沒有連接耗盡問題,應用線程從不需等待連接。
5. MaxConnection(連接池歷史最大并發連接數)
常態是 4,只有在快到 14:00 時突增至 200;
猜測是某個服務(或某次壓測)在那個時段拉高了連接數。
? 結論
項目 | 結論 |
---|---|
min-idle 是否生效? | ? 是的,空閑連接維持在 20 |
是否存在連接不足 / 堵塞? | ? 沒有。activeCount 、waitThreadCount 都非常低 |
是否需要增加 min-idle? | ? 目前不需要,現有配置已滿足需求 |
是否要擴大連接池? | ? 不需要,max-active: 100 遠超實際并發需求 |
當前鏈接數在22左右,超過了預熱的的鏈接數20,所以需要與mysql中建立鏈接。
思考:
但是為什么與mysql建立鏈接這么長時間?
1.mysql的監控
Threads Cached = 1
意味著什么?
這表示:
當前 MySQL 有 1 個空閑線程 在等待下一個連接復用;
如果有新連接請求到來,MySQL 可以立刻用這 1 個線程處理,而 無需調用
pthread_create()
創建新線程;
重點觀察圖表分析
1.?線程緩存 (MySQL Thread Cache
)
Threads Created
?幾乎為 0,說明線程緩存有效;但?
Threads Cached
?明顯有下降段(21:45 前后出現斷崖);?表示短時間內大量連接請求導致緩存線程被用完,需新建線程。
這會造成連接響應變慢,尤其是連接池新建連接時要與數據庫創建新線程,代價高。
2.?臨時表 (MySQL Temporary Objects
)
每秒創建臨時表數在 4~5 個,且偶爾觸發?
Created Tmp Disk Tables
(磁盤臨時表);說明存在大量使用?
GROUP BY
、ORDER BY
、子查詢、聯合查詢等臨時表消耗。
?磁盤臨時表嚴重影響 SQL 響應速度,從而增加連接持有時間。
3.?排序 (MySQL Sorts
)
Sort Rows
?高峰時可達 30~40;Sort Scan
?也非 0,說明未命中索引的排序操作存在。
?排序越多、越復雜,單個 SQL 執行越慢 → 應用端連接持有時間越長 → 導致連接池空閑不足。
4.?Select Types 分布
Select Scan
?穩定在高位,說明存在大量全表掃描;Select Range
?較低,表示索引未能充分利用。
5.?慢查詢 (MySQL Slow Queries
)
21:45 左右出現明顯慢 SQL 峰值,最高達 1.45/s;
時間點與線程緩存耗盡、臨時表升高高度吻合!
綜合分析:導致連接獲取慢的根因
MySQL 層 | 臨時表多 / 排序多 / 索引未命中 | SQL 響應時間延長,連接被長時間占用 |
MySQL 層 | Thread Cache 命中率下降 | 新建線程成本高,拖慢新連接初始化 |
應用層 | 連接池配置不足 / minIdle 過低 | 無法預熱足夠連接,應對突發請求 |
應用層 | SQL 過慢 + 連接未及時釋放 | 導致連接池回收和復用效率變差 |
?優化建議
A. MySQL 層建議
慢查詢排查 | 開啟?slow_query_log ,排查 21:45 的慢 SQL |
索引優化 | 優化?SELECT SCAN ?多的表結構,添加合適聯合索引 |
避免臨時表 | 檢查是否有復雜嵌套子查詢 / group by 未配 index |
調大線程緩存 | thread_cache_size = 128 |
臨時表優化 | 調整?tmp_table_size ?和?max_heap_table_size ?至 128M 起步 |
排序優化 | 優化?ORDER BY ?相關 SQL,能使用索引就用索引 |
B. 應用層建議(Druid)
spring:datasource:druid:initial-size: 30min-idle: 30max-active: 100max-wait: 30000validation-query: SELECT 1test-on-borrow: truetest-while-idle: truetime-between-eviction-runs-millis: 5000remove-abandoned: trueremove-abandoned-timeout: 180log-abandoned: true
重點說明:
initial-size
,?min-idle
: 提高初始連接和空閑連接數,快速預熱;test-on-borrow
: 確保連接可用,避免使用“死連接”;remove-abandoned
: 回收長時間未關閉連接,防止泄露;max-wait
: 縮短應用等待連接時間,提高失敗可控性;
總結一句話:
MySQL 當前存在執行慢 / 緩存線程耗盡 / 排序臨時表密集的問題,間接導致應用端連接獲取慢,連接池設置不當進一步放大了問題
當前mysql數據庫設置:
SHOW VARIABLES LIKE 'thread_cache_size';
68?
將thread_cache_size 調整到128后,后續再看結果