Mysql binlog 數據恢復


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 時的數據,再往后的數據很難找回。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM