1. 程式人生 > >MySql CPU彪高到百分之1000的排查思路

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伺服器配置方式,以及已經被優化過的mysqlDB.5.7.20的安裝包: 連結:https://pan.baidu.com/s/1hF99W4DJY8vSZ0rx3NYYow 提取碼: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 命令引數使用詳解可參考如下連結: http://lovesoo.org/linux-sar-command-detailed.html?aonypw=msmxi   https://blog.csdn.net/u012167045/article/details/55056940 2、索引的建立及優化方式:  https://www.cnblogs.com/lfs2640666960/p/9147768.html  3、show processlist 欄位解釋 https://blog.csdn.net/dhfzhishi/article/details/81263084