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

相关文章
相关标签/搜索