mysql日志管理
參考https://www.jianshu.com/p/00c54d2832ed
日志設置
工具日志,不同於undo log(事務等)
錯誤日志(排錯、主從錯誤)--log-error,默認打開,路徑datadir/主機名.err,文本格式,重點關注[ERROR]
慢查詢日志(優化)--slow_query_log、--long_query_time
二進制日志(主從)--log-bin、--expire-logs-days
目錄授權chown -R mysql.mysql /tmp/{errlog,binlog}
一般會定制這些日志的路徑,避免數據盤出錯,日志也拿不到
查看錯誤日志路徑:select @@log_error,默認應該在./主機名.err,我的在stderr
修改到mysql.mysql有權限的路徑,在/etc/my.cnf的[mysqld]下添加log_error=自定義錯誤日志路徑,如/tmp/errlog/mysql.err或mysql.log(自動創建文件),重啟生效
二進制日志(binlog),sql層邏輯日志,記錄sql語句操作,默認關閉
- 主從復制依賴binlog
- 數據恢復依賴binlog
開啟,需要配置參數(/etc/my.cnf的[mysqld]),重啟生效:
-
server_id= 主從復制用,但5.7開始,開啟binlog需要配置server_id,1-65535
-
log_bin= 設置為1,打開binlog功能,生成在默認位置,也可以指定路徑如/tmp/binlog/mysql-bin,會打開binglog功能,且按指定路徑和名稱前綴生存二進制日志,也可以單獨設置log_bin和log_bin_basename參數
其中/tmp/binlog是路徑,必須mysql.mysql有權限
mysql-bin是前綴,生成日志名稱mysql-bin.000001,mysql-bin.000002等,mysql只能使用一個,關注編號最大那個,其他是歷史文件(可以設置自動清除的策略),每次重啟會生成並使用新的binlog,其中mysql-bin.index列出所有二進制日志文件名稱,相當於索引
-
上面2給參數必須設置,下面可選,binlog_format=row,5.7版本默認配置就是row,可以不設置
innodb_flush_log_at_trx_commit=0:每秒一次將Log Buffer中數據寫入到Log File中,並且Flush到磁盤。事務提交不會主動觸發寫磁盤操作。
innodb_flush_log_at_trx_commit=1:每次事務提交時將Log Buffer數據寫入到Log File中,並且Flush到磁盤。
innodb_flush_log_at_trx_commit=2:每次事務提交時將Log Buffer數據寫入到Log File中,但不立即Flush到磁盤,MySQL會每秒一次刷新到磁盤。
由於進程調度問題,每條一次操作不能保證每一秒都執行一次。
當innodb_flush_log_at_trx_commit=0時,最近一秒的事務日志存在MySQL的Log Buffer中,無論時MySQL實例停止還是MySQL服務器宕機,都會導致最近一秒的事務日志丟失。
當innodb_flush_log_at_trx_commit=1時,最近一秒的事務日志存在操作系統的文件緩存中,MySQL實例停止不會導致事務日志丟失,但MySQL服務器宕機會導致最近一秒事務日志丟失。
上述的一秒一次刷新,取決於參數innodb_flush_log_at_timeout默認值為1,DDL或其他InnoDB內部操作並不受參數innodb_flush_log_at_trx_commit的限制。
二進制日志概述
二進制日志記錄:變更類操作日志,DML增刪改(數據)、DDL(增刪改表)、DCL(修改權限)
DDL和DCL(如建表create database 庫名、alter、drop等),以語句的方式原樣記錄
DML語句(增刪改),記錄已提交的事務的SQL語句(未提交或回滾的事務不記錄),多種記錄格式(statement、row、mixed),通過binlog_format=row參數控制(該參數只控制DML語句),建議使用row。
- statement:SBR模式,語句模式,以SQL語句原樣記錄命令,可讀性強。對於范圍操作,日志量少,節省空間(如update t set name='test' where id > 10,SBR只有一條日志,RBR有多少行數據被更新就加多少條日志)。但SBR可能記錄不准確,如時間函數,舉例insert into t values (1,'test',now());在主從復制或備份還原以后時間字段的值不准確。
- row:RBR模式,行模式,記錄一行數據的變化(與redo log區別,redo log記錄page頁的變化),推薦使用,默認。特點,可讀性較弱,范圍操作日志量大,但是不會出現記錄錯誤。高可用環境新型架構很多新特性依賴RBR模式,所以建議使用RBR模式。
- mixed:MBR模式,混合模式,由mysql決定選擇SBR還是RBR,不可控,不建議使用。
面試:SBR和RBR的區別,選擇依據,看上面的筆記即可。
二進制日志的記錄單元:
最小單元event,事件,了解了這些,方便有需要截取某些部分日志做數據恢復的需求,比如如刪除某幾條數據的恢復這種操作,需要知道截取哪些范圍的event
不同類型的語句,事件不同
DDL、DCL以SQL形式記錄,每個語句(操作)就是一個事件
DML(標准事務語句begin; 語句1;語句2;commit;,這里有4條語句,4個事件),一個事務包含多個語句,每條語句是一個事件
event事件的開始、結束號碼(方便從日志中截取想要的event日志事件范圍):
操作二進制文件
查找二進制日志是否開啟及位置:從配置文件看,或執行show variables like '%log_bin%';
查看二進制日志文件列表:去log_bin的路徑下看,或執行show binary logs;
執行flush logs;會滾動出一個新的日志,再執行show binary logs;就會新增加一個文件。
查看正在使用的二進制文件:show master status;
先做些操作記錄事件:
create database binlog charset utf8mb4;
use binlog;
create table t1(id int);
insert into t1 values(1);
查看二進制日志的事件:
show master status; 查看使用的二進制日志文件
show binlog events in '文件名' [limit 10]; 查看事件
mysql> show binlog events in 'mysql-bin.000001';
+------------------+-----+----------------+-----------+-------------+----------------------------------------+
| Log_name | Pos | Event_type | Server_id | End_log_pos | Info |
+------------------+-----+----------------+-----------+-------------+----------------------------------------+
| mysql-bin.000001 | 4 | Format_desc | 6 | 123 | Server ver: 5.7.26-log, Binlog ver: 4 |
| mysql-bin.000001 | 123 | Previous_gtids | 6 | 154 | |
| mysql-bin.000001 | 154 | Anonymous_Gtid | 6 | 219 | SET @@SESSION.GTID_NEXT= 'ANONYMOUS' |
| mysql-bin.000001 | 219 | Query | 6 | 335 | create database binlog charset utf8mb4 |
| mysql-bin.000001 | 335 | Anonymous_Gtid | 6 | 400 | SET @@SESSION.GTID_NEXT= 'ANONYMOUS' |
| mysql-bin.000001 | 400 | Query | 6 | 501 | use `binlog`; create table t1(id int) |
| mysql-bin.000001 | 501 | Anonymous_Gtid | 6 | 566 | SET @@SESSION.GTID_NEXT= 'ANONYMOUS' |
| mysql-bin.000001 | 566 | Query | 6 | 640 | BEGIN |
| mysql-bin.000001 | 640 | Table_map | 6 | 687 | table_id: 108 (binlog.t1) |
| mysql-bin.000001 | 687 | Write_rows | 6 | 727 | table_id: 108 flags: STMT_END_F |
| mysql-bin.000001 | 727 | Xid | 6 | 758 | COMMIT /* xid=16 */ |
+------------------+-----+----------------+-----------+-------------+----------------------------------------+
11 rows in set (0.00 sec)
其中前兩行是二進制文件頭格式,不用關心,第三行事件POS是154
每行一個事件,pos和end_log_pos是事件開始和結束的位置號碼,上一個事件的結束位置是下一個事件的開始位置,開始和結束位置可以作為截取事件的依據,事務截取要從begin到commit才完整。
查看二進制日志文件(二進制格式,用工具查看),Linux下查看日志文件類型:file mysql-bin.000001(mysql復制日志)
[root@VM_0_4_centos ~]# file /tmp/binlog/mysql-bin.000001
/tmp/binlog/mysql-bin.000001: MySQL replication log
查看二進制日志內容:mysqlbinlog mysql-bin.000001;或mysqlbinlog mysql-bin.00001 | grep -v '^SET';不看SET開頭的事件
@號碼,這是一個事件開始的標志,從#@154開始看,那些SET的事件可以跳過不看,可以對照上面的事件查看結果來看,事件的第一行是注釋,注明了事件發生時間
其中行模式記錄的sql是base64編碼的,要想以解碼的方式看,-vvv是使結果更加詳細,執行:
mysqlbinlog --base64-output=decode-rows -vvv mysql-bin.000001; 執行mysqlbinlog --help可以查看這些參數
# at 687
#200130 21:37:52 server id 6 end_log_pos 727 CRC32 0x209b53a6 Write_rows: table id 108 flags: STMT_END_F
### INSERT INTO `binlog`.`t1`
### SET
### @1=1 /* INT meta=0 nullable=1 is_null=0 */
向binlog.t1插入數據,給第一列設置為1,多列分別為@1,@2...
截取二進制日志:
show binlog events in 'mysql-bin.000001';
mysqlbinlog --start-position=起始位置 --stop-position=結束位置 mysql-bin.000001 [ >/tmp/t1.sql];
查看並截取,其中前兩行事件的記錄依然存在,使用>可以將截取內容輸出到sql文件,可以用於數據恢復。
position是事件在二進制文件中的字節占用的位置。
使用二進制日志進行數據恢復(source sql文件;)
誤操作或故障以后做數據恢復
drop 庫名 表名;刪了表和庫。
截取二進制日志從庫創建到誤刪除之前的日志,保持為sql文件。
使用source導入sql文件,這部分不需要記錄binlog,因為這些日志是從binlog截取的,再記錄binlog,以后用binlog做全量恢復會出問題。使用set sql_log_bin=0;在當前會話中臨時設置參數將binlog關閉,不影響其它會話,source命令執行完成以后,執行set sql_log_bin=1;修改回來
二進制日志恢復在數據恢復中必不可少,但是有弊端,如數據量大,時間長,只能作為輔助(使用備份+日志)。
若帶過濾截取,只能截取某個庫的(因為有use可以標識),不能截取某個表的(沒有標識,截取較麻煩,如二次開發改寫二進制記錄的方式,對表的create和增刪改操作加上標識):
mysqlbinlog -d 庫名 mysql-bin.000001;
gtid模式(全局事務id)
5.6出現的,但不完善,5.7開始企業中建議將二進制日志文件改為gtid模式管理,某些高級功能新特性必須在RBR模式+gtid下才能使用
gtid之前按事件來組織二進制日志的內容,用事件起始、終止position去截取binlog
gtid之后,對binlog中的每個獨立事務(不同於innodb的事務)生產一個gtid號碼
ddl和dcl,如create database,一條語句就是一個事件event,就是一個事務,就有一個gtid號碼
dml,從begin到commit才是一個事務,有一個gtid號碼
gtid組成:server-uuid:TID,server-uuid是數據庫第一次啟動自動生成的,在數據目錄下的auto.cnf
文件中(若刪除該文件,重啟會生成新的,但不要刪除和修改它),TID是事務號碼,從1開始自增長,不是innodb的事務id
gtid具有冪等性:即用開啟了gtid的日志去恢復數據時,系統中存在相同的gtid,若存在重復的gtid自動跳過(執行過的不再執行),會影響binlog的恢復和主從復制
gtid的開啟和配置,配置/etc/my.cnf:
gtid-mode=on 開啟gtid
enforce-gtid-consistency=true 強制gtid一致性
重啟systemctl restart mysqld,gtid開啟只影響后面的事務
開啟gtid之后操作數據庫,執行show master status;在Executed_Gtid_Set列會有值,即server-uuid:TID,其中TID,一個事務是1,n給事務是1-n
執行show binlog events in 'mysql-bin.000001'查看事件,每個事務開始之前有SET設置GTID
截取時使用GTID即可,不用position:
mysqlbinlog --skip-gtids --include-gtids='server-uuid:TID范圍,如1-3' mysql-bin.000001 >/tmp/gtid.sql
恢復set sql_log_bin=0; source /tmp/gtid.sql; set sql_log_bin=1;
--skip-gtids參數在導出的時候忽略gtid冪等性(生成的備份不記錄原有的gtid信息,恢復時生成新的gtid),否則恢復的時候會檢查系統以后的binlog里面是否有要恢復的gtid,有就跳過(冪等性),導致結果不正確。
--include-gtids='server-uuid:TID范圍,如1-3',‘server-uuid:TID5',需要導出的事務
--exclude-gtids='server-uuid:TID范圍,如1-3',’server-uuid:TID5','server-uuid:TID7',忽略導出的事務
慢查詢日志
slowlog,慢查詢日志,記錄運行慢的sql,優化參考工具,默認關閉
開啟,配置/etc/my.cnf的[mysqld]
slow_query_log=1 開關
slow_query_log_file=/tmp/slowlog/slow.log 路徑及文件名,/tmp/slowlog需要有mysql.mysql權限,文件名隨意
log_query_time=0.1 慢查詢時間設定,單位秒,執行select @@long_query_time;(或show variables like '%long_query_time%';)查詢默認時間是10.000000秒(不合理,百萬數據全表掃描才2-3秒)可以精確到微秒
log_queries_not_using_indexes 沒走索引的語句也記錄
重啟systemctl restart mysqld
構造一張大表,desc 表名;找一個key自帶沒有值的列(無索引),做查詢(全表掃描),構造多條慢查詢。
slowlog是文本文件,直接查看即可,記錄了超過log_query_time的sql執行記錄或沒有走索引的查詢,包括執行的時間點,庫、表、語句、查詢時間等。按時間點排序。
過濾,將慢查詢日志中,相同的查詢語句合並(記錄平均查詢時間),不同的語句按查詢次數(次數多是熱語句,優先級高)、Query_time降序排列,使用慢查詢分析工具:
mysqldumpslow -s c -t 10 /tmp/slowlog/slow.log -s是排序,c是次數,-s c是按次數排序,-t 10是top 10,自動按查詢時間做第二排序維度
拿到需要優化的sql,去做執行計划分析,如分析是否走索引,或是否需要改寫sql等
第三方慢查詢分析工具(rpm包)
https://www.percona.com/downloads/percona-toolkit/LATEST下載並安裝rpm包
安裝依賴:
yum install perl-DBD-MYSQL perl-Time-HiRes perl-IO-Socket-SSL perl-Digest-MD5
運行:
pt-query-diagest /tmp/slowlog/slow.log
安裝Anemometer可基於pt-query-digest將慢查詢以網頁形式可視化。
補充
現象:網站訪問越來越慢,最后無法訪問了,經過檢查發現磁盤滿了。查詢下來是由於mysql的binlog太多太大占用了空間。
分析過程及解決方案:通常出現這種問題都應該登錄服務器檢查磁盤、內存和進程使用的情況,通過top、df –h和free –m來檢查,發現磁盤空間滿了。再進一步通過du –sh對可以的目錄進行檢查,發現是mysql的binlog占用空間過大。清理binlog的方法如下:
1) 設置日志保留時長expire_logs_days自動刪除
查看當前日志保存天數:
show variables like '%expire_logs_days%';
這個默認是0,也就是logs不過期,可通過設置全局的參數,使他臨時生效:
set global expire_logs_days=7;
設置了只保留7天BINLOG, 下次重啟mysql這個參數默認會失敗,所以需在/etc/my.cnf中設置
expire_logs_days=7
2) 手動刪除BINLOG (purge binary logs,官網https://dev.mysql.com/doc/refman/5.6/en/purge-binary-logs.html)
用於刪除列於在指定的日志或日期之前的日志索引中的所有二進制日志。這些日志文件也會從日志索引文件中刪除:
PURGE {MASTER | BINARY} LOGS TO 'log_name'
PURGE {MASTER | BINARY} LOGS BEFORE 'date'
例如:
PURGE MASTER LOGS TO 'mysql-bin.000001';
PURGE MASTER LOGS BEFORE '2008-06-22 13:00:00';
PURGE MASTER LOGS BEFORE DATE_SUB(NOW(), INTERVAL 3 DAY);
purge binary logs before current_timestamp-interval 1 day;
purge.sh腳本(可加入定時任務):
#!/bin/bash
mysql -uroot -piMC123 mysql<<EOFMYSQL
purge binary logs before current_timestamp-interval 1 day #或purge binary logs to 'mysql-bin.000001'
EOFMYSQL