MySQL二進位制檔案(binlog)
阿新 • • 發佈:2020-12-04
二進位制檔案(binlog)記錄對MySQL資料庫執行更改的所有操作,但不包括SELECT和SHOW這類操作,因為這類操作沒有改變資料。
### 為什麼會有binlog?
首先 binlog 是 Server 層的日誌模組,最初設計來是為了歸檔(備份)使用的。經過多個版本的發展,現在 binlog 主要有三個作用:
- 恢復:提供 point-in-time 的恢復功能。通過全備+binlog,可實現恢復到指定時間的資料庫資料。
- 複製:主備複製(同步)的基礎模組,主庫寫 binlog,再發送給備庫執行,實現主備資料一致性。
- 審計:使用者可以通過二進位制日誌中的資訊來進行審計,判斷是否有對資料庫進行注入的攻擊。
### 如何記錄
下面以一條Update語句來介紹 binlog 是如何記錄的。
```
mysql> update T set c=c+1 where ID=2;
```
![update語句執行流程圖](https://static001.geekbang.org/resource/image/2e/be/2e5bff4910ec189fe1ee6e2ecc7b4bbe.png)
1. 取得 ID=2 這一行(通過記憶體或磁碟讀取)
2. 這行的 c 值加1
3. 更新到記憶體
4. 寫入 redo log(處於 prepare 階段)
5. 寫 binlog
6. 提交事務(處於 commit 狀態)
這裡涉及兩階段提交和 redo log 的內容,感興趣的移步到[此處]()。
binlog 的寫入時機是在資料更改後,事務提交前。
### 三種寫入格式
#### binlog_format=STATEMENT
binlog 記錄邏輯SQL語句。
當執行以下命令:
```
mysql> delete from t /*comment*/ where a>=4 and t_modified<='2018-11-10' limit 1;
mysql> show binlog events in 'master.000001';
```
其中'master.000001'是binlog的檔名。
binlog 記錄的內容如下圖所示:
![image](https://static001.geekbang.org/resource/image/b9/31/b9818f73cd7d38a96ddcb75350b52931.png)
優點:省空間:只記錄邏輯語句。
缺點:可能產生主備不一致。
```
mysql> delete from t /*comment*/ where a>=4 and t_modified<='2018-11-10' limit 1;
```
上面的SQL,假如在主庫使用索引 a,而備庫使用索引 t_modified 會導致刪除的記錄不一樣。
#### binlog_format=ROW
binlog 記錄表的行更改情況。配合 READ COMMITED,獲得更好的併發性。
檢視 binlog 內容:`mysql> show binlog events in 'master.000001';`(其中'master.000001'是binlog的檔名)
![image](https://static001.geekbang.org/resource/image/d6/26/d67a38db154afff610ae3bb64e266826.png)
解析 binlog 內容:使用 mysqlbinlog 命名解析 binlog 內容。
```
liang24@ubuntu:~$ mysqlbinlog -vv data/master.000001 --start-position=8900;
```
![image](https://static001.geekbang.org/resource/image/c3/c2/c342cf480d23b05d30a294b114cebfc2.png)
優點:記錄原始資料;保證主備一致性;
缺點:
1、費空間:因為要儲存原始資料;
例如:刪除十萬行資料,STATEMENT 格式只記錄邏輯語句,而 ROW 會記錄十萬條日誌,相當費空間。
2、費IO
例如:刪除十萬行資料,ROW 會記錄十萬條日誌,而寫 binlog 會耗費一定的 IO。
**推薦使用** binlog_format=ROW:能記錄原記錄資料。誤操作時,能夠根據原資料進行恢復,例如 Delete 就轉寫成 Insert,Update 就把 Update 前的再執行一次。
#### binlog_format=MIXED
因為 STATEMENT 和 ROW 各有優缺點,因此 MySQL 新增了一種格式 MIXED,採用折中方案,MySQL 會判斷採用 STATEMENT 還是 ROW 來記錄 binlog。
### 如何使用
1、檢視是否開啟
mysql 預設是不開啟 binlog 的。
```mysql
mysql> show variables like 'log_bin%';
+---------------------------------+-------+
| Variable_name | Value |
+---------------------------------+-------+
| log_bin | OFF |
| log_bin_basename | |
| log_bin_index | |
| log_bin_trust_function_creators | OFF |
| log_bin_use_v1_row_events | OFF |
+---------------------------------+-------+
5 rows in set (0.00 sec)
```
從結果看到 `log_bin=OFF`,知道沒有開啟 binlog。
2、開啟 binlog 日誌
退出 MySQL,使用 vi 編輯器修改 MySQL 的 my.cnf 配置檔案(vim /etc/my.cnf)
```
# server-id:表示節點名稱
server-id=1
# log-bin:表示儲存binlog日誌的目錄和binlog的檔名
log-bin=/var/lib/mysql/mysql-bin
```
3、重啟 MySQL 及檢視 binlog 開啟狀態
```shell
service mysql restart
```
登入 MySQL,輸入 `show variables like '%log_bin%';` 檢視到 binlog=ON ;
```mysql
mysql> show variables like 'log_bin%';
+---------------------------------+--------------------------------+
| Variable_name | Value |
+---------------------------------+--------------------------------+
| log_bin | ON |
| log_bin_basename | /var/lib/mysql/mysql-bin |
| log_bin_index | /var/lib/mysql/mysql-bin.index |
| log_bin_trust_function_creators | OFF |
| log_bin_use_v1_row_events | OFF |
+---------------------------------+--------------------------------+
5 rows in set (0.00 sec)
```
### 參考資料
- [02 | 日誌系統:一條SQL更新語句是如何執行的?](https://time.geekbang.org/column/articl