MySql CPU彪高到百分之1000的排查思路


 
原文內容來自於LZ(樓主)的印象筆記,如出現排版異常或圖片丟失等情況,可查看當前鏈接:https://app.yinxiang.com/fx/bf7839b3-5f7b-4212-9f7d-5f5577e952ea
 

MySql CPU彪高到百分之1000的排查思路

 
查看當前MySql的CPU已經在百分之 1019
 
下述為當前MySql的所以子線程的CPU使用狀況,可以看到當前已經有11個線程的CPU都是在99%左右
 
進行問題的排查:
1、首先懷疑是否是存在較大的全盤掃描的SQL語句,導致MySql查詢時間過長導致的CPU彪高現象
2、查詢當前MySql的my.cnf配置,是否是MySql配置問題(由於我司運維同學有一個統一的MySql公共配置可用,所以並沒有懷疑是MySql的配置不合理而導致的問題,最終確認,也的確不是MySql的配置問題,博客結尾會給出一份優化過的MySQL5.7.20的安裝包,需要的朋友可自取)
3、驗證當前服務器的IO,是否是過於頻繁的讀寫引起的IO異常而導致的CPU彪高;
 
1、使用 show FULL PROCESSLIST 查詢當前MySql的線程執行情況
 
由於之前出現過由於用戶的使用過於頻繁,而導致的表數據量過大引起的數據查詢緩慢的問題,所以在此CPU彪高之前,已經頻繁使用 show processlist  查看過執行時間過長的SQL,並且皆已經做了相對應的處理 (相關的業務皆已經分表分層,以及都增加了相關的表索引) ,所以,我在人工觀察 show processlist的過程當中,的確沒有再出現過 Query過程中Time占用時間很長的情況;
 
並且查看了對應的  mysql-slow.log 日志(在最初部署Mysql的同時,MySql的配置中已經開啟過了慢SQL記錄的日志功能),查詢了對應的慢SQL的記錄日志后,的確是不存在在當前CPU彪高的時間點中存在慢SQL查詢的情況;
 
所以,也就是說,當前已經不在存在由於表數據量較大導致的SQL查詢慢的情況;那么此時則開始轉向思考,難道是我的服務在使用MySql的過程中,讀寫頻率太高了?而導致的MySql服務CPU異常?LZ(樓主)當前所負責開發的產品是一款坐席的實時通話的產品,相關的業務邏輯中的確是存在頻繁的讀寫DB的;所以此時開始轉向思考是否是讀寫頻率太高而引起的CPU彪高的問題,於是開始了以下的排查;
 
2、查詢CPU的IO讀寫速率
分別使用sar 命令獲取 IO的讀寫速率監控:
1、sar -b 1 30
2、sar -u -o 1 30
 
通過使用,sar 命令查看了相關的IO信息后,發現並沒有出現 IOWAIT過高的問題,並且也沒看到每秒鍾物理設備讀寫頻率過高的問題,所以此處就很疑惑;並且由於此處使用sar是分析的系統級IO使用情況,所以也很  難避免是否存在MySql自身的機制,比如某些Sql的查詢頻繁被命中緩存,所以走緩存查詢而並沒有直接走IO讀取的情況;由於上述使用TOP命令時,所對應的wa值也是很低的,那么到底是什么原因引起的MySQL的CPU彪高呢,而且還是如此高?
 
此時,在逐步的排查中,重點來了:
 
當首先出現了CPU彪高的時候,我們對於Mysql的第一印象就是某SQL執行較慢,導致的線程卡死最終引起的CPU彪高,我們會去排查慢SQL的執行日志,或者查看MySql的執行日志,是否有異常的情況出現; 甚至還會懷疑是否是應用程序鏈接Mysql的線程池太多,沒有及時回收線程鏈接,而導致不斷創建線程鏈接最終導致的MySQL服務彪高(此時使用 top -Hp 查看了進程所創建的線程數量,也是正常數據);
 
但始終就一直沒懷疑,是否是並發過高,而導致的MySQL CPU問題,其實LZ最初也懷疑過,難道是應用程序的並發過高而導致的嗎?但簡單想了一下,當前的應用程序並還沒有到達完全的負載狀態,理論上MySQL這樣一個成熟的DB,不至於如此便隨意彪高了,雖然是在簡單的回想,但手上的動作還是敲起了熟悉的命令:show full processlist ,因為如果並發高的情況下,采取每1秒獲取一次正在運行的線程數量的方式(采用SQL腳本for輸出),可以判斷出是否存在運行線程遞增的情況。
 
 
此時則發現了一個新的問題,我每一次不管任何時候查詢當前正在運行的線程,都會看到這樣一個SQL在執行中過程中,盡管對應的Time查詢時間很短,該線程的ID便直接結束了,但意外的是,每一次查看時,都能看到該SQL在運行中;換句話理解則是,該SQL查詢結果是很快的,但是 不管在任何一個時間查看線程時都能看到該SQL正在執行中,這只能說明一個問題,,那就是該SQL的查詢頻率極高!高到每毫秒不間斷的都一直在重新查詢該SQL;
 
所以這只能是代碼BUG問題,最終根據該線程所一直在執行的SQL反向推到應用程序中以后發現,。。。。的確是存在一個定時器的業務BUG,由於定時器是每秒鍾都會被執行,且當前定時器設置的是並行模式(即當前定時器線程無論是否執行完成,只要1秒以后,都會緊接着開啟新的線程執行該定時器代碼塊,所以,這就導致了一旦線程執行了1分鍾,甚至更久,那么將會導致后續的所有線程都會執行1分鍾的時間,並且還在源源不斷的創建新的線程,且由於線程代碼快中,對該SQL查詢代碼還是循環的在查詢........(后續這塊代碼被重構了),所以這將導致不斷的for循環查詢,再加上不斷的新的創建的創建查詢,引起了CPU的循環彪高的情況。。。。。)
 
 
所以如果有遇到相同CPU彪高的情況,但是一直在生產環境沒法定位到具體SQL的情況下,此時記得也一定要關注下SQL的執行頻率問題,因為最初的確沒有想到執行頻率可以高到這種程度,一個如此高的執行頻率竟然可以讓MySQL彪高到如此大的CPU;
 
 
此處做下簡單匯總:
MySQL的服務器本質上是一個很穩定的軟件了,正常情況下只要是給與正確的服務器配置( my.cnf ),很難再出現因為連接數過多,或者線程所占用內存較大,導致的內存或者CPU問題,因為在對應的mysql的配置中,可以設置對應的線程鏈接數,以及線程所占用的內存大小,包括緩沖區的內存大小等配置,只要給與合理的配置,這些問題所導致的服務異常都很難看到,也正是因為如此,所以MySQL這樣的服務對外所提供的排查手段也是極為有限的,類似排查MySQL的運行日志,以及查看慢SQL的日志,和查看線程的執行狀況等,只有寥寥幾個是MySQL所提供的排查工具;
所以如果出現了MySql的服務異常:
1、排查MySql運行日志,是否有錯誤提示
2、排查是否是全表查詢慢SQL導致的服務異常
3、排查MySQL內部線程的執行情況
4、排查SQL線程的執行頻率
 
MySQL本質上還是一個DB服務,提供數據的存儲和檢索,一般情況下更大的問題還是來自於不合理的表的使用,以及不合理的全表檢索,和不合理的索引等使用上而導致的服務異常的情況偏多,而對於上述LZ做碰到的頻繁的線程查詢而導致的CPU彪高,應該也是很難遇到的。。。當然,,如果遇到類似的問題,一定也要記得關注下執行頻率而會導致的問題。
 
此處推薦一份已經被驗證過的常用的MySQL服務器配置方式,以及一個簡單優化了my.cnf后的 mysqlDB.5.7.20的實例安裝包:
提取碼:a47j
[client]
port = 3306
default-character-set=utf8
#character_set_server=utf8
 
 
[mysqld]
port = 3306
character_set_server=utf8
basedir = /opt/mysqlDB/mysql
datadir = /opt/mysqlDB/dbData
server-id = 1 #表示是本機的序號為1,一般來講就是master的意思
skip-name-resolve
#skip-networking
back_log = 600
max_connections = 1000
open_files_limit = 65535
table_open_cache = 128
max_allowed_packet = 4M
binlog_cache_size = 1M
max_heap_table_size = 8M
tmp_table_size = 16M
read_buffer_size = 2M
read_rnd_buffer_size = 8M
sort_buffer_size = 8M
join_buffer_size = 8M
thread_cache_size = 16
query_cache_size = 8M
query_cache_limit = 2M
key_buffer_size = 4M
log_bin = /opt/mysqlDB/logs/binLog/mysql-bin
binlog_format = mixed
expire_logs_days = 7 #超過7天的binlog刪除
log_error = /opt/mysqlDB/logs/errorLog/mysql-error.log #錯誤日志路徑
slow_query_log = 1
long_query_time = 10 #慢查詢時間 超過1秒則為慢查詢
slow_query_log_file = /opt/mysqlDB/logs/slowLog/mysql-slow.log
performance_schema = 0
explicit_defaults_for_timestamp
lower_case_table_names = 1 #不區分大小寫
skip-external-locking #MySQL選項以避免外部鎖定。該選項默認開啟
default-storage-engine = InnoDB #默認存儲引擎
 
 
innodb_file_per_table = 1
innodb_open_files = 500
innodb_buffer_pool_size = 5G
innodb_write_io_threads = 4
innodb_read_io_threads = 4
innodb_thread_concurrency = 0
innodb_purge_threads = 1
innodb_flush_log_at_trx_commit = 2
innodb_log_buffer_size = 2M
innodb_log_file_size = 32M
innodb_log_files_in_group = 3
innodb_max_dirty_pages_pct = 90
innodb_lock_wait_timeout = 120
 
 
bulk_insert_buffer_size = 8M
myisam_sort_buffer_size = 8M
myisam_max_sort_file_size = 10G
myisam_repair_threads = 1
interactive_timeout = 28800
wait_timeout = 28800
 
 
sql_mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES
[mysqldump]
quick
max_allowed_packet = 16M #服務器發送和接受的最大包長度
[myisamchk]
key_buffer_size = 8M
sort_buffer_size = 8M
read_buffer = 4M
write_buffer = 4M
 
 
 
 
相關鏈接參考推薦:
1、使用sar 命令進行IO以及CPU讀寫速率的排查,相關 sar 命令參數使用詳解可參考如下鏈接:
2、索引的創建及優化方式:  
3、show processlist 字段解釋
 
 
 
 
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM