三分鐘講透:MySQL CPU 500% 的排查與優(yōu)化套路
大家好呀,我是小米,31歲,坐標(biāo)在一個(gè)天天和 MySQL 打交道的技術(shù)部,平時(shí)喜歡折騰技術(shù),也喜歡把踩過的坑講成段子,分享給大家。
今天要聊的題目,是很多小伙伴在社招面試時(shí)可能被問到過的一個(gè)經(jīng)典問題:
“如果 MySQL 數(shù)據(jù)庫 CPU 飆升到 500%,你會(huì)怎么處理?”
當(dāng)時(shí)我第一次被問到這個(gè)問題的時(shí)候,腦子里第一反應(yīng)是:“完蛋,這服務(wù)器怕不是要冒煙了吧!”但是冷靜下來想想,這類問題其實(shí)考察的并不是你背答案,而是你有沒有處理線上問題的思路和能力。
那今天,就讓我給大家拆解一下這個(gè)問題,同時(shí)用一個(gè)小故事的方式,把我在真實(shí)項(xiàng)目里踩過的坑分享給你們。
1.故事開場:凌晨兩點(diǎn)的報(bào)警電話
事情發(fā)生在去年的某個(gè)深夜。
那天我剛準(zhǔn)備進(jìn)入美夢(mèng),突然手機(jī)叮的一聲,一條報(bào)警短信彈出來:
告警:MySQL CPU 使用率 500%,請(qǐng)立即處理!
我整個(gè)人瞬間清醒。500%是個(gè)什么概念?我們機(jī)器是 8 核的,500% 就是 5 核被壓榨得死死的,服務(wù)器分分鐘可能宕機(jī)。
于是我立刻披上外套,打開電腦遠(yuǎn)程登錄服務(wù)器。接下來,就是一場和“CPU 飆升”的較量。
2.第一步:到底是不是 MySQL 的鍋?
當(dāng)遇到 CPU 飆升時(shí),第一件事不是慌,而是要先定位元兇。
我敲下了熟悉的命令:

果然,mysqld 進(jìn)程赫然在列,占用了絕大多數(shù) CPU。
這一步很關(guān)鍵!因?yàn)楹芏嗳艘簧蟻砭陀X得一定是數(shù)據(jù)庫的鍋,其實(shí)有時(shí)候可能是別的進(jìn)程(比如日志進(jìn)程、惡意腳本)搶資源。
所以總結(jié)一下第一步:
- 先用 top 等操作系統(tǒng)命令,確認(rèn)是不是 mysqld 占用導(dǎo)致的。
- 如果不是,那就去追查別的進(jìn)程。
- 如果是,那就進(jìn)入下一步
3.第二步:誰在數(shù)據(jù)庫里搗亂?
既然是 MySQL 占用過高,那接下來要看看:是哪個(gè) SQL 把 CPU 吃爆了。
這時(shí)候經(jīng)典命令登場:
圖片
屏幕上立刻刷出了幾十條正在運(yùn)行的 session。果然,有幾個(gè) SQL 正在跑,而且狀態(tài)卡在 Sending data 上,執(zhí)行了十幾秒還沒結(jié)束。
這就是罪魁禍?zhǔn)琢恕?/p>
那么該怎么辦呢?
- 先確認(rèn) SQL 是誰的:比如是哪個(gè)應(yīng)用、哪個(gè)功能觸發(fā)的。
- 分析 SQL 是否有問題:比如寫得不合理、沒用上索引。
- 檢查數(shù)據(jù)量:有時(shí)候 SQL 沒錯(cuò),但是單表太大,掃描量太多,也會(huì)吃 CPU。
我當(dāng)時(shí)就是先挑出幾個(gè)明顯異常的 session,果斷執(zhí)行:
圖片
CPU 使用率果然立刻從 500% 掉到 200% 左右。這一刀下去,算是止血了,但問題還沒真正解決。
4.第三步:SQL 優(yōu)化與索引
止血之后,我開始分析那幾個(gè)消耗高的 SQL。
拿其中一條來說,大概長這樣:
圖片
聽起來沒啥毛病對(duì)吧?但是當(dāng)我一看執(zhí)行計(jì)劃,發(fā)現(xiàn)它居然在全表掃描!原因是 status != 'CLOSED' 這種寫法,讓索引徹底失效了。
于是我立刻和同事溝通,把 SQL 改成:
圖片
同時(shí)在 customer_id, status 上建了一個(gè)聯(lián)合索引。優(yōu)化后的 SQL 再跑,瞬間就從幾十秒降到毫秒級(jí)。
那一刻我心里只想說:
索引就是數(shù)據(jù)庫的靈魂,寫 SQL 時(shí)不考慮索引,就等著 CPU 飆升吧。
5.第四步:別忘了連接數(shù)的陷阱
不過,CPU 飆升并不一定都是“某幾條 SQL”造成的。
有一次,我遇到的情況是:
每條 SQL 都很正常,執(zhí)行時(shí)間很短,但 CPU 一樣沖到 400%-500%。
后來一查,原來是因?yàn)閼?yīng)用層突然有個(gè) bug,瘋狂建立數(shù)據(jù)庫連接,短時(shí)間內(nèi)涌入了幾百個(gè) session。
這種場景下,你 kill 再多線程也沒用,因?yàn)樾碌倪B接會(huì)源源不斷涌進(jìn)來。
解決辦法就不一樣了:
- 限制數(shù)據(jù)庫最大連接數(shù),防止被沖垮。
- 檢查應(yīng)用層邏輯,為什么會(huì)短時(shí)間內(nèi)有這么多連接?是重試機(jī)制問題?還是連接池沒配置好?
我記得那次,我們?cè)?MySQL 配置里調(diào)整了 max_connections,同時(shí)應(yīng)用端修復(fù)了連接池的 bug,CPU 才徹底恢復(fù)穩(wěn)定。
6.總結(jié)經(jīng)驗(yàn):處理 CPU 飆升的黃金流程
到這里,我已經(jīng)把兩個(gè)最典型的場景講完了。那我們不妨把思路梳理成一個(gè)面試時(shí)能用的黃金流程:
1)確認(rèn) CPU 占用元兇
- 用 top 等命令確認(rèn)是不是 mysqld 占用。
2)查看數(shù)據(jù)庫當(dāng)前線程
- 用 show processlist 找出消耗資源的 SQL。
3)SQL 優(yōu)化與索引調(diào)整
- 檢查執(zhí)行計(jì)劃,優(yōu)化寫法,補(bǔ)充索引。
4)必要時(shí)立即止血
- kill 高消耗線程,觀察 CPU 是否下降。
5)排查并發(fā)連接問題
- 如果是大量 session 導(dǎo)致,就要限制連接數(shù),修復(fù)應(yīng)用邏輯。
6)長期方案
- 調(diào)整內(nèi)存參數(shù)、優(yōu)化表結(jié)構(gòu)、做分庫分表,甚至引入緩存。
圖片
7.面試答題套路
如果你在面試中被問到這個(gè)問題,可以用這樣的思路來回答:
“當(dāng) MySQL CPU 飆升時(shí),我會(huì)先用操作系統(tǒng)命令確認(rèn)是不是數(shù)據(jù)庫導(dǎo)致的,如果不是則排查其他進(jìn)程。如果是 MySQL 的問題,會(huì)通過 show processlist 查看正在運(yùn)行的 session,找出是否有大 SQL 或者執(zhí)行異常的 SQL。如果有高消耗 SQL,會(huì)先 kill 線程止血,再分析執(zhí)行計(jì)劃,看是否缺少索引、SQL 寫法是否合理。如果不是單條 SQL 消耗過高,而是連接數(shù)暴增導(dǎo)致的,我會(huì)和應(yīng)用側(cè)排查為何會(huì)有這么多連接,同時(shí)通過限制連接數(shù)來緩解壓力。最后再根據(jù)情況做持久優(yōu)化,比如加索引、改 SQL、調(diào)參數(shù)?!?/p>
這樣一套邏輯下來,面試官肯定會(huì)覺得你對(duì)線上問題的處理有條理。
8.彩蛋:小米的踩坑教訓(xùn)
最后給大家分享一個(gè)小插曲:
我第一次遇到 CPU 飆升時(shí),沒想太多,直接一通亂 kill,把好幾個(gè)正常業(yè)務(wù)的 SQL 也殺了,結(jié)果引發(fā)了線上小故障,被領(lǐng)導(dǎo)批評(píng)了一頓。
所以后來我學(xué)會(huì)了一個(gè)原則:
先觀察,后下手;先止血,后優(yōu)化。
殺線程只是臨時(shí)措施,真正的解決方案永遠(yuǎn)是優(yōu)化 SQL 和系統(tǒng)架構(gòu)。
9.結(jié)語
好了,今天的分享就到這里啦。
如果你正在準(zhǔn)備 Java 社招面試,這道題一定要爛熟于心,因?yàn)樗还饪紨?shù)據(jù)庫功底,還考察你遇事冷靜、思路清晰的能力。
希望大家下次被問到:“MySQL CPU 飆升到 500%怎么辦?”,都能胸有成竹地答出來,不再心慌。






























