往期回顧 - [圖文結合帶你搞定MySQL日誌之Undo log(回滾日誌)](http://mp.weixin.qq.com/s?__biz=MzkzMTIzMDgwMg==&mid=2247496981&idx=1&sn=ec496da6e52e19ee505483a15fb54f6b&chks ...
往期回顧
- 圖文結合帶你搞定MySQL日誌之Undo log(回滾日誌)
- 圖文結合帶你搞懂InnoDB MVCC
- 圖文結合帶你搞懂MySQL日誌之Redo Log(重做日誌)
- 圖文結合帶你搞懂MySQL日誌之Error Log(錯誤日誌)
- 圖文結合帶你搞懂MySQL日誌之Slow Query Log(慢查詢日誌)
- 圖文結合帶你搞懂MySQL日誌之relay log(中繼日誌)
- 圖文結合帶你搞懂MySQL日誌之General Query Log(通用查詢日誌)
此篇為圖文結合搞懂MySQL日誌的最後一篇,MySQL中共有八大日誌,其中數據定義語句日誌不是給用戶查看的,在此篇尾部簡單介紹,接下來圖文結合系列還會繼續推出新文章!
二進位日誌(Binary log)
binlog可以說是MySQL中比較重要
的日誌了,在日常開發及運維過程中,經常會遇到。
binlog即binary log,二進位日誌文件,也叫作變更日誌(update log)。它記錄了資料庫所有執行的DDL和DML等資料庫更新事件的語句,但是不包含沒有修改任何數據的語句(如數據查詢語句select、show等)。
它以事件形式
記錄並保存在二進位文件
中。通過這些信息,我們可以再現數據更新操作的全過程。
如果想要記錄所有語句(例如,為了識別有問題的查詢),需要使用通用查詢日誌。
Binary log主要應用場景:
- 一是用於
數據恢復
,如果MySQL資料庫意外停止,可以通過二進位日誌文件來查看用戶執行了哪些操作,對資料庫伺服器文件做了哪些修改,然後根據二進位日誌文件中的記錄來恢複數據庫伺服器。 - 二是用於
數據複製
,由於日誌的延續性和時效性,master把它的二進位日誌傳遞給slaves來達到master-slave數據一致的目的。
可以說MySQL資料庫的數據備份、主備、單主、多主、MGR都離不開Binary log,需要依靠Binary log來同步數據,保證數據一致性。
查看預設情況
查看記錄二進位日誌是否開啟:在MySQL8中預設情況下,二進位文件是開啟的。
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 | ON |// 函數創建
| log_bin_use_v1_row_events | OFF |
| sql_log_bin | ON |//變更sql記錄下來
+---------------------------------+-----------------------------+
6 rows in set (0.01 sec)
log_bin_basename:
是binlog日誌的基本文件名,後面會追加標識來表示每一個文件log_bin_index:
是binlog文件的素引文件,這個文件管理了所有的binlog文件的目錄log_bin_trust_function_creators:
限制存儲過程,前面我們已經講過了,這是因為二進位日誌的一個重要功能是用於主從複製,而存儲函數有可能導致主從的數據不一致。所以當開啟二進位日誌後,需要限制存儲函數的創建、修改、調用log_bin_use_v1_row_events此只讀系統變數已棄用
。ON表示使用版本1二進位日誌行,OFF表示使用版本2二進位日誌行(MySQL5.6的預設值為2)。
日誌參數設置
方式 1 :永久性方式
修改MySQL的my.cnf或my.ini文件可以設置二進位日誌的相關參數:
[mysqld]
#啟用二進位日誌
log-bin=atguigu-bin
binlog_expire_logs_seconds= 600
max_binlog_size=100M
提示:
- log-bin=mysql-bin
打開日誌(主機需要打開),這個mysql-bin也可以自定義,這裡也可以加上路徑,如:/home/www/mysql_bin_log/mysql-bin
- binlog_expire_logs_seconds
此參數控制二進位日誌文件保留的時長單位是秒,預設2592000 30天 --14400 4小時;86400 1天; 259200 3天;
- max_binlog_size
控制單個二進位日誌大小,當前日誌文件大小超過此變數時,執行切換動作。此參數的最大和預設值是1GB
,該設置並不能嚴格控制Binlog的大小
,尤其是Binlog比較靠近最大值而又遇到一個比較大事務時,為了保證事務的完整性,可能不做切換日誌的動作只能將該事務的所有SQL都記錄進當前日誌,直到事務結束。一般情況下可採取預設值。
設置帶文件夾的bin-log日誌存放目錄
如果想改變日誌文件的目錄和名稱,可以對my.cnf或my.ini中的log_bin參數修改如下:
[mysqld]
log-bin="/var/lib/mysql/binlog/atguigu-bin"
註意:新建的文件夾需要使用mysql用戶,使用下麵的命令即可。
chown -R -v mysql:mysql binlog
提示 資料庫文件最好不要與日誌文件放在同一個磁碟上!
這樣,當資料庫文件所在的磁碟發生故障時,可以使用日誌文件恢複數據。
方式 2 :臨時性方式
如果不希望通過修改配置文件並重啟的方式設置二進位日誌的話,還可以使用如下指令,需要註意的是在mysql 8 中只有會話級別的設置,沒有了global級別的設置。
# global 級別
mysql> set global sql_log_bin= 0 ;
ERROR 1228 (HY000): Variable 'sql_log_bin' is a SESSION variable and can`t be used
with SET GLOBAL
# session級別
mysql> SET sql_log_bin = 0 ;
Query OK, 0 rows affected (0.01 秒)
查看日誌
當MySQL創建二進位日誌文件時,先創建一個以“filename”為名稱、以“.index”為尾碼的文件,再創建一個以“filename”為名稱、以“.000001”為尾碼的文件。
MySQL服務重新啟動一次,以“.000001”為尾碼的文件就會增加一個,並且尾碼名按 1 遞增。即日誌文件的數與MySQL服務啟動的次數相同;如果日誌長度超過了max_binlog_size的上限(預設是1GB),就會創建一個新的日誌文件。
查看當前的二進位日誌文件列表及大小。指令如下:
mysql> SHOW BINARY LOGS;
+--------------------+-----------+-----------+
| Log_name | File_size | Encrypted |
+--------------------+-----------+-----------+
| atguigu-bin.000001 | 156 | No |
+--------------------+-----------+-----------+
1 rows in set (0.00 sec)
所有對資料庫的修改都會記錄在binglog中。但binlog是二進位文件,無法直接查看,藉助mysqlbinlog命令工具了。指令如下:在查看執行,先執行一條sQL語句,如下
update student set name='張三_back' where id=1;
[root@localhost ~]$ cd /var/lib/mysql
[root@localhost ~]$ mysqlbinlog "/var/lib/mysql/lqhdb-binlog.000001"
執行結果可以看到,這是一個簡單的日誌文件,日誌中記錄了用戶的一些操作,這裡並沒有出現具體的SQL語句,這是因為binlog關鍵字後面的內容是經過編碼後的二進位日誌。
這裡一個update語句包含如下事件
- Query事件負責開始一個事務(BEGIN)
- Table_map事件負責映射需要的表
- Update_rows事件負責寫入數據
- Xid事件負責結束事務
下麵命令將行事件以偽SQL
的形式表現出來
mysqlbinlog -v "/var/lib/mysql/binlog/test.000002"
前面的命令同時顯示binlog格式的語句,使用如下命令不顯示它
mysqlbinlog -v --base64-output=DECODE-ROWS "/var/lib/mysql/binlog/test.000002"
關於mysqlbinlog工具的使用技巧還有很多,例如只解析對某個庫的操作或者某個時間段內的操作等。簡單分享幾個常用的語句,更多操作可以參考官方文檔。
# 可查看參數幫助
mysqlbinlog --no-defaults --help
# 查看最後 100 行
mysqlbinlog --no-defaults --base64-output=decode-rows -vv atguigu-bin.000002 |tail - 100
# 根據position查找
mysqlbinlog --no-defaults --base64-output=decode-rows -vv atguigu-bin.000002 |grep -A
20 '4939002'
上面這種辦法讀取出binlog日誌的全文內容比較多,不容易分辨查看到pos點信息,下麵介紹一種更為方便的查詢命令:
mysql> show binlog events [IN 'log_name'] [FROM pos] [LIMIT [offset,] row_count];
IN 'log_name':
指定要查詢的binlog文件名(不指定就是第一個binlog文件)FROM pos:
指定從哪個pos起始點開始查起(不指定就是從整個文件首個pos點開始算)LIMIT [offset]:
偏移量(不指定就是 0 )row_count :
查詢總條數(不指定就是所有行)
上面這條語句可以將指定的binlog日誌文件,分成有效事件行的方式返回,並可使用limit指定pos點的起始偏移,查詢條數。其它舉例:
#a、查詢第一個最早的binlog日誌:
show binlog events\G ;
#b、指定查詢mysql-bin.088802這個文件
show binlog events in 'atguigu-bin. 008002'\G;
#c、指定查詢mysql-bin. 080802這個文件,從pos點:391開始查起:
show binlog events in 'atguigu-bin.008802' from 391\G;
#d、指定查詢mysql-bin.000802這個文件,從pos點:391開始查起,查詢5條(即5條語句)
show binlog events in 'atguigu-bin.000882' from 391 limit 5\G
#e、指定查詢 mysql-bin.880002這個文件,從pos點:391開始查起,偏移2行〈即中間跳過2個)查詢5條(即5條語句)。
show binlog events in 'atguigu-bin.088882' from 391 limit 2,5\G;
binlog格式查看
mysql> show variables like 'binlog_format';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| binlog_format | ROW | //行格式
+---------------+-------+
1 rows in set (0.00 sec)
除此之外,binlog還有 2 種格式,分別是Statemen
和Mixed
- Statement 每一條會修改數據的sql都會記錄在binlog中。 優點:不需要記錄每一行的變化,減少了binlog日誌量,節約了IO,提高性能。
- Row 5.1.5版本的MySQL才開始支持row level 的複製,它不記錄sql語句上下文相關信息,僅保存哪條記錄被修改。 優點:row level 的日誌內容會非常清楚的記錄下每一行數據修改的細節。而且不會出現某些特定情況下的存儲過程,或function,以及trigger的調用和觸發無法被正確複製的問題。
- Mixed 從5.1.8版本開始,MySQL提供了Mixed格式,實際上就是Statement與Row的結合。
使用日誌恢複數據
mysqlbinlog恢複數據的語法如下:
mysqlbinlog [option] filename|mysql –uuser -ppass;
這個命令可以這樣理解:使用mysqlbinlog命令來讀取filename中的內容,然後使用mysql命令將這些內容恢復到資料庫中。
-
filename:是日誌文件名。
-
option:可選項,比較重要的兩對option參數是–start-date、–stop-date 和 --start-position、–stop-position。
-
- –start-date 和 - -stop-date:可以指定恢複數據庫的起始時間點和結束時間點。
- –start-position和–stop-position:可以指定恢複數據的開始位置和結束位置。
註意:使用mysqlbinlog命令進行恢復操作時,必須是編號小的先恢復,例如atguigu-bin.000001必須在atguigu-bin.000002之前恢復。
flush logs; #可以生成新的binLog 文件,不然這個文件邊恢復邊變大是不行的。
show binary logs; # 顯示有哪些binLog 文件
恢複數據
mysqlbinlog [option] filename|mysql –uuser -ppass;
mysqlbinlog --no-defaults --start-position=236 --stop-position=1071 --database=my_db1 /var/lib/mysql/lqhdb-bin.000002 | /usr/bin/mysql -root -p123456 -v my_db1
刪除二進位日誌
MySQL的二進位文件可以配置自動刪除,同時MySQL也提供了安全的手動刪除二進位文件的方法。PURGE MASTER LOGS
只刪除指定部分的二進位日誌文件,RESET MASTER
刪除所有的二進位日誌文件。具體如下:
1.PURGE MASTER LOGS:刪除指定日誌文件
PURGE MASTER LOGS語法如下:
PURGE {MASTER | BINARY} LOGS TO ‘指定日誌文件名’
PURGE {MASTER | BINARY} LOGS BEFORE ‘指定日期’
舉例 :使用PURGE MASTER LOGS語句刪除創建時間比binlog.000005早的所有日誌
(1)多次重新啟動MysSQL服務,便於生成多個日誌文件。然後用SHOW語句顯示二進位日誌文件列表
SHOW BINARY LOGS;
(2)執行PURGE MASTER LOGS語句刪除創建時間比binlog.000005早的所有日誌
PURGE MASTER LOGS T0 "binlog. 000005";
(3)顯示二進位日誌文件列表
SHGW BINARY LOGS;
舉例:使用PURGE MASTER LOGS語句刪除2023年3月17日前創建的所有日誌文件。具體步驟如下:
(1) 顯示二進位日誌文件列表
SHOW BINARY LOGS;
(2)執行mysqlbinlog命令查看二進位日誌文件binlog.000005的內容
mysqlbinlog --no-defaults "/var/lib/mysql/binlog/atguigu-bin.000005"
(3)使用PURGE MASTER LOGS語句刪除2023年3月17日前創建的所有日誌文件
PURGE MASTER LOGS before "20220317";
(4)顯示二進位日誌文件列表
SHOW BINARY LOGS;
2022年01月05號之前的二進位日誌文件都已經被刪除,最後一個沒有刪除,是因為當前在用,還未記錄最後的時間,所以未被刪除。
2.RESET MASTER:刪除所有二進位日誌文件
reset master;
其它場景
二進位日誌可以通過資料庫的全量備份
和二進位日誌中保存的增量信息
,完成資料庫的無損失恢復
。但是,如果遇到數據量大、資料庫和數據表很多(比如分庫分表的應用)的場景,用二進位日誌進行數據恢復,是很有挑戰性的,因為起止位置不容易管理。
在這種情況下,一個有效的解決辦法是配置主從資料庫伺服器
,甚至是一主多從
的架構,把二進位日誌文件的內容通過中繼日誌,同步到從資料庫伺服器中,這樣就可以有效避免資料庫故障導致的數據異常等問題。
深入理解二進位日誌
寫入機制
binlog的寫入時機也非常簡單,事務執行過程中,先把日誌寫到binlog cache
,事務提交的時候,再把binlog cache寫到binlog文件中。因為一個事務的binlog不能被拆開,無論這個事務多大,也要確保一次性寫入,所以系統會給每個線程分配一個塊記憶體作為binlog cache。
我們可以通過binlog_cache_size
參數控制單個線程binlog cache大,如果存儲內容超過了這個參數,就要暫存到磁碟(Swap)。binlog日誌刷盤流程如下:
上圖的write,是指把日誌寫入到文件系統的page cache,並沒有把數據持久化到磁碟,所以速度比較快。
上圖的fsync,才是將數據持久化到磁碟的操作
write和fsync的時機,可以由參數sync_binlog
控制,預設是 0 。
為 0 的時候,表示每次提交事務都只write,由系統自行判斷什麼時候執行fsync。雖然性能得到提升,但是機器宕機,page cache裡面的binglog 會丟失。如下圖:
為了安全起見,可以設置為 1 ,表示每次提交事務都會執行fsync,就如同 redo log 刷盤流程 一樣。最後還有一種折中方式,可以設置為N(N>1),表示每次提交事務都write,但累積N個事務後才fsync。
在出現IO瓶頸的場景里,將sync_binlog設置成一個比較大的值,可以提升性能。同樣的,如果機器宕機,會丟失最近N個事務的binlog日誌。
binlog與redolog對比
-
redo log 它是
物理日誌
,記錄內容是“在某個數據頁上做了什麼修改”,屬於 InnoDB 存儲引擎層產生的。 -
而 binlog 是
邏輯日誌
,記錄內容是語句的原始邏輯,類似於“給 ID=2 這一行的 c 欄位加 1”,屬於MySQL Server 層 -
雖然它們都屬於持久化的保證,但是則重點不同。
-
- redo log讓InnoDB存儲引擎擁有了崩潰恢復能力。
- binlog保證了MySQL集群架構的數據一致性。
Enjoy GreatSQL