MySQL 閃回工具之 binlog2sql

前奏

  DBA/開發 工做過程當中誤刪數據、誤改數據是常有的事,做爲 DBA 如何快速填坑呢python

  (1)利用最近的全量備份+增量binlog備份,恢復到誤操做以前的狀態,可是隨着數據量的增大,binlog的增多,恢復起來很費時。mysql

  (2)若是binlog的格式爲row,那麼就能夠將binlog解析出來生成反向的原始SQLgit

固然還有其餘的一些操做方法,這裏暫不展開來說,咱們今天主要介紹binlog2sql  github

  大衆點評開源的一個 MySQL 閃回工具 -- binlog2sqlsql

閃回原理

binlog 概述:bash

  MySQL binlog 以event 的形式,記錄了 MySQL  server 從啓用 binlog 以來的全部變動信息,可以幫實現這之間的全部變化。工具

  MySQL 引用 binglog 的主要目的:1、主從複製;2、某些備份還原操做須要從新應用 binlogspa

  既然 binlog 以 event 形式記錄了全部的變動信息,那麼咱們把須要回滾的event,從後往前回滾回去便可。code

  閃回前提:log_bin 爲 ON;binlog_row_image 爲full;binlog_format 爲 row;orm

| log_bin                                   | ON                                                 |
| binlog_row_image                        | full                                                 |
| binlog_format                            | ROW                                               |

回滾操做:

  • 對於 delete 操做,咱們從 binlog 提取出 delete 信息,反向生成 insert 回滾語句;
  • 對於 insert 操做,反向生成 delete 回滾語句;
  • 對於update操做,回滾sql應該交換SET和WHERE的值。

閃回實戰

(一) 安裝binlog2sql

 

(root@localhost) [employees]> select *  from titles where emp_no <= 10007 ; +--------+-----------------+------------+---------+
| emp_no | title           | from_date  | to_date |
+--------+-----------------+------------+---------+
|  10001 | Senior          | 1986-06-26 | NULL    |
|  10002 | Staff           | 1996-08-03 | NULL    |
|  10003 | Senior Engineer | 1995-12-03 | NULL    |
|  10004 | Engineer        | 1986-12-01 | NULL    |
|  10004 | Senior Engineer | 1995-12-01 | NULL    |
|  10005 | Senior Staff    | 1996-09-12 | NULL    |
|  10005 | Staff           | 1989-09-12 | NULL    |
|  10006 | Senior Engineer | 1990-08-05 | NULL    |
|  10007 | Senior Staff    | 1996-02-11 | NULL    |
|  10007 | Staff           | 1989-02-10 | NULL    |
+--------+-----------------+------------+---------+
10 rows in set (0.00 sec) (root@localhost) [employees]> delete  from titles where emp_no <= 10007 ; Query OK, 10 rows affected (0.00 sec) (root@localhost) [employees]> select *  from titles where emp_no <= 10007 ; Empty set (0.00 sec)

(root@localhost) [employees]> show master status\G
*************************** 1. row ***************************
File: mysql-bin.000015
Position: 364596
Binlog_Do_DB:
Binlog_Ignore_DB:
Executed_Gtid_Set:
1 row in set (0.00 sec)

(root@localhost) [employees]> select now();
+---------------------+
| now() |
+---------------------+
| 2019-01-23 16:26:43 |
+---------------------+
1 row in set (0.00 sec)

 

 

 

[root@05 binlog2sql]# python binlog2sql.py -h127.0.0.1 -P3306 -uroot -p123 -demployees -t titles --start-file=mysql-bin.000015 --start-datetime='2019-01-23 16:20:04'

[root@05 binlog2sql]# python binlog2sql.py --flashback  -h127.0.0.1 -P3306 -uroot -p123 -demployees -t titles --start-file=mysql-bin.000015 --start-datetime='2019-01-23 16:20:04' >tit.sql

[root@05 binlog2sql]# mysql -uroot -p123 --database employees < tit.sql

[root@05 binlog2sql]# python binlog2sql.py -h127.0.0.1 -P3306 -uroot -p123 -demployees -t titles --start-file=mysql-bin.000015 --start-datetime='2019-01-23 16:20:04'


DELETE FROM `employees`.`titles` WHERE `emp_no`=10001 AND `to_date` IS NULL AND `from_date`='1986-06-26' AND `title`='Senior' LIMIT 1; #start 364141 end 364565 time 2019-01-23 16:23:59
DELETE FROM `employees`.`titles` WHERE `emp_no`=10002 AND `to_date` IS NULL AND `from_date`='1996-08-03' AND `title`='Staff' LIMIT 1; #start 364141 end 364565 time 2019-01-23 16:23:59
DELETE FROM `employees`.`titles` WHERE `emp_no`=10003 AND `to_date` IS NULL AND `from_date`='1995-12-03' AND `title`='Senior Engineer' LIMIT 1; #start 364141 end 364565 time 2019-01-23 16:23:59
DELETE FROM `employees`.`titles` WHERE `emp_no`=10004 AND `to_date` IS NULL AND `from_date`='1986-12-01' AND `title`='Engineer' LIMIT 1; #start 364141 end 364565 time 2019-01-23 16:23:59
DELETE FROM `employees`.`titles` WHERE `emp_no`=10004 AND `to_date` IS NULL AND `from_date`='1995-12-01' AND `title`='Senior Engineer' LIMIT 1; #start 364141 end 364565 time 2019-01-23 16:23:59
DELETE FROM `employees`.`titles` WHERE `emp_no`=10005 AND `to_date` IS NULL AND `from_date`='1996-09-12' AND `title`='Senior Staff' LIMIT 1; #start 364141 end 364565 time 2019-01-23 16:23:59
DELETE FROM `employees`.`titles` WHERE `emp_no`=10005 AND `to_date` IS NULL AND `from_date`='1989-09-12' AND `title`='Staff' LIMIT 1; #start 364141 end 364565 time 2019-01-23 16:23:59
DELETE FROM `employees`.`titles` WHERE `emp_no`=10006 AND `to_date` IS NULL AND `from_date`='1990-08-05' AND `title`='Senior Engineer' LIMIT 1; #start 364141 end 364565 time 2019-01-23 16:23:59
DELETE FROM `employees`.`titles` WHERE `emp_no`=10007 AND `to_date` IS NULL AND `from_date`='1996-02-11' AND `title`='Senior Staff' LIMIT 1; #start 364141 end 364565 time 2019-01-23 16:23:59
DELETE FROM `employees`.`titles` WHERE `emp_no`=10007 AND `to_date` IS NULL AND `from_date`='1989-02-10' AND `title`='Staff' LIMIT 1; #start 364141 end 364565 time 2019-01-23 16:23:59
You have mail in /var/mail/root

[root@05 binlog2sql]# python binlog2sql.py --flashback  -h127.0.0.1 -P3306 -uroot -p123 -demployees -t titles --start-file=mysql-bin.000015 --start-datetime='2019-01-23 16:20:04' >tit.sql

[root@05 binlog2sql]# mysql -uroot -p123 --database employees < tit.sql 

 

(root@localhost) [employees]> select * from titles where emp_no <= 10007 ;
+--------+-----------------+------------+---------+
| emp_no | title | from_date | to_date |
+--------+-----------------+------------+---------+
| 10001 | Senior | 1986-06-26 | NULL |
| 10002 | Staff | 1996-08-03 | NULL |
| 10003 | Senior Engineer | 1995-12-03 | NULL |
| 10004 | Engineer | 1986-12-01 | NULL |
| 10004 | Senior Engineer | 1995-12-01 | NULL |
| 10005 | Senior Staff | 1996-09-12 | NULL |
| 10005 | Staff | 1989-09-12 | NULL |
| 10006 | Senior Engineer | 1990-08-05 | NULL |
| 10007 | Senior Staff | 1996-02-11 | NULL |
| 10007 | Staff | 1989-02-10 | NULL |
+--------+-----------------+------------+---------+
10 rows in set (0.01 sec

 

TIPS

  • 閃回的目標:快速篩選出真正須要回滾的數據。
  • 先根據庫、表、時間作一次過濾,再根據位置作更準確的過濾。
  • 因爲數據一直在寫入,要確保回滾sql中不包含其餘數據。可根據是不是同一事務、誤操做行數、字段值的特徵等等來幫助判斷。
  • 執行回滾sql時若有報錯,須要查實具體緣由,通常是由於對應的數據已發生變化。因爲是嚴格的行模式,只要有惟一鍵(包括主鍵)存在,就只會報某條數據不存在的錯,沒必要擔憂會更新不應操做的數據。業務若是有特殊邏輯,數據回滾可能會帶來影響。
  • 若是隻回滾某張表,而且該表有關聯表,關聯表並不會被回滾,需與業務方溝通清楚

哪些數據須要回滾,讓業務方來判斷!

 

MySQL binlog2sql的更多內容可參考:

https://github.com/danfengcao/binlog2sql/blob/master/example/mysql-flashback-priciple-and-practice.md

相關文章
相關標籤/搜索