Mysql binlog 相關
MySQL 修改密碼
sudo -s
mysql
use mysql
ALTER USER root@localhost IDENTIFIED WITH caching_sha2_password BY '123456'
MySQL 允許 root 遠程登錄
mysql -u root -p
use mysql
GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY '123456'
flush privileges
開啟 MySQL 的 binlog 日志
在my.inf主配置文件中直接添加三行
log-bin=/var/lib/mysql/mysql-bin
server-id=123454 #5.7以上需要
然后重啟服務
查看數據庫是否支持 binlog:
show variables like '%log_bin%'
首先 binlog 需要配合定期備份一起恢復數據,如果數據庫沒有做定期備份,那只有 binlog 也是白瞎。
binlog 恢復實戰一
先說明一下背景:一台 Mysql5.7 數據庫,開啟了 binlog,且設置了每日凌晨 1 點備份一次數據庫。早上 10:30 數據庫操作人員誤 ##誤更新/刪除## 1W 條數據導致系統出現了嚴重問題。
11:00 關閉系統,停止運行,並開始着手數據恢復。
這里 ##誤更新/刪除/新增## 為簡單的場景,比如更新或刪除數據忘記添加 where
條件。我們可以通過找到當時時間點的 binlog,然后通過人工替換字符串的方式來恢復。
數據恢復步驟如下:
- 停止運行服務,並開始着手數據恢復。
- 數據庫執行
flush logs;
將最新的 binlog 生成。 - 找到需要恢復的 binlog。
- 通過分析 binlog 生成恢復 sql。
- 執行 sql 進行恢復。
我們可以通過時間點來找到響應的 binlog 日志,比如我們找到的 binlog 日志名字為:binlog.000001
mysqlbinlog -D --database=release -v binlog.000001 > temp.sql
然后找到出事時的 binlog 日志,大約如下:
# at 599
BEGIN
### UPDATE `release`.`co_record`
### WHERE
### @1='5c0751c4189d4cd5b9c7223ca0ad74689f4915b5421e4cc0ac50e1e6b640c787'
### @2='2021-11-02 15:07:00'
### SET
### @1='5c0751c4189d4cd5b9c7223ca0ad74689f4915b5421e4cc0ac50e1e6b640c787'
### @2='2021-11-02 15:06:00'
# at 1923
COMMIT/*!*/;
需要對這種偽 sql 進行轉換成恢復 sql。這個部分自行轉換,轉換好的 sql 應該長這個樣子:
UPDATE `release`.`co_record` SET xxx='5c0751c4189d4cd5b9c7223ca0ad74689f4915b5421e4cc0ac50e1e6b640c787', xxx= '2021-11-02 15:06:00';
轉換這個部分很煩,需要根據業務來靈活轉換,但基本上就是字符串批量替換的事情。
binlog 恢復實戰二
先說明一下背景:一台 Mysql5.7 數據庫,開啟了 binlog,且設置了每日凌晨 1 點備份一次數據庫。早上 10:30 數據庫操作人員 誤更新/刪除 1W 條數據導致系統出現了嚴重問題。
11:00 關閉系統,停止運行,並開始着手數據恢復。
這里 誤更新/刪除/新增 為復雜的場景,沒有辦法通過上一個辦法恢復。這時候可以嘗試全量恢復。
數據恢復步驟如下:
- 停止運行服務,並開始着手數據恢復。
- 數據庫執行
flush logs;
將最新的 binlog 生成。 - 找到需要恢復的 binlog。
- 全量恢復今日凌晨1點備份的數據庫。
- 恢復 binlog。
由於每天凌晨 1 點會備份數據,只要將包含凌晨 1 點的 binlog 和以后的 binlog 找到即可。比如我們找到 binlog.000001/binlog.000002/binlog.000003/binlog.000004 四個日志文件。
也許真實的場景只有一個或更多的 binlog 日志,但總結起來就分為四種日志:
- binlog 記錄了 凌晨 1 點前的數據,結束於備份完成后
- binlog 記錄了 備份完成后且不包含出事的記錄
- binlog 記錄了 出事時的記錄
- binlog 記錄了 出事后的記錄且不包含出事的記錄
其中 2 4 記錄是最簡單的,直接恢復就可以了。 1 3 需要倒出來處理一下才可以。
第一種情況的 binlog 包含了已經恢復的數據,當我們恢復了凌晨 1 點備份后,這份 binlog 我們就只需要恢復 1 點后的數據,所以我們要按照時間來過濾。
例子中的 933659 就是凌晨 1 點后第一個需要恢復的數據的位置
mysqlbinlog -D --database=release --start-position=933659 binlog.000001 | mysql -u root -p -v release
第二種情況和第四種情況就直接按照時間先后執行即可
mysqlbinlog -D --database=release binlog.000002 | mysql -u root -p -v release
## 執行完 binlog.000003 后
mysqlbinlog -D --database=release binlog.000004 | mysql -u root -p -v release
第三種情況是最難處理的,因為該 binlog 包含了一串錯誤的日志,我們需要將這部分記錄去除,然后再恢復。我們這里是 誤更新/刪除/新增 1W 條數據。
這里就需要人工的將這部分數據的開始位置和結束位置找到,然后跳過這部分記錄恢復。
比如我們這里例子中錯誤的記錄是在 4500-67000 行之間,那么我們就需要分兩步來恢復。
mysqlbinlog -D --database=release --stop-position=4500 binlog.000003 | mysql -u root -p -v release
mysqlbinlog -D --database=release --start-position=67000 binlog.000003 | mysql -u root -p -v release
其實恢復就是對數據庫操作的重放,binlog 記錄了所有數據庫的操作,只要將錯誤和不要的 binlog 記錄剔除出去,就可以恢復。
但是這里有一個問題,就是我們去除了誤更新/刪除/新增 1W 條數據的 binlog 記錄,這個時候,其實后面的 binlog 恢復(10:30 以后的數據)就很容易出錯。
因為用戶是在錯誤的數據的基礎上繼續更新的,我們將錯誤的數據去除后,就和真實的數據對應不上了,所以很大情況下我們就只能恢復到 10:30 時的數據,再往后的數據很難找回。