幾年前MySQL資料庫出現突然的從庫延遲故障和CPU爆高時,如何排查具體原因,可能說已在騰訊雲的MySQL庫裡開啟了SQL全審計,記錄了全部執行的SQL,再透過下面的方法就可以很容易找到原因:
1,實用QPS和TPS高的高效分析方法
但如果沒有開通SQL全審計,如何去找原因。當然說可以看慢SQL日誌,但這時的慢SQL日誌記錄的SQL不全,就不好判斷分析出具體是哪些SQL引起的。
如何在非開通SQL全審計的MySQL資料庫(因例項不可能都開SQL審計,自建MySQL開還不方便儲存檢視等),有什麼辦法? 有更多資訊來分析出原因!
當時接手公司資料庫運維時,研發已經寫了一個Shell,每10秒儲存一下當前的:show full processlist ,保留當前執行SQL情況到檔案中,後來發現這些還不夠,後來加上長事務和表鎖,可能更好,Shell指令碼如下:
1,CPU爆高:
監控shell:
每10秒執行一次保留當前查詢的監控到txt文字中
#!/bin/bash cd $(dirname $0) echo $log_file sql=" show full processlist" ip=172.16.0.15 start_time=$(date +%s) let "check_time=start_time+60"; now=$start_time while [ $now -lt $check_time ]; do log_dir=/root/monitor/$(date +"%Y-%m-%d")/$(date +"%H")/$(date +"%M") mkdir -p $log_dir log_file=$log_dir/$(date +"%Y-%m-%d-%H-%M-%S") echo $sql | mysql -udba_op -ppwd -h$ip mysql > $log_file.master mysql -udba_op -ppwd -h$ip mysql </root/shell/long_tran.sql > $log_file.master_tran echo "next " sleep 10; now=$(date +%s) done
long_tran.sql下的SQL指令碼:
select timestampdiff(SECOND,trx_started,now()) diffsecond,b.host,b.user,concat('kill ',b.ID,' ;') killsql,b.db, IFNULL(b.INFO,a.trx_query) runsql from information_schema.innodb_trx a left join information_schema.PROCESSLIST b on a.trx_mysql_thread_id=b.ID where timestampdiff(SECOND,trx_started,now()) >=1 order by 1 desc limit 20; show open tables where in_use >=1;
Crontab執行排程和清理10天前的日誌
*/1 * * * * sh /root/shell/sg_monitor_master.sh > /dev/null 2>&1
1 1 * * * find /root/monitor/ -name "20*" -type d -mtime +10 -exec rm -rf {} \; > /dev/null 2>&1
這樣每隔10秒就有下面2個檔案:
可以結合慢SQL和這2個檔案,監控出出問題時當前的資料庫的SQL執行情況,找出問題。
2,從庫突然延遲
因為當時公司是做線上教育的,但從庫延遲幾十秒,對他們影響很大,同時領導就會收到報警簡訊,釘釘群裡叫,就要查是什麼原因導致的從庫延遲,一種方法是檢視上面的監控處理的SQL獲取資訊,另外當時還有解析出binlog資訊,查出具體的SQL,看是什麼SQL導致的,具體做法:
1,從騰訊雲的下載出問題時間的binlog日誌本地的機器
2,根據出問題的時間範圍,解析binlog日誌,如下:
mysqlbinlog --no-defaults -vv --base64-output=decode-rows --start-datetime='2020-08-18 11:20:00' --stop-datetime='2020-08-18 12:03:00' mysql-bin.000203 >log.sql
3,解析出binlog日誌後,用notepad++開啟檔案,仔細檢視執行的SQL日誌,分析出SQL,這就是細心活。如果查到具體表,可以用上grep過濾,如下:
1, grep user_0 -A 10 -B 10 >/data/61.txt
2, mysqlbinlog --start-datetime="2019-07-08 9:32:00" --stop-datetime="2019-07-09 11:20:00" -v --base64-output=DECODE-ROWS binlog.000001 | grep -A4 'INSERT' > test.sql
4,結合上面資訊,發出SQL,讓研發同學去修改業務。
3,記錄原始SQL
當時在公司,公司技術VP說要記錄執行的原始SQL,這樣大資料讀取binlog,把這個原始SQL保留起來,日後審計時就可以透過原始SQL發現誰亂改線上業務資料,同時要把研發人員每次業務要改資料的SQL郵件抄送給他。查詢發現mysql還有這樣的引數: binlog_rows_query_log_events引數
預設配置下,ROW格式二進位制日誌只記錄資料發生的變化,並不會記錄什麼語句導致資料發生變化,而出於審計或者處理bug的需求,需要了解導致資料變化的SQL語句,MYSQL提供了binlog_rows_query_log_events來控制是否在二進位制中存放"原始SQL"。開啟後如下:
後來在主庫上開啟該引數,大資料就記錄主庫的SQL執行情況,要監控誰有亂修改更新線上業務資料,但後面一直沒用這個資料去查,反而大資料說記錄的執行SQL資料量太大,不得不縮短資料保留日期。