一次性講清楚「連接池獲取連接慢」的所有原因
一、前言
應(yīng)用連接數(shù)據(jù)庫基本上都是通過連接池去連接,比如常用的 HikariCP、Druid 等,在應(yīng)用運行期間經(jīng)常會出現(xiàn)獲取連接很慢的場景,大多數(shù)同學(xué)都是一頭霧水,不知道從哪下手。而且很多時候都是偶發(fā)場景,讓人頭疼不已,別著急,本文帶你逐步剖析獲取連接慢的所有可能的原因,以及對應(yīng)的調(diào)優(yōu)手段,讓你成為連接池排障大師。
二、連接池監(jiān)控
排查問題的前提是發(fā)現(xiàn)問題,所以首先需要有連接池的詳細(xì)監(jiān)控,下面我們以 HikariCP 為例,簡單介紹幾個常用的指標(biāo)的含義。
圖片
圖片
圖片
對應(yīng)應(yīng)用程序比較敏感的時間就是獲取連接耗時,因為它是同步的會直接影響鏈路的RT,下面我們就來逐步分析造成這個獲取連接耗時較高的所有可能性以及解決方案。
三、排查思路
連接池存在等待連接
獲取連接耗時較高最直接的原因就是存在等待連接數(shù),這種情況直接觀測等待連接數(shù)的大盤即可
圖片
那么又有哪幾種情況會導(dǎo)致存在等待連接數(shù)呢?
- 連接池容量過小
如果日常的活躍連接數(shù)/總連接比例持續(xù)很高,或者 QPS * AVG-RT(s) > 連接總數(shù)說明當(dāng)前連接池的最大連接數(shù)已經(jīng)不足以支撐當(dāng)前的流量,如何解決?
適當(dāng)增加連接池最大連接數(shù):連接數(shù)也不是越大越好,一般是根據(jù) CPU 核數(shù)決定,HikariCP 官方給出了一個公式可以做一下參考,最大連接數(shù)一般不要超過 50。
core_count 為core的數(shù)量 effective_spindle_count 為掛載的磁盤數(shù)量。
core_count 為core的數(shù)量 effective_spindle_count 為掛載的磁盤數(shù)量。
- 應(yīng)用擴(kuò)容:如果連接數(shù)調(diào)大后,仍然無法解決,說明單機(jī)的連接數(shù)已經(jīng)達(dá)到上限,需要對應(yīng)用進(jìn)行擴(kuò)容,但是需要注意擴(kuò)容節(jié)點的數(shù)量,單機(jī)連接數(shù)*節(jié)點數(shù)量不要超過數(shù)據(jù)庫支持的最大連接數(shù)
有慢查詢&長事務(wù)
- 慢SQL
慢 SQL 相對來說比較好排查,數(shù)據(jù)庫或者數(shù)據(jù)庫中間件都有成熟的慢 SQL 采集工具。只需要分析一下指定時間段內(nèi)是否有慢 SQL 即可。 如果SQL 優(yōu)化空間比較低,可以把慢 SQL 和核心業(yè)務(wù)分 2 個數(shù)據(jù)源,防止慢 SQL 影響正常核心業(yè)務(wù)。
- 長事務(wù)
長事務(wù)是很容易忽略的一種 case,可以通過觀測連接使用時間指標(biāo)和 SQL 耗時來分析,如果連接使用平均耗時遠(yuǎn)大于 SQL 平均耗時,那么說明有長事務(wù)。還可以根據(jù) HikariCP 自帶的連接泄露檢測來分析,當(dāng)連接被借出后長時間未歸還(超過配置的閾值 leak-detection-threshold=30000)會打印借出時的堆棧,可以幫助我們快速定位。
圖片
還可以通過 RDS 的 SQL 洞察來分析是否有長事務(wù),如果使用 Spring+JDBC 管理事務(wù)的情況下,開啟事務(wù)的命令是 SET autocommit=0,提交事務(wù)是 commit,這里根據(jù)數(shù)據(jù)庫線程 ID 來逐個分析,提交事務(wù)的時間-開啟事務(wù)的時間=事務(wù)持續(xù)時間。
應(yīng)用負(fù)載過高
由于 HikariCP、Druid 在從連接池借出連接時,會有一個同步探活的操作,比如直接 MySQL 的 PING 命令或執(zhí)行 select 'X' 等,因為有網(wǎng)絡(luò) IO,所以這里會讓當(dāng)前線程進(jìn)入阻塞狀態(tài)讓出 CPU 時間片。
圖片
在 CPU 繁忙時,執(zhí)行完網(wǎng)絡(luò) IO 后等待獲取 CPU 時間片的時間較長,最終表現(xiàn)的結(jié)果就是獲取連接時間拉長。這種 case 的分析手段比較簡單,直接通過觀測應(yīng)用的 CPU 和 Load 指標(biāo)即可。
應(yīng)用STW
在獲取連接方法開始到結(jié)束期間,如果應(yīng)用發(fā)生了 STW,就會導(dǎo)致獲取連接耗時升高,需要結(jié)合 JVM 監(jiān)控 &GC 日志來分析,關(guān)于 GC 分析不是本文重點,這里簡單列舉幾個重點說明一下(以 ZGC 舉例)。
- JVM 監(jiān)控存在 Allocation Stall(垃圾回收阻塞,會暫停線程)或者暫停時間較長。
圖片
圖片
- GC 日志相對于監(jiān)控會更為準(zhǔn)確一點,把日志文件直接丟到 https://gceasy.ycrash.cn/ 里面分析一下即可,會輸出詳細(xì)的報告,重點關(guān)注一下 STW 時間和分配阻塞。
圖片
圖片
網(wǎng)絡(luò)阻塞
這一類問題比較難以排查,具有偶發(fā)性和難以觀測的特點,網(wǎng)絡(luò)阻塞也分好幾種情況。
- 網(wǎng)絡(luò)抖動
這是最常見的一種情況,一般我們可以通過觀測應(yīng)用所在主機(jī)的 TCP 重傳監(jiān)控是否有尖刺,但這里要注意下,TCP 重傳不代表一定是網(wǎng)絡(luò)抖動,也可能是網(wǎng)絡(luò)帶寬打滿或者數(shù)據(jù)庫 &DAL 異常。
圖片
除了監(jiān)控還可以通過網(wǎng)絡(luò)循環(huán)抓包來分析(主要磁盤容量不要保留太多文件),可以參考以下命令。
抓取 3306 端口的網(wǎng)絡(luò)包,存儲到 3306.pcap 文件中,-C 50 -W 10 代表一個文件最大 50M,最多保留 10 個 tcpdump -i eth0 port 3306 -w 3306.pcap -C 50 -W 10。
然后導(dǎo)入到 WireShark 工具中分析,重點關(guān)注 TCP Retransmission 即 TCP 重傳。
圖片
- 網(wǎng)絡(luò)阻塞
如機(jī)器帶寬打滿,具體表現(xiàn)也是 TCP 重傳,這里可以觀測機(jī)器的帶寬監(jiān)控和機(jī)器支持的最大帶寬做對比,看看是否超過限制。
圖片
數(shù)據(jù)庫&數(shù)據(jù)庫中間件異常
當(dāng)數(shù)據(jù)庫或者數(shù)據(jù)庫中間件出現(xiàn)異常時,對于上游應(yīng)用的表現(xiàn)大多數(shù)就是 SQL RT 增高、TCP 重傳。如果懷疑是數(shù)據(jù)庫或者數(shù)據(jù)庫中間件出現(xiàn)異常,可以先確定自己的應(yīng)用連的是哪個庫,這里可以通過應(yīng)用監(jiān)控(上下游 -RDS)直觀的看到應(yīng)用連接的具體的庫信息,然后再觀測對應(yīng) RDS 和數(shù)據(jù)庫中間件的監(jiān)控進(jìn)一步分析。
圖片
- 如果是數(shù)據(jù)庫中間件域名,就可以看數(shù)據(jù)庫中間件的監(jiān)控大盤。
圖片
如果數(shù)據(jù)庫中間件本身沒有異常,可以繼續(xù)下鉆到 RDS。
圖片
- 如果是 RM/RR 開頭的,說明連的是 RDS,可以看阿里云的 RDS 監(jiān)控,把下面的 Rdsid 替換一下即可。
https://rdsnext.console.aliyun.com/detail/{替換成rdsId}/performance?reginotallow=cn-hangzhou&DedicatedHostGroupId=
重點觀測 CPU內(nèi)存利用率 & IOPS 使用率,也可以框選指定時間段進(jìn)行自動診斷。
圖片
四、總結(jié)
本文列舉了幾乎所有可能導(dǎo)致連接池獲取連接慢的 case,相信看完的讀者以后再遇到此類問題時,再也不會一頭霧水了。學(xué)會自助排查,不光可以提升自己的排障能力,同時也能減輕各位中間件 &DBA 小伙伴的客服壓力。
參考文檔:https://github.com/brettwooldridge/HikariCP/wiki/About-Pool-Sizing