上篇回顧:https://www.cnblogs.com/dotnetcrazy/p/10810798.html#top
1.6.5.MySQL日志相關
本文的測試環境:MySQL5.7.26
、MariaDB5.5.60
、MySQL8.0.16
PS:版本查詢
select version();
1.MySQL常用日志
服務器層日志(存儲引擎層有自己的日志)
日志類型 | 描述 |
---|---|
error_log (錯誤日志) |
記錄MySQL啟動、運行或停止時出現的問題 |
general_log (常規日志) |
記錄所有發送給MySQL的請求(耗性能) |
slow_query_log (慢查日志) |
記錄符合條件的查詢(eg:超過10s、沒有使用索引等) |
binary_log (二進制日志) |
記錄全部有效的數據修改日志(老版本數據庫不會開啟) |
relay_log (中繼日志) |
用於主從復制,臨時存儲主從同步的二進制日志(增量復制) |
知識擴展:https://blog.csdn.net/zhang123456456/article/details/72811875
實時查看文件:tail -f /var/log/mysqld.log
tail -f 用於監視文件增長(默認是末尾10行)
2.error_log(錯誤日志)
一般記錄MySQL運行錯誤
和和未授權的訪問
- 老版:
log_error
+log_warnings
- 常用:
log_error
+log_error_verbosity
- 新版:
log_error
+log_error_verbosity
+log_error_services
查詢MySQL配置:show variables like '%log_error%';
SQL查詢可以這么干:
-- Ubuntu下默認是:`/var/log/mysql/error.log`
-- CentOS下默認是:`/var/log/mysqld.log` | `/var/log/mariadb/mariadb.log`
select @@log_error; -- 盡可能和Data分開存儲
-- 0:不記錄警告信息,1:告警信息寫入錯誤日志,2:各類告警信息都寫入(eg:網絡故障和重連信息)
select @@log_warnings; -- MySQL8中已經移除(MySQL5.7默認是2,MariaDB5.5.60默認是1)
-- 錯誤級別(1:Error,2:Error、Warning,3:Error、Warning、Info
select @@log_error_verbosity; -- MySQL8默認是2,MySQL5.7默認是3
-- PS:從MySQL 5.7.2開始,首選`log_error_verbosity`系統變量
-- 默認是`log_filter_internal; log_sink_internal`
select @@log_error_services; -- MySQL8.0中新增
PS:其實MySQL在市面上有很多成熟解決方案(基本上都是基於5.6、5.7的)
這也是為什么我開篇主推
MySQL5.7
系列和MariaDB5.5.60
(很多時候不是不用最新DB,而是架構依賴做不到啊)
知識拓展:https://www.cnblogs.com/kerrycode/p/8973285.html
PS:SQLServer的ErrorLog也是差不多的
MySQL8.0新增參數:log_error_services
日志服務組件:
日志服務組件名 | 描述 |
---|---|
log_sink_internal |
默認的日志輸出組件(依賴log_error ) |
log_filter_internal |
默認的日志過濾組件(依賴log_error_verbosity ) |
log_sink_json |
將錯誤日志輸出到json 文件 |
log_sink_syseventlog |
將錯誤日志輸出到系統日志文件 |
PS:log_filter_internal
:過濾錯誤信息(達不到級別的不記錄)
日記格式一般是這樣的:UTC時間戳 進程id [日志級別] [錯誤代碼] [由什么產生的日志(Server or Client)] 詳細信息
eg:
2019-05-19T09:54:11.590474Z 8 [Warning] [MY-010055] [Server] IP address '192.168.36.144' could not be resolved: Name or service not known
一般log_sink_json
用的比較多:
官方文檔參考:https://dev.mysql.com/doc/refman/8.0/en/error-log-json.html
PS:第一次使用需要安裝一下json組件:install component 'file://component_log_sink_json';
常用設置:
set persist log_error_services='log_filter_internal;log_sink_json';
時間戳相關的小知識點
上面的時間默認是UTC的時間戳,和我們是有時差的,這個時間戳可以通過設置log_timestamps
來本地化:
-- 查詢
select @@log_timestamps; -- MySQL5.7新增
-- 從8開始,可通過SET PERSIST命令將全局變量的修改持久化到配置文件中
set persist log_timestamps='SYSTEM'; -- 需要root權限
PS:set persist
生成的配置文件路徑在:/var/lib/mysql/mysqld-auto.cnf
3.general_log(常規日志)
以前開發調試的時候基本上都是會開啟的,上線后關閉(系統V1初期的時候也會開啟一段時間)
現在開發可以使用go-sniffer來抓包查看客戶端執行的SQL
-- 是否打開常規日志(0不打開,1打開)
-- 一般不打開(性能)
select @@general_log; -- 默認為0
-- Ubuntu默認:/var/lib/mysql/ubuntuserver.log
-- CentOS默認:/var/lib/mysql/localhost.log
select @@general_log_file; -- 常規日志的路徑
-- 日志的存儲方式(FILE | TABLE | NONE)
select @@log_output; -- 默認是文件存儲
簡單看一下常規日志在數據庫中的結構:
臨時開啟參考:
# 開啟
set global general_log = 1;
# set [global | persist] general_log_file = '日志路徑';
set global log_output = 'TABLE';
4.slow_query_log
(慢查詢日志)
這個是最常用
的,把符合條件的查詢語句記錄在日志中,一般都是些需要優化的SQL
PS:出現性能瓶頸的時候,或者為了優化SQL會開啟一段時間(小項目推薦直接開啟)
先看下默認值:show variables like '%slow%';
、show variables like 'long%';
SQL查詢:
-- 是否開啟
select @@slow_query_log; -- 默認是關閉
-- CentOS:/var/lib/mysql/localhost-slow.log
-- Ubuntu:/var/lib/mysql/ubuntuserver-slow.log
select @@slow_query_log_file;
-- 條件:設置超過多少秒為慢查詢(一般設置1s)
select @@long_query_time; -- 默認是10s(支持小數:0.003)
-- PS:設置為0就會記錄所有SQL(不推薦這么干)
-- 條件:沒有使用索引的查詢記錄到日志中
select @@log_queries_not_using_indexes; -- 默認是0(不開啟)
-- 記錄optimize table、analyze table和alter table的管理語句
select @@log_slow_admin_statements; -- 默認是0(不開啟)
-- 記錄由Slave所產生的慢查詢
select @@log_slow_slave_statements;
常用設置:
PS:高並發下的互聯網項目,對SQL執行時間的容忍度一般都是低於
300~500ms
的(long_query_time=0.05
)
# 常用如下:(需要MySQL的root權限)
set global slow_query_log = 1; # 開啟慢查詢日志
set global long_query_time = 1; # 記錄大於1s的SQL
set global log_slow_admin_statements = 1; # 記錄管理語句
set global log_queries_not_using_indexes = 1; # 記錄沒有使用索引的SQL
# set [global | persist] slow_query_log_file = '路徑'; # 設置log路徑
設置long_query_time
時,需要重新連接才能生效(不需要重啟DB)
PS:當前會話不生效,之后的會話就生效了(不想重連可以再設置下當前會話的
long_query_time
)
知識拓展:(chown mysql:mysql /work/log/xxx.log
)
擴展:慢查詢工具
先簡單分析下慢查詢日志:
# Time: 2019-05-22T21:16:28.759491+08:00
# User@Host: root[root] @ localhost [] Id: 11
# Query_time: 0.000818 Lock_time: 0.000449 Rows_sent: 5 Rows_examined: 5
SET timestamp=1558530988;
select * from mysql.user order by host; # SQL語句
Time
:查詢的執行時間(start_time
)User@Host: root[root] @ localhost [] Id:11
:執行 sql 的主機信息Query_time
:SQL查詢
所耗的時間Lock_time
:鎖定時間Rows_sent
:所發送的行數Rows_examined
:鎖掃描的行數SET timestamp=1558530988;
:SQL執行時間
現在可以說說工具了,推薦兩款:
- 自帶的慢日志分析工具:
mysqldumpslow
- MySQL工具箱(
percona-toolkit
)中的pt-query-digest
mysqldumpslow(精簡)
查詢最慢的10條SQL:mysqldumpslow -s t -t 10 /var/lib/mysql/localhost-slow.log
-s 按照那種方式排序
t: 查詢時間
c:訪問計數
l:鎖定時間
r:返回記錄
al:平均鎖定時間
ar:平均訪問記錄數
at:平均查詢時間
-t 返回多少條數據(可以理解為top n)
-g 可以跟上正則匹配模式,大小寫不敏感。
PS:使用mysqldumpslow的分析結果不會顯示具體完整的sql語句:
- 翻頁sql不一樣,性能也是不一樣的,越往后的頁數越容易出現慢查詢,而mysqldumpslow把所有翻頁sql當成一個sql了
- eg:
select * from tb_table where uid=20 group by createtime limit 10000, 1000;
==>select * from tb_table where uid=N group by createtime limit N, N;
- 不管你uid和limit怎么變,mysqldumpslow認為是一樣的
pt-query-digest(推薦)
官方文檔:https://www.percona.com/doc/percona-toolkit/3.0/pt-query-digest.html
分析慢查詢日志:
pt-query-digest /var/lib/mysql/localhost-slow.log
- 使用tcppdump捕獲MySQL協議數據,然后報告最慢的查詢:
tcpdump -s 65535 -x -nn -q -tttt -i any -c 1000 port 3306 > mysql.tcp.txt
pt-query-digest --type tcpdump mysql.tcp.txt
- 查看來自遠程進程列表上最慢的查詢:
pt-query-digest --processlist h=ip
安裝可以參考:https://github.com/lotapp/awesome-tools/blob/master/README.md#4運維
PS:percona-toolkit的常用工具我也在里面簡單說了下,對應文檔也貼了
other
PS:還有一款mysqlsla
我沒用過,所以貼個參考文章,感興趣的同志自己研究下
知識拓展:https://www.cnblogs.com/fengchi/p/6187099.html
5.binary_log(二進制日志)
上節主要說了通用日志和慢查日志,今天說下二進制日志:
二進制日志算是最常用的了,主要就是記錄對數據庫的修改
,然后就是主從復制
用的比較多(比如增量備份)
PS:記錄了修改操作,那么衍生出的場景就是:
增量備份和恢復
(基於時間點的備份和恢復)
PS:MySQL日志主要分為這兩類:(互不干擾)
服務層
日志(和使用存儲引擎無關)- 通用日志、慢查詢日志、二進制日志
存儲引擎層
日志- eg:innodb的重做日志(
redo log
)和回滾日志(undo log
)
- eg:innodb的重做日志(
Q:那什么樣的修改會記錄下來呢?
A:記錄所有對MySQL數據庫的修改事件(包括增刪改查事件和對表結構修改的事件),而且只記錄已經成功執行的事件(失敗的不會記錄)
這么說可能有點抽象,熟悉SQLServer的同志看個圖就秒懂:
5.1.二進制日志格式
參數 | 說明 |
---|---|
STATEMENT |
基於段的格式,記錄執行數據修改時候所執行的SQL語句 |
ROW |
基於行的格式,記錄增刪改查操作所修改行的信息(每修改一行就會有一條信息) |
MIXED |
基於行和端的混合格式,根據SQL語句由系統決定是基於段還是基於行的日志格式記錄 |
查看方式:show variables like 'binlog_format';
- binlog_format=
statement
:基於段的記錄格式(老版本的默認值)- 優點:記錄量較小,節約磁盤和網絡IO(單條操作Row更節約)
- 缺點:必須記錄上下文信息來保證語句在從服務器上執行結果與主服務器相同
- 但是如果使用了
uuid()
、user()
等結果非確定的函數,可能會造成MySQL主從不一致
- 但是如果使用了
- 日志查看:
mysqlbinlog /var/lib/mysql/binlog.0000xx | more
(不用指定參數)
- binlog_format=
row
:基於行的記錄格式(5.7以后的默認值)- 優點:可以避免MySQL復制中出現的主從不一致的問題(主從更安全)
- PS:沒有備份的時候可以通過分析row格式的二進制日志來反向恢復
- 缺點:記錄日志量較大(順序寫入)
- 現在增加了新參數來優化:
binlog_row_image=[full|minimal|noblob]
- 現在增加了新參數來優化:
- 日志查看:
mysqlbinlog -vv /var/lib/mysql/binlog.0000xx | more
- 優點:可以避免MySQL復制中出現的主從不一致的問題(主從更安全)
- binlog_format=
mixed
:基於行和端的混合格式(推薦
)- PS:數據量大小由所執行的SQL決定(非確定性函數越多,行數越多)
PS:DDL操作(create、drop、alter)的時候都是基於段方式來記錄log
如果一條一條記錄,表有上億數據,我就修改某列的狀態值,那不得瘋?
對binlog_row_image=[FULL|MINIMAL|NOBLOB]
的補充說明:
PS:查看方式:
show variables like 'binlog_row_image'
- 默認是
full
:完整- 記錄修改行的全部內容
noblob
:就是在full記錄的基礎上對大文本列的優化- 沒有對text或者blob列修改就不記錄該列
minimal
:簡單記錄,只記錄修改的那一列- PS:這個要特別注意一點,雖然容量小了,但是一旦誤操作,很難恢復的(不知道原來內容)
推薦使用
一般使用binlog_format=mixed
混合格式 or binlog_format=row
+ binlog_row_image=minimal
PS:如果對安全性要求特別高,推薦使用
binlog_format=row
+binlog_row_image=full
(不怕誤操作)
這個和SQLServer的日志恢復模式有點類似,我貼下圖你們可以對比參考:
5.2.二進制日志配置
上面雖然說完了二進制日志的常用3種格式,但老版本默認都是不啟用二進制日志的,咋辦?
PS:如果是MariaDB可以去示例配置中查看:
ls /usr/share/mysql/ |grep .cnf
(CentOS)
驗證下:
MySQL8之前:cat /etc/mysql/mysql.conf.d/mysqld.cnf
(UbuntuServer)
MySQL8:cat /etc/my.cnf |grep log
(CentOS)
Q:有些人可能疑惑了,為什么用show variables like 'log_bin';
查詢出來的結果和配置文件中不大一樣啊?
PS:一般配置項中的參數都可以使用
show variables like 'xx'
來查詢對應的值
A:那是因為5.7之后版本分成了兩個參數:log_bin
和log_bin_basename
:
PS:配置文件的
log_bin=xxx
相當於命令中的log_bin
和log_bin_basename
mysql> show variables like 'log_bin%';
+---------------------------------+-----------------------------+
| Variable_name | Value |
+---------------------------------+-----------------------------+
| log_bin | ON |
| log_bin_basename | /var/lib/mysql/binlog |
| log_bin_index | /var/lib/mysql/binlog.index |
| log_bin_trust_function_creators | OFF |
| log_bin_use_v1_row_events | OFF |
+---------------------------------+-----------------------------+
5 rows in set (0.00 sec)
開啟演示
MariaDB開啟binlog圖示:(CentOS)
MySQL5.7演示:(UbuntuServer)
配置文件中修改:(show variables like 'binlog_format';
:查看當前binlog基於什么格式)
# 服務器標識
server-id=1 # 單機MariaDB可不開啟
# 開啟binlog並設置路徑
# 不指定路徑則默認在數據目錄下
log_bin=binlog # 這個代表以binlog開頭的文件
# binlog采用ROW|MIXED格式
# binlog_format=MIXED # 5.7默認是ROW
先看下文件前綴(log_bin=binlog
)的概念,一張圖就懂:
PS:如果log_bin只是指定一個名字,那么默認路徑一般都是在數據文件的文件夾中
配置文件一般都會寫,eg:
datadir=/var/lib/mysql
,或者通過show variables like 'datadir';
也可以查詢到
雖然和SQLServer文件組不是一個概念,但有些相似 ==> log可以多個也可以動態調整
5.3.ROW模式下記錄SQL
Q:雖然ROW記錄能保證主從數據安全,但我們排查問題的時候往往需要知道SQL,而用段的記錄方式又不合適,咋辦?
A:有個新參數可以解決:binlog_rows_query_log_events
,開啟后就可以記錄sql了
查看方式:show variables like 'binlog_row%';
mysql> show variables like 'binlog_row%';
+------------------------------+-------+
| Variable_name | Value |
+------------------------------+-------+
| binlog_row_image | FULL |
| binlog_rows_query_log_events | OFF |
+------------------------------+-------+
2 rows in set (0.01 sec)
binlog演示
顯示binlog列表:show binary logs;
刷新一份新的binlog:flush logs;
(現在開始的二進制日志就記錄在這個新文件中)
binlog現在是空的:(-vv
:把二進制格式的日志顯示為能讀懂的字符串)
mysqlbinlog --no-defaults -vv --base64-output=DECODE-ROWS /var/lib/mysql/binlog.000006
現在簡單摸擬幾個SQL操作,然后看看binlog:
查看下binlog日志:(線上開發一般都是FULL模式,主要是防止程序員修改SQL的時候不加條件等誤操作)
FULL模式就是這樣,該行數據全部記錄(修改部分其實就綠色框的地方)
想要binlog中記錄SQL就開啟binlog_rows_query_log_events
:
PS:像這種操作,如果模式選混合模式,binlog中會記錄SQL的
臨時開啟下binlog_rows_query_log_events
(如果你有需要可以配置文件設置一下)
PS:MySQL8可通過
set persist
命令將全局變量的修改持久化到配置文件中
效果如下:
5.4.二進制日志的清除
- 自動清除
- 配置文件中設置時間:
expire_logs_days = 30
- 配置文件中設置時間:
- 手動清除
- 刪除指定編號之前的日志:
purge binary logs to 'binlog.000006';
- 刪除指定時間之前的日志:
purge binary logs before '2019-06-15 14:14:00';
- 刪除指定編號之前的日志:
已經23:23了,我們快速演示下:
MySQL命令行中執行命令:
文件列表:
5.5.二進制日志與主從
這個把運維篇講完會繼續說,運維篇結束后會有個高級篇(架構),這邊就簡單提下二進制格式對主從復制的影響
:
- 基於SQL語句的復制(SBR)
- 二進制日志格式使用的是
statement
格式(5.7前的默認)
- 二進制日志格式使用的是
- 基於行的復制(RBR)
- 二進制日志格式使用的是基於行的日志格式
- 混合模式
- 根據實際在上面兩者中切換
貼個課后拓展文章:https://www.cnblogs.com/gujianzhe/p/9371682.html
下級預估:備份與恢復、監控