最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

MySQL數(shù)據(jù)庫(kù)CPU飆升到500%的原因和解決方案

 更新時(shí)間:2026年02月27日 09:09:49   作者:嘻哈baby  
這篇文章討論了MySQL?CPU使用率高達(dá)500%的問(wèn)題,并提出了滅火、查因、防復(fù)發(fā)的處理步驟,滅火包括找到并終止問(wèn)題SQL,查因涉及分析全表掃描、鎖等待和排序等,防復(fù)發(fā)則包括優(yōu)化索引、限制連接數(shù)、應(yīng)用層限流和緩存等措施,需要的朋友可以參考下

CPU 500%意味著MySQL吃掉了好幾個(gè)核,基本上是某些SQL在瘋狂消耗計(jì)算資源。這種情況下不要急著重啟——重啟只是把問(wèn)題藏起來(lái)了,過(guò)一會(huì)兒還會(huì)炸。

先滅火,再查因,最后防復(fù)發(fā)。按這個(gè)順序來(lái)。

滅火:先找到罪魁禍?zhǔn)?/h2>

登上服務(wù)器,第一件事不是看MySQL,是看操作系統(tǒng)。

top -Hp $(pidof mysqld)

這條命令列出mysqld進(jìn)程下所有線程的CPU占用。找到CPU最高的那幾個(gè)線程,記下它們的LWP(輕量級(jí)進(jìn)程ID)。

然后進(jìn)MySQL:

SHOW PROCESSLIST;

或者更詳細(xì)的版本:

SELECT id, user, host, db, command, time, state, info 
FROM information_schema.processlist 
WHERE command != 'Sleep' 
ORDER BY time DESC;

重點(diǎn)看 command 不是Sleep的連接——Sleep的連接是空閑的,不吃CPU???time 列,跑了幾百秒甚至幾千秒的查詢大概率就是兇手。info 列顯示正在執(zhí)行的SQL。

找到了問(wèn)題SQL之后,如果業(yè)務(wù)允許,直接殺掉:

KILL <process_id>;

這一步的目的是止血。CPU降下來(lái)之后,你才有余裕去分析根因。如果不先殺掉問(wèn)題查詢,服務(wù)器可能連登錄都卡。

查因:為什么這條SQL吃這么多CPU

CPU飆升的原因,90%以上是這幾種情況。

全表掃描。 一條查詢沒(méi)走索引,掃了幾百萬(wàn)行甚至幾千萬(wàn)行。每一行都要從磁盤(pán)讀到內(nèi)存(如果Buffer Pool裝不下的話),然后逐行比較WHERE條件。CPU的消耗主要在"逐行比較"這一步。

拿到問(wèn)題SQL之后,用EXPLAIN看一下:

EXPLAIN SELECT ... ;

如果 type 列是 ALL,rows 列是幾百萬(wàn),那就是全表掃描???key 列是不是NULL——NULL說(shuō)明沒(méi)用上任何索引。

鎖等待引發(fā)的連鎖反應(yīng)。 一條慢SQL持有行鎖,后面的請(qǐng)求全部排隊(duì)等鎖。等待的連接越來(lái)越多,每個(gè)連接都占一個(gè)線程,MySQL的線程調(diào)度開(kāi)銷就上去了。這種情況下CPU高不是因?yàn)樵?quot;計(jì)算",而是因?yàn)樵?quot;調(diào)度"。

SELECT * FROM information_schema.innodb_trx 
ORDER BY trx_started ASC;

這條命令列出所有活躍事務(wù),按開(kāi)始時(shí)間排序。跑了最久的那個(gè)事務(wù)大概率是罪魁禍?zhǔn)?mdash;—它持有鎖不釋放,后面的事務(wù)全部堵住了。

SELECT * FROM performance_schema.data_lock_waits;

這條(MySQL 8.0+)能看到誰(shuí)在等誰(shuí)的鎖。如果 BLOCKING_ENGINE_TRANSACTION_ID 指向的事務(wù)已經(jīng)跑了很久,考慮殺掉它。

排序和臨時(shí)表。ORDER BYGROUP BY 的查詢,如果排序字段沒(méi)有索引,MySQL會(huì)在內(nèi)存里(或者磁盤(pán)上)建臨時(shí)表做排序。數(shù)據(jù)量一大,排序本身就是CPU密集型操作。

EXPLAIN里看到 Extra 列有 Using filesortUsing temporary,就是這個(gè)情況。

大量短連接。 某些應(yīng)用沒(méi)用連接池,每次請(qǐng)求都新建MySQL連接、用完就斷開(kāi)。MySQL創(chuàng)建和銷毀連接的開(kāi)銷不小(要做認(rèn)證、分配線程、初始化會(huì)話變量)。如果QPS很高,光是連接管理就能把CPU吃滿。

SHOW GLOBAL STATUS LIKE 'Threads_created';
SHOW GLOBAL STATUS LIKE 'Connections';

如果 Threads_created 的值很高且在快速增長(zhǎng),說(shuō)明在頻繁創(chuàng)建新線程。正常情況下,連接池會(huì)復(fù)用線程,Threads_created 應(yīng)該增長(zhǎng)很慢。

常見(jiàn)場(chǎng)景的具體處理

場(chǎng)景一:某條慢SQL導(dǎo)致CPU飆升

這是最常見(jiàn)的情況。處理步驟:

殺掉問(wèn)題查詢 → EXPLAIN分析 → 加索引或改寫(xiě)SQL → 驗(yàn)證。

加索引的時(shí)候注意:在生產(chǎn)環(huán)境給大表加索引,MySQL 5.6之前會(huì)鎖表,5.6之后支持Online DDL,但仍然會(huì)消耗大量IO。如果表有幾千萬(wàn)行,加索引可能要跑幾分鐘到幾十分鐘,期間會(huì)影響寫(xiě)入性能。

建議在業(yè)務(wù)低峰期操作,或者用 pt-online-schema-change 工具:

pt-online-schema-change --alter "ADD INDEX idx_user_status(user_id, status)" \
  D=mydb,t=orders --execute

這個(gè)工具的原理是創(chuàng)建一張新表、加上索引、通過(guò)觸發(fā)器同步數(shù)據(jù)、最后原子性地rename。對(duì)線上業(yè)務(wù)的影響比直接ALTER TABLE小很多。

場(chǎng)景二:大事務(wù)持有鎖導(dǎo)致連鎖堵塞

SELECT trx_id, trx_state, trx_started, trx_mysql_thread_id, trx_query
FROM information_schema.innodb_trx
WHERE trx_started < NOW() - INTERVAL 60 SECOND;

找到跑了超過(guò)60秒的事務(wù),看它在干什么。如果是一個(gè)忘記提交的事務(wù)(trx_query 為NULL說(shuō)明當(dāng)前沒(méi)在執(zhí)行SQL,但事務(wù)還開(kāi)著),直接殺掉對(duì)應(yīng)的連接:

KILL <trx_mysql_thread_id>;

然后去排查應(yīng)用代碼——大概率是某個(gè)地方開(kāi)了事務(wù)忘記commit/rollback,或者事務(wù)里做了不該做的事(比如在事務(wù)里調(diào)了外部HTTP接口,接口超時(shí)導(dǎo)致事務(wù)一直掛著)。

場(chǎng)景三:突發(fā)流量導(dǎo)致CPU飆升

不是某條SQL有問(wèn)題,而是正常的SQL突然來(lái)了十倍的量。這種情況加索引沒(méi)用,因?yàn)槊織lSQL本身都很快,只是量太大了。

短期應(yīng)對(duì):

SET GLOBAL max_connections = 500;

限制最大連接數(shù),超出的請(qǐng)求直接拒絕,保護(hù)MySQL不被打死。比讓所有請(qǐng)求都卡住要好——至少一部分請(qǐng)求能正常處理。

中期方案:應(yīng)用層加限流、加緩存。把熱點(diǎn)查詢的結(jié)果緩存到Redis,大部分請(qǐng)求不打到MySQL。

長(zhǎng)期方案:讀寫(xiě)分離,讀請(qǐng)求分散到從庫(kù)。

預(yù)防:別等CPU飆了再處理

開(kāi)慢查詢?nèi)罩尽?/strong> 這是最基本的。

SET GLOBAL slow_query_log = 1;
SET GLOBAL long_query_time = 1;

long_query_time 設(shè)成1秒。很多人設(shè)成10秒,那等于只能抓到"已經(jīng)嚴(yán)重影響用戶體驗(yàn)"的查詢。1秒的閾值能讓你提前發(fā)現(xiàn)潛在問(wèn)題。

監(jiān)控線程狀態(tài)。 定期檢查活躍連接數(shù)和長(zhǎng)時(shí)間運(yùn)行的查詢:

SELECT COUNT(*) FROM information_schema.processlist WHERE command != 'Sleep';

活躍連接數(shù)突然飆升,往往是CPU飆升的前兆。配合Prometheus + Grafana做監(jiān)控告警,活躍連接超過(guò)閾值就報(bào)警。

定期審查慢查詢。 每周跑一次 pt-query-digest,看看有沒(méi)有新出現(xiàn)的慢查詢。很多CPU飆升事故不是突然發(fā)生的,而是某條SQL隨著數(shù)據(jù)量增長(zhǎng)越來(lái)越慢,從100ms慢到1秒,從1秒慢到10秒,最后某天數(shù)據(jù)量過(guò)了臨界點(diǎn),直接把CPU打滿。

檢查Buffer Pool命中率。

SHOW GLOBAL STATUS LIKE 'Innodb_buffer_pool_read%';

Innodb_buffer_pool_read_requests(邏輯讀)和 Innodb_buffer_pool_reads(物理讀,即磁盤(pán)讀)算 命中率:1 - 物理讀/邏輯讀。正常應(yīng)該在99%以上。如果低于95%,說(shuō)明Buffer Pool太小,大量數(shù)據(jù)要從磁盤(pán)讀,CPU花在IO等待上的時(shí)間就多了。調(diào)大 innodb_buffer_pool_size,一般設(shè)成物理內(nèi)存的60%-80%。

一個(gè)容易忽略的點(diǎn)

MySQL的CPU飆升有時(shí)候不是MySQL本身的問(wèn)題。

檢查一下服務(wù)器上是不是還跑著別的東西——有些運(yùn)維圖省事,把應(yīng)用服務(wù)和MySQL部署在同一臺(tái)機(jī)器上。應(yīng)用服務(wù)突然吃了大量CPU,MySQL分到的CPU時(shí)間片就少了,本來(lái)100ms能跑完的查詢變成了500ms,連接堆積,惡性循環(huán)。

top 命令看一眼整體CPU分布,如果mysqld不是CPU占用最高的進(jìn)程,那問(wèn)題可能根本不在MySQL。

還有一種情況是OOM Killer。Linux內(nèi)核在內(nèi)存不足的時(shí)候會(huì)殺掉占內(nèi)存最多的進(jìn)程,MySQL經(jīng)常是第一個(gè)被殺的。殺完之后MySQL重啟,Buffer Pool是冷的,所有查詢都要從磁盤(pán)讀數(shù)據(jù),CPU和IO同時(shí)飆升???dmesg | grep -i oom 能確認(rèn)是不是被OOM Killer干掉過(guò)。

線上數(shù)據(jù)庫(kù)出問(wèn)題的時(shí)候,最重要的不是你知道多少優(yōu)化技巧,而是能不能在壓力下保持冷靜、按步驟排查。先止血、再查因、最后防復(fù)發(fā)——這三步的順序不能亂。CPU飆到500%的時(shí)候最怕的操作就是慌了直接重啟,重啟完發(fā)現(xiàn)問(wèn)題還在,又開(kāi)始亂改配置,越改越亂。

以上就是MySQL數(shù)據(jù)庫(kù)CPU飆升到500%的原因和解決方案的詳細(xì)內(nèi)容,更多關(guān)于MySQL CPU飆升到500%的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評(píng)論

新乡县| 平南县| 大名县| 连南| 陈巴尔虎旗| 天峻县| 聂拉木县| 洛川县| 长顺县| 任丘市| 南汇区| 香港 | 德钦县| 惠东县| 铜陵市| 台安县| 安丘市| 永年县| 微博| 定边县| 宁晋县| 得荣县| 齐齐哈尔市| 彩票| 巴南区| 武陟县| 常州市| 潢川县| 上栗县| 屏东市| 榆林市| 视频| 日土县| 丹阳市| 阿荣旗| 鹰潭市| 白玉县| 永川市| 鸡东县| 克山县| 昭觉县|