亚洲视频二区_亚洲欧洲日本天天堂在线观看_日韩一区二区在线观看_中文字幕不卡一区

公告:魔扣目錄網為廣大站長提供免費收錄網站服務,提交前請做好本站友鏈:【 網站目錄:http://www.430618.com 】, 免友鏈快審服務(50元/站),

點擊這里在線咨詢客服
新站提交
  • 網站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會員:747

CPU 占用過高常見現象

在使用 MySQL 的過程中會遇到各種瓶頸問題,常見的是 IO 瓶頸,但是有時候會出現服務器 CPU 使用率超過 100%,應用頁面訪問慢,登錄服務器負載很高。而導致這個問題竟然是 MySQL 進程,按理說如果 MySQL 運行穩定,服務器的 CPU 資源并不會跑滿,如果出現這個問題,初步可以斷定,是 MySQL 實例中出現了問題 SQL。

CPU 占用過高常見原因

CPU 占用過高常見原因:

  • 服務器硬件問題
  • 內存溢出
  • 業務高并發

如果是業務高并發引起,可以理解為一種業務繁忙的狀態,有可能業務猛增,有可能是定期或者臨時的并發窗口:

  • 數據庫對象設計不合理
  • 觸發器導致
  • 表索引設計不合理
  • 數據庫鎖導致,如行鎖沖突、行鎖等待、鎖超時、死鎖等
  • 系統架構沒有緩存中間件
  • 讀寫分離配置不合理
  • OLTP 系統承載了 OLAP 的業務需求
  • 未合理升級改造為集群環境
  • 未配置異構數據分析系統
  • MySQL 系統參數設置不合理
  • 問題 SQL 導致

SQL 問題導致 CPU 使用率過高是最常見的現象,比如 group by、order by、join 等,這些很大程度影響 SQL 執行效率,從而占用大量的系統資源。

說了這么多常見原因,其實總結一句話來說就是現有系統的現有配置下的現有環境提供不了所需要的數據查詢、分析、執行能力,針對這個問題,首先我們要發現問題的所在,就是說我們要準確的定位問題,然后針對問題進行優化,再考慮其他升級改造的事情。

定位分析問題 SQL

光說不練假把式,接下來我們比劃比劃。

首先,搭建一套模擬環境,這里我讓我的得力助手 DBdeployer 來幫我搭建一套模擬環境。

DBdeployer 是用 Go 語言實現的一款非常強大與高效的部署數據庫環境的開源工具,我們完全可以用它來部署開發、測試環境。如果你對這個助手感興趣,可以看我的另外一篇 Chat。

MySQL 安裝部署:我是如何“秒級”部署 MySQL 集群

使用 DBdeployer 來部署一個單點 5.7.27 版本的 MySQL,并配置一個模擬 CPU 占比高的測試環境。

[root@localhost ~]# dbdeployer deploy single 5.7.27
Database installed in /dbdata/sandboxes/msb_5_7_27
run 'dbdeployer usage single' for basic instructions'
.. sandbox server started

創建測試表:

[root@localhost ~]# cd /dbdata/sandboxes/msb_5_7_27/
[root@localhost msb_5_7_27]# ./use 
mysql [localhost:5727] {msandbox} ((none)) > use test
Database changed
mysql [localhost:5727] {msandbox} (test) > create table t_cpu(id int primary key auto_increment);        
Query OK, 0 rows affected (0.39 sec)

插入大量模擬測試數據:

mysql [localhost:5727] {msandbox} (test) > insert into t_cpu values(),(),(),(),();
Query OK, 5 rows affected (0.06 sec)
Records: 5  Duplicates: 0  Warnings: 0
mysql [localhost:5727] {msandbox} (test) > insert into t_cpu select id+(select count(*) from t_cpu) from t_cpu;
Query OK, 5 rows affected (0.05 sec)
Records: 5  Duplicates: 0  Warnings: 0

......
......

mysql [localhost:5727] {msandbox} (test) > insert into t_cpu select id+(select count(*) from t_cpu) from t_cpu;
Query OK, 5242880 rows affected (1 min 8.84 sec)
Records: 5242880  Duplicates: 0  Warnings: 0

mysql [localhost:5727] {msandbox} (test) > select count(*) from t_cpu;                                         
+----------+
| count(*) |
+----------+
| 10485760 |
+----------+
1 row in set (2.22 sec)

至此我們已經造了 10485760 條數據。

有 1000W+ 的數據量了,我們模擬一個業務場景,讓 CPU 嗨(high)起來。

執行一個慢查詢:

mysql [localhost:5727] {msandbox} (test) > select * from t_cpu order by rand() limit 1;

另外開一個會話,top 看看進程:

top - 15:21:20 up 33 days, 23:10,  3 users,  load average: 0.38, 0.19, 0.21
Tasks: 202 total,   2 running, 200 sleeping,   0 stopped,   0 zombie
%Cpu(s): 23.3 us,  3.6 sy,  0.0 ni, 73.1 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
KiB Mem :  8173716 total,  2867684 free,  1059276 used,  4246756 buff/cache
KiB Swap:  2097148 total,  2097140 free,        8 used.  6761912 avail Mem 

  PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND                                                                              
32232 root      20   0 1443252 356688  11748 S 107.0  4.4   2:03.82 mysqld                                                                               
  296 root      20   0   67044  15588   1440 S   0.7  0.2 325:32.46 plymouthd                                                                            
  600 root      20   0  162032   2360   1580 R   0.3  0.0   0:04.21 top                                                                                  
 1901 gnome-i+  20   0  714116  22436   9168 S   0.3  0.3  98:46.20 gsd-color                                                                            
    1 root      20   0  191264   4192   2632 S   0.0  0.1  18:39.97 systemd                                                                              
    2 root      20   0       0      0      0 S   0.0  0.0   0:01.28 kthreadd                                                                             
    4 root       0 -20       0      0      0 S   0.0  0.0   0:00.00 kworker/0:0H                                                                         
    6 root      20   0       0      0      0 S   0.0  0.0   0:00.95 ksoftirqd/0                                                                          
    7 root      rt   0       0      0      0 S   0.0  0.0   0:02.08 migration/0                                                                          
    8 root      20   0       0      0      0 S   0.0  0.0   0:00.00 rcu_bh               

通過 top 我們發現有一個 32232 的進程使得 CPU 使用率已經超過了 100%。

接下來我們具體分析分析,究竟是什么導致 CPU 使用率達到 100%以上的。

檢查內存使用情況

[root@localhost ~]# free -m
              total        used        free      shared  buff/cache   available
Mem:           7982        1033        2801          40        4147        6604
Swap:          2047           0        2047

內存使用率還可以,應該不是內存影響導致的問題。

檢查服務器線程

方法一:

top -H -p <mysqld 進程 id>

先通過 top 找出占用 CPU 使用率 100% 的 MySQL 進程 32232,在具體查看該進程下的線程情況。

[root@localhost ~]# top -H -p 32232
top - 15:30:32 up 33 days, 23:20,  3 users,  load average: 0.18, 0.15, 0.18
Threads:  28 total,   1 running,  27 sleeping,   0 stopped,   0 zombie
%Cpu(s): 24.4 us,  3.2 sy,  0.0 ni, 72.4 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
KiB Mem :  8173716 total,  2867420 free,  1059520 used,  4246776 buff/cache
KiB Swap:  2097148 total,  2097140 free,        8 used.  6761668 avail Mem 

  PID USER      PR  NI    VIRT    RES    SHR S %CPU %MEM     TIME+ COMMAND                                                                               
32272 root      20   0 1443252 356688  11748 R 99.7  4.4   2:25.74 mysqld                                                                                
32244 root       0 -20 1443252 356688  11748 S  3.7  4.4   0:08.68 mysqld                                                                                
32236 root      20   0 1443252 356688  11748 S  1.7  4.4   0:01.45 mysqld                                                                                
32237 root      20   0 1443252 356688  11748 S  1.7  4.4   0:01.43 mysqld                                                                                
32238 root      20   0 1443252 356688  11748 S  1.3  4.4   0:01.43 mysqld                                                                                
32239 root      20   0 1443252 356688  11748 S  1.3  4.4   0:01.42 mysqld                                                                                
32241 root      20   0 1443252 356688  11748 S  0.3  4.4   0:00.75 mysqld                                                                                
32250 root      20   0 1443252 356688  11748 S  0.3  4.4   0:00.98 mysqld                                                                                
32232 root      20   0 1443252 356688  11748 S  0.0  4.4   0:00.31 mysqld                                                                                
32233 root      20   0 1443252 356688  11748 S  0.0  4.4   0:00.00 mysqld                                                                                
32234 root      20   0 1443252 356688  11748 S  0.0  4.4   0:00.23 mysqld                                                                                
32235 root      20   0 1443252 356688  11748 S  0.0  4.4   0:00.31 mysqld                                                                                
32240 root      20   0 1443252 356688  11748 S  0.0  4.4   0:00.74 mysqld                                                                                
32242 root      20   0 1443252 356688  11748 S  0.0  4.4   0:00.72 mysqld                                                                                
32243 root      20   0 1443252 356688  11748 S  0.0  4.4   0:00.69 mysqld                                                                                
32247 root      20   0 1443252 356688  11748 S  0.0  4.4   0:00.16 mysqld                                                                                
32248 root      20   0 1443252 356688  11748 S  0.0  4.4   0:00.23 mysqld                                                                                
32249 root      20   0 1443252 356688  11748 S  0.0  4.4   0:00.02 mysqld                                                                                
32251 root      20   0 1443252 356688  11748 S  0.0  4.4   0:08.04 mysqld                                                                                
32252 root      20   0 1443252 356688  11748 S  0.0  4.4   0:00.00 mysqld                                                                                
32253 root      20   0 1443252 356688  11748 S  0.0  4.4   0:00.00 mysqld                                                                                
32254 root      20   0 1443252 356688  11748 S  0.0  4.4   0:00.00 mysqld                                                                                
32255 root      20   0 1443252 356688  11748 S  0.0  4.4   0:00.00 mysqld                                                                                
32256 root      20   0 1443252 356688  11748 S  0.0  4.4   0:00.18 mysqld                                                                                
32257 root      20   0 1443252 356688  11748 S  0.0  4.4   0:00.03 mysqld                                                                                
32258 root      20   0 1443252 356688  11748 S  0.0  4.4   0:00.00 mysqld                                                                                
32259 root      20   0 1443252 356688  11748 S  0.0  4.4   0:00.00 mysqld                                                                                
32260 root      20   0 1443252 356688  11748 S  0.0  4.4   0:00.00 mysqld      

結果可以明顯的看到 32272 這個線程的 CPU 使用率異常。

方法二:

pidstat -t -p <mysqld 進程 id> 1 5

先通過 top 找出占用 CPU 使用率 100% 的 MySQL 進程 32232,使用 pidstat 工具在具體查看該進程下的線程情況。

pidstat -t -p 32232 1 5

Average:      UID      TGID       TID    %usr %system  %guest    %CPU   CPU  Command
Average:        0     32232         -   85.00   12.60    0.00   97.60     -  mysqld
Average:        0         -     32232    0.00    0.00    0.00    0.00     -  |__mysqld
Average:        0         -     32233    0.00    0.00    0.00    0.00     -  |__mysqld
Average:        0         -     32234    0.00    0.00    0.00    0.00     -  |__mysqld
Average:        0         -     32235    0.00    0.00    0.00    0.00     -  |__mysqld
Average:        0         -     32236    1.00    0.40    0.00    1.40     -  |__mysqld
Average:        0         -     32237    0.80    0.40    0.00    1.20     -  |__mysqld
Average:        0         -     32238    0.80    0.40    0.00    1.20     -  |__mysqld
Average:        0         -     32239    1.00    0.20    0.00    1.20     -  |__mysqld
Average:        0         -     32240    0.20    0.00    0.00    0.20     -  |__mysqld
Average:        0         -     32241    0.00    0.20    0.00    0.20     -  |__mysqld
Average:        0         -     32242    0.00    0.00    0.00    0.00     -  |__mysqld
Average:        0         -     32243    0.00    0.00    0.00    0.00     -  |__mysqld
Average:        0         -     32244    1.20    1.80    0.00    3.00     -  |__mysqld
Average:        0         -     32247    0.00    0.00    0.00    0.00     -  |__mysqld
Average:        0         -     32248    0.00    0.00    0.00    0.00     -  |__mysqld
Average:        0         -     32249    0.00    0.00    0.00    0.00     -  |__mysqld
Average:        0         -     32250    0.00    0.00    0.00    0.00     -  |__mysqld
Average:        0         -     32251    0.00    0.00    0.00    0.00     -  |__mysqld
Average:        0         -     32252    0.00    0.00    0.00    0.00     -  |__mysqld
Average:        0         -     32253    0.00    0.00    0.00    0.00     -  |__mysqld
Average:        0         -     32254    0.00    0.00    0.00    0.00     -  |__mysqld
Average:        0         -     32255    0.00    0.00    0.00    0.00     -  |__mysqld
Average:        0         -     32256    0.00    0.00    0.00    0.00     -  |__mysqld
Average:        0         -     32257    0.00    0.00    0.00    0.00     -  |__mysqld
Average:        0         -     32258    0.00    0.00    0.00    0.00     -  |__mysqld
Average:        0         -     32259    0.00    0.00    0.00    0.00     -  |__mysqld
Average:        0         -     32260    0.00    0.00    0.00    0.00     -  |__mysqld
Average:        0         -     32272   80.00    9.80    0.00   89.80     -  |__mysqld

結果可以明顯的看到 32272 這個線程的 CPU 使用率異常。

查看 MySQL 進程

在 MySQL 中看看當前連接是否有什么異常。

方法一:

mysql [localhost:5727] {msandbox} ((none)) > show full processlist;
+----+----------+-----------+------+---------+------+---------------------+---------------------------------------------+
| Id | User     | Host      | db   | Command | Time | State               | Info                                        |
+----+----------+-----------+------+---------+------+---------------------+---------------------------------------------+
|  3 | msandbox | localhost | test | Query   |    7 | Creating sort index | select * from t_cpu order by rand() limit 1 |
|  4 | msandbox | localhost | NULL | Query   |    0 | starting            | show full processlist                       |
+----+----------+-----------+------+---------+------+---------------------+---------------------------------------------+
2 rows in set (0.00 sec)

方法二:

mysql [localhost:5727] {msandbox} ((none)) > select * from information_schema.processlist;
+----+----------+-----------+------+---------+------+--------------+----------------------------------------------+
| ID | USER     | HOST      | DB   | COMMAND | TIME | STATE        | INFO                                         |
+----+----------+-----------+------+---------+------+--------------+----------------------------------------------+
|  5 | msandbox | localhost | test | Query   |    2 | Sending data | select * from t_cpu order by rand() limit 1  |
|  6 | msandbox | localhost | NULL | Query   |    0 | executing    | select * from information_schema.processlist |
|  4 | msandbox | localhost | NULL | Sleep   | 1401 |              | NULL                                         |
|  3 | msandbox | localhost | test | Sleep   | 1405 |              | NULL                                         |
+----+----------+-----------+------+---------+------+--------------+----------------------------------------------+
4 rows in set (0.00 sec)

參數說明:

  • id:標識位,MySQL 進程 ID,使用 kill id,可以殺掉某一個進程
  • user:當前連接的用戶
  • host:當前連接的主機
  • db:連接的數據庫
  • command:執行的數據庫操作類型
  • sleep:休眠狀態
  • Query:查詢狀態
  • connect:連接狀態
  • time:已經執行的時間,單位秒
  • info:已經執行的 SQL
  • state:SQL 執行的狀態,結果是 SQL 語句整個執行狀態中的一個,其中包含很多狀態,我們整理如下表:

MySQL 5.7 官方參考MySQL 8.0 官方參考

狀態

含義

After create

當線程使用函數創建表(包括內部臨時表)最后階段會出現這個狀態,即使由于某些錯誤未能創建成功,也會標識該狀態

altering table

服務端正在執行 ALTER TABLE

Analyzing

線程正在計算 MyISAM 引擎表鍵值分布(例如 ANALYZE TABLE)

checking permissions

線程正在檢查服務端是否有執行語句所需要的的權限

Checking table

線程正在執行表的檢查工作

cleaning up

線程已經處理了一個命令,并準備釋放內存并重置某些狀態

Closing tables

線程正在將表中修改的數據刷新到磁盤,同時正在關閉已經用完的表。是一個能很快完成的動作,如果持續完不成,需要確認磁盤空間是否用滿或者磁盤使用的負載很高

converting HEAP to ondisk

線程正在將內部臨時表從 MEMORY 表轉換為磁盤表

copy to tmp table

線程正在執行一個 ALTER TABLE 語句。在創建一個新表,然后將老表記錄復制到新表之前將是此狀態

Copying to group table

如果語句具有不同的條件 ORDER BY 和 GROUP BY 標準,則按組對行進行排序并將其復制到臨時表

Copying to tmp table

服務端正在復制到內存中的臨時表

Copying to tmp table on disk

服務端正在復制到磁盤上的臨時表,臨時結果集變的太大(參考 8.4.4 節,MySQL 內部臨時表的使用),線程正在將臨時表從內存更改為基于磁盤的格式來節省內存

Creating index

線程正在執行 MyISAM 表的 ALTER TABLE ... ENABLE KEYS

Creating sort index

線程正在處理 SELECT 使用內部臨時表

creating table

線程正在創建表,包括創建臨時表

Creating tmp table

線程正在內存中或者磁盤上創建臨時表,如果臨時表在內存中創建之后轉換到磁盤,狀態為 Copying to tmp table on disk

committing alter table to storage engine

服務端完成 ALTER TABLE 并提交結果

deleting from main table

服務端正在執行多表刪除的第一部分,僅刪除第一個表,保存列和偏移量用于刪除其他表

deleting from reference tables

服務端正在執行多表刪除的第二部分,在其他表中刪除匹配的行

discard_or_import_tablespace

線程正在執行 ALTER TABLE ... DISCARD TABLESPACE or ALTER TABLE ... IMPORT TABLESPACE 語句

end

結束狀態,結束之前需要清理 ALTER TABLE, CREATE VIEW, DELETE, INSERT, SELECT, or UPDATE

executing

線程正在執行語句

Execution of init_command

線程正在執行變量 init_command system 中的語句

freeing items

線程執行了一條命令,在此期間完成了一些項目的資源釋放,涉及如查詢緩存,這個狀態之后通常為 cleaning up

FULLTEXT initialization

服務端正在準備執行 natural-language 的全文檢索

init

該狀態在 ALTER TABLE, DELETE, INSERT, SELECT, or UPDATE 初始化之前,服務端在該狀態下會刷新二進制日志和 InnoDB 日志,清理查詢緩存

Killed

有發送了一個 KILL 線程的請求,下次終止前會檢查 kill 標志位。MySQL 會在每次主循環中檢查 kill 標志位,有時該線程并不能立馬殺掉會保留短暫時間,如果該線程被其他線程鎖定,那么 kill 會在鎖釋放后生效

logging slow query

線程正在往慢日志中寫入語句

login

連接線程的初始狀態,直到客戶端成功完成驗證

manage keys

服務端開啟或者關閉表的索引

Opening tables

線程正在打開表,這應該是一個很快的過程,除非有些事情組織了打開表。例如 ALTER TABLE or a LOCK TABLE 會在結束前阻止打開表操作。再就是有必要檢查 table_open_cache 參數的值設置是否足夠大。

optimizing

服務端正在對查詢進行初始化優化

preparing

查詢優化狀態

Purging old relay logs

線程正在刪除不需要的中繼日志

query end

處理完查詢,在 freeing items 之前的狀態

Receiving from client

服務端正在讀取客戶端的包,該狀態在 5.7.8 叫 Reading from net

Removing duplicates

查詢正在使用 SELECT DISTINCT,這個過程 MySQL 在早期階段無法完成,因此需要一個額外的階段在把結果返回給客戶端前需要刪除重復行

removing tmp table

線程在執行完 SELECT 后刪除中間臨時表,如果沒有使用臨時表,無該狀態

rename

重命名表

rename result table

線程正在執行 ALTER TABLE 語句,創建一個新表,重命名新表替換老表

Reopen tables

線程給表加鎖,但是發現在獲取表后發現表結構發生了變化。當釋放鎖,關閉表之后嘗試重新打開表

Repair by sorting

使用排序創建索引修復代碼

preparing for alter table

服務端正準備就地執行 ALTER TABLE

Repair done

線程已完成對 MyISAM 表的多線程修復

Repair with keycache

創建索引緩存修復代碼,比 Repair by sorting 慢的多

Rolling back

線程在回滾事務

Saving state

對于 MyISAM 表的修復和分析操作,線程將新表保存到.MYI 文件頭,狀態包含行數,AUTO_INCREMENT 計數器,鍵值分布之類的信息

Searching rows for update

線程正在執行第一階段查詢未更新的數據,如果更新了索引所在行就會執行有該狀態

Sending data

線程正在讀取和處理 SELECT 的行記錄,發送給客戶端,由于在這個狀態下的操作會執行大量的磁盤訪問(讀),因此它通常是查詢生命周期最長的狀態。

Sending to client

服務端正在給客戶端發送包,在 5.7.8 該狀態叫 Writing to net

setup

線程開始執行 ALTER TABLE 操作

Sorting for group

線程正在做排序來滿足 GROUP BY

Sorting for order

線程正在做排序來滿足 ORDER BY

Sorting index

線程正在做索引頁優化來使得 MyISAM 表優化操作期間有更高效的訪問

Sorting result

對于一個 SELECT 語句,類似不使用臨時表的 Creating sort index

starting

語句執行的第一個狀態

statistics

服務端正在計算統計信息對一個查詢創建執行計劃,如果持續很長時間,服務端可能正在執行其他的操作

System lock

線程調用了 mysqllocktables(),并且一直未更新狀態,這個狀態非常常見,可能有很多原因造成。

update

線程正準備執行更新操作

Updating

線程正在檢索要更新的行并且更新行

updating main table

服務端正在執行多表更新的第一部分,僅更新第一個表,保存列和偏移量用于更新其他表

updating reference tables

服務端正在執行多表更新的第二部分,在其他表中更新匹配的行

User lock

線程正在使用 GET_LOCK()請求或等待一個意向鎖,對于 SHOW PROFILE 這個狀態意味著線程請求鎖(但是不等鎖)

User sleep

線程正在調用 SLEEP()

Waiting for commit lock

FLUSH TABLES WITH READ LOCK 正在等待一個提交鎖

Waiting for global read lock

FLUSH TABLES WITH READ LOCK 正在等待全局讀鎖或者設置系統全局變量 read_only

Waiting for tables

線程得到一個表結構變化的通知,需要重新打開表獲取新的表結構,該線程需要等待其他線程關閉該表。這個通知發生在另外的線程執行了 FLUSH TABLES,ALTER TABLE,RENAME TABLE,REPAIR TABLE,ANALYZE TABLE or OPTIMIZE TABLE

Waiting for table flush

線程正在執行 FLUSH TABLES,正在等待其他線程關閉他們的表,或者是線程得到一個表結構變化的通知,需要重新打開表獲取新的表結構,該線程需要等待其他線程關閉該表。這個通知發生在另外的線程執行了 FLUSH TABLES,ALTER TABLE,RENAME TABLE,REPAIR TABLE,ANALYZE TABLE or OPTIMIZE TABLE

Waiting for lock_type lock

服務端正在等待 THR_LOCK 鎖,或者是元數據鎖定子系統的鎖,其中 lock_type 是鎖的類型,等待 THR_LOCK 鎖(Waiting for table level lock),等待元數據鎖(Waiting for event metadata lock、Waiting for global read lock、Waiting for schema metadata lock、Waiting for stored function metadata lock、Waiting for stored procedure metadata lock、Waiting for table metadata lock、Waiting for trigger metadata lock)

Waiting on cond

線程正在等待條件變為 true 的狀態,沒有具體可用的狀態信息

Writing to net

服務端正在網絡中寫包,在 5.7.8 中該狀態叫 Sending to client

通過結果我們可以大致看看如下的情況:

  • 是否有大量的未執行查詢語句
  • 是否有正在執行的 DML 語句
  • 是否有執行了很長時間的 DDL 語句
  • 是否有鎖等情況

我們模擬的這個環境,show 的結果只有兩條,結果非常明顯,但是真正的生產環境不止這兩條結果,通過這個查詢結果,可以大致分析一下,并不能準確定位,準確的定位問題,需要進行后續的操作。

根據問題線程 id 定位 MySQL 中的 SQL:

mysql [localhost:5727] {msandbox} ((none)) > select a.user,a.host,a.db,b.thread_os_id,b.thread_id,a.id processlist_id,a.command,a.time,a.state,a.info from information_schema.processlist a,performance_schema.threads b where a.id = b.processlist_id and b.thread_os_id=32272;
+----------+-----------+------+--------------+-----------+----------------+---------+------+--------------+---------------------------------------------+
| user     | host      | db   | thread_os_id | thread_id | processlist_id | command | time | state        | info                                        |
+----------+-----------+------+--------------+-----------+----------------+---------+------+--------------+---------------------------------------------+
| msandbox | localhost | test |        32272 |        32 |              7 | Query   |    2 | Sending data | select * from t_cpu order by rand() limit 1 |
+----------+-----------+------+--------------+-----------+----------------+---------+------+--------------+---------------------------------------------+
1 row in set (0.00 sec)
  • thread_os_id=32272,代表的是操作系統級別的線程 id
  • thread_id=32,代表的是 MySQL 內部級別的線程 id
  • processlist_id=7,代表的是會話發起者的進程 id,可 kill 的 id

根據問題線程 id 查看其他監控指標:

mysql [localhost:5727] {msandbox} (performance_schema) > select * from performance_schema.events_statements_current where thread_id in (select thread_id from performance_schema.threads where thread_os_id = 32272)G;
*************************** 1. row ***************************
              THREAD_ID: 32
               EVENT_ID: 11
           END_EVENT_ID: 11
             EVENT_NAME: statement/sql/select
                 SOURCE: 
            TIMER_START: 93213362472684000
              TIMER_END: 93221551162460000
             TIMER_WAIT: 8188689776000
              LOCK_TIME: 993000000
               SQL_TEXT: select * from t_cpu order by rand() limit 1
                 DIGEST: 83dacab9df764f11291d0001e420012e
            DIGEST_TEXT: SELECT * FROM `t_cpu` ORDER BY `rand` ( ) LIMIT ? 
         CURRENT_SCHEMA: test
            OBJECT_TYPE: NULL
          OBJECT_SCHEMA: NULL
            OBJECT_NAME: NULL
  OBJECT_INSTANCE_BEGIN: NULL
            MYSQL_ERRNO: 0
      RETURNED_SQLSTATE: NULL
           MESSAGE_TEXT: NULL
                 ERRORS: 0
               WARNINGS: 0
          ROWS_AFFECTED: 0
              ROWS_SENT: 1
          ROWS_EXAMINED: 20971521
CREATED_TMP_DISK_TABLES: 1
     CREATED_TMP_TABLES: 1
       SELECT_FULL_JOIN: 0
 SELECT_FULL_RANGE_JOIN: 0
           SELECT_RANGE: 0
     SELECT_RANGE_CHECK: 0
            SELECT_SCAN: 1
      SORT_MERGE_PASSES: 0
             SORT_RANGE: 0
              SORT_ROWS: 1
              SORT_SCAN: 1
          NO_INDEX_USED: 0
     NO_GOOD_INDEX_USED: 0
       NESTING_EVENT_ID: NULL
     NESTING_EVENT_TYPE: NULL
    NESTING_EVENT_LEVEL: 0
1 row in set (0.00 sec)

ERROR: 
No query specified

通過這個結果我們可以查看具體的 SQL,看到有使用臨時表、使用了排序等信息。

CREATED_TMP_DISK_TABLES: 1  
CREATED_TMP_TABLES: 1  
SORT_ROWS: 1  
SORT_SCAN: 1  

其他排查手段之慢查詢日志

查詢慢日志情況:

mysql [localhost:5727] {msandbox} ((none)) > show variables like 'slow_query_log%';
+---------------------+------------------------------------------------------+
| Variable_name       | Value                                                |
+---------------------+------------------------------------------------------+
| slow_query_log      | ON                                                   |
| slow_query_log_file | /dbdata/sandboxes/msb_5_7_27/data/localhost-slow.log |
+---------------------+------------------------------------------------------+
2 rows in set (0.01 sec)

在慢日志中查看慢 SQL:

cat /dbdata/sandboxes/msb_5_7_27/data/localhost-slow.log

# Time: 2021-08-17T09:11:06.768816Z
# User@Host: msandbox[msandbox] @ localhost []  Id:     5
# Query_time: 7.984593  Lock_time: 0.000184 Rows_sent: 1  Rows_examined: 20971521
SET timestamp=1629191466;
select * from t_cpu order by rand() limit 1;

可以很清楚的查到慢 SQL:

select * from t_cpu order by rand() limit 1

執行了有 7.984593 秒,返回結果為 1 行。

其他排查手段之排查日志

開啟排查日志功能:

更改排查日志為 TABLE 方式,默認為 FILE 方式
mysql [localhost:5727] {msandbox} ((none)) > set global log_output='TABLE';
Query OK, 0 rows affected (0.00 sec)

mysql [localhost:5727] {msandbox} ((none)) > set global general_log=ON;
Query OK, 0 rows affected (0.00 sec)

執行慢查詢:

select * from t_cpu order by rand() limit 1

查詢排查日志內容:

mysql [localhost:5727] {msandbox} ((none)) > SELECT * from mysql.general_log ORDER BY event_time DESC;
+----------------------------+-----------------------------------+-----------+-----------+--------------+----------------------------------------------------------+
| event_time                 | user_host                         | thread_id | server_id | command_type | argument                                                 |
+----------------------------+-----------------------------------+-----------+-----------+--------------+----------------------------------------------------------+
| 2021-08-17 17:19:19.863849 | msandbox[msandbox] @ localhost [] |         2 |         0 | Query        | SELECT * from mysql.general_log ORDER BY event_time DESC |
| 2021-08-17 17:18:45.017615 | msandbox[msandbox] @ localhost [] |         5 |         0 | Query        | select * from t_cpu order by rand() limit 1              |
+----------------------------+-----------------------------------+-----------+-----------+--------------+----------------------------------------------------------+
2 rows in set (0.00 sec)

結果顯示了剛才的慢 SQL,還有我們查詢排查日志結果的 SQL,其實慢日志會記錄所有的 SQL,我們只能通過這個日志內容查看一些不太正常的 SQL,比如大量相同的 SQL;定期出現的 SQL;分析一個特定的事務等,排查日志模式非常影響 MySQL 性能,慎用。

關閉排查日志模式:

mysql [localhost:5727] {msandbox} ((none)) > set global general_log=OFF;
Query OK, 0 rows affected (0.05 sec)

mysql [localhost:5727] {msandbox} ((none)) > truncate table mysql.general_log;
Query OK, 0 rows affected (0.05 sec)

到目前為止,介紹了幾種常用的 MySQL 占用 CPU 過高的定位方法,你是否掌握了。找到問題了,接下來,我們就需要看看如何優化這個問題了。

優化一下也不難

前面介紹了幾種常用的排查 MySQL 占用 CPU 過高問題排查的方法,那么當我們遇到問題了,如何解決,如何優化呢?

首先,最暴力的方法,如果我們確定這個 SQL 可以被干掉,我們直接 kill id 即可。id 為 process 的 id。

其次,具體問題具體分析,如何排查問題是如何發生的,根據不同的問題作出相應的解決方法。

1. 優化 SQL,從邏輯上優化 SQL,降低 SQL 復雜度,降低 MySQL 執行成本。

2. 對 where、join、max()、min()、order by、group by 等子句用到的字段,創建相應的索引。

3. 二級索引的正確使用。

4. 參數優化:

  • 增加 tmp_table_size 大小
  • 增加 max_heap_table_size 大小
  • 調整 key_buffer_size、table_cache、innodb_buffer_pool_size、innodb_log_file_size 參數大小

其他常用優化方法

1. 檢查 MySQL 連接數當前使用是否超過限制

如果超出限制,而且之前的連接沒有得到釋放,那新的連接肯定會連接不到,造成連接延遲,影響效率。

2. MySQL 的 timeout 參數設置問題

這里介紹兩個參數:

  • wait_timeout:MySQL 在關閉一個非交互的連接之前所要等待的秒數,其取值范圍在 windows 系統中為 1-2147483,linux 系統中為 1-31536000,默認值 28800。
  • interactive_time:MySQL 在關閉一個交互的連接之前所要等待的秒數(如 mysql gui tool 中的連接),其取值范圍隨 wait_timeout 變動,默認值 28800。

交互連接即在 mysql_real_connect() 函數中使用了 CLIENT_INTERACTIVE 選項。簡單說,就是通過 MySQL 客戶端連接數據庫是交互式連接,通過 jdbc 連接數據庫是非交互式連接。在 MySQL 默認設置下,當一個連接的空閑時間超過 8 小時后,當業務出現了高峰期,肯定會造成有太多的 TCP 連接沒關閉,數據庫連接數肯定會不夠用。從而會產生 CPU 占用過高,服務器告警等問題。因 EPG 的一個訪問一次對數據庫操作量不大,查詢完數據就完成 ok 了,wait_timeout 設置在 120s 內就可以了。

在 MySQL 的官網了解到修改以上兩個參數必須修改 interactive_timeout。如果修改 interactive_timeout,則 wait_timeout 也發生變化,如果只修改 wait_timeout,不生效。

3. 老生常談,規范的 SQL 也是非常必要的

好了,至此我們基本學習完本節內容了,內容比較多,當然也有不足之處,歡迎朋友們指正補充。

分享到:
標簽:MySQL
用戶無頭像

網友整理

注冊時間:

網站:5 個   小程序:0 個  文章:12 篇

  • 51998

    網站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會員

趕快注冊賬號,推廣您的網站吧!
最新入駐小程序

數獨大挑戰2018-06-03

數獨一種數學游戲,玩家需要根據9

答題星2018-06-03

您可以通過答題星輕松地創建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學四六

運動步數有氧達人2018-06-03

記錄運動步數,積累氧氣值。還可偷

每日養生app2018-06-03

每日養生,天天健康

體育訓練成績評定2018-06-03

通用課目體育訓練成績評定