Mysql binlog数据恢复(使用mysqlbinlog_flashback逆向生成SQL语句)

这里有个建议,由于mysql默认是不开启binlog的,如果是线上数据库,或者比较重要的数据库,建议还是将binlog开启,而且格式设为ROW类型的。
防止出现问题时,也有恢复的退路,养成定期备份数据库的习惯。
通过命令,查看是否开启了binlog。

show variables like 'log_%';

在这里插入图片描述
数据恢复方法:
1.用最近的全量备份,然后在加上全量备份时间点后的binlog日志,然后先还原全量备份,在通过命令把binlog执行掉,这样数据就能还原了,这种方法,不限binlog的日志格式,ROW或者MIXED都行。但是随着业务量增大,可能单次还原数据库和执行binlog需要很长时间。
2.只用binlog日志,将binlog日志解析出来,生成反向原始sql,然后执行还原数据,这种方式binlog日志格式需要是ROW

下面开始模拟,数据修改出错,或者数据误删进行数据恢复,基于第二种方法。

目录

        • 1.环境模拟
        • 2.往表中插入数据
        • 3.模拟线上更改1个表数据,删除1个数据,并查看更改日志
        • 4.还原数据

1.环境模拟

先建1个库,然后建1个表,
在这里插入图片描述
建表语句如下

CREATE TABLE `table_test1` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(50) DEFAULT '' COMMENT '姓名',
  `sex` int(1) DEFAULT '1' COMMENT '性别',
  `age` int(3) DEFAULT '18' COMMENT '年龄',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

2.往表中插入数据

insert into binlog_test1.table_test1 VALUES(1,'张三1',1,19);
insert into binlog_test1.table_test1 VALUES(2,'李四1',1,19);
insert into binlog_test1.table_test1 VALUES(3,'王五1',1,19);

数据插入进去后,我们通过mysqlbinlog 命令看看binlog日志内容

mysqlbinlog --no-defaults E:\......\mysql-5.6.35-winx64\logs\mysql-bin.000001

Mysql binlog数据恢复(使用mysqlbinlog_flashback逆向生成SQL语句)_第1张图片
可以看到我们新增的数据都在日志中,随便抓一个片段,来解释下日志内容。

/*!*/;
# at 483
#210222 10:56:11 server id 1  end_log_pos 563 CRC32 0xc52b14e5  Query   thread_id=1     exec_time=0     error_code=0
SET TIMESTAMP=1613962571/*!*/;
BEGIN
/*!*/;
# at 563
#210222 10:56:11 server id 1  end_log_pos 630 CRC32 0xbf00ad20  Table_map: `binlog_test1`.`table_test1` mapped to number 70
# at 630
#210222 10:56:11 server id 1  end_log_pos 686 CRC32 0x4473d9af  Write_rows: table id 70 flags: STMT_END_F

BINLOG '
Sx0zYBMBAAAAQwAAAHYCAAAAAEYAAAAAAAEADGJpbmxvZ190ZXN0MQALdGFibGVfdGVzdDEABAMP
AwMClgAOIK0Avw==
Sx0zYB4BAAAAOAAAAK4CAAAAAEYAAAAAAAEAAgAE//ABAAAAB+W8oOS4iTEBAAAAEwAAAK/Zc0Q=
'/*!*/;
# at 686
#210222 10:56:11 server id 1  end_log_pos 717 CRC32 0x115267fc  Xid = 21
COMMIT/*!*/;
# at 717
#210222 10:56:11 server id 1  end_log_pos 797 CRC32 0xb521ac31  Query   thread_id=1     exec_time=0     error_code=0
SET TIMESTAMP=1613962571/*!*/;
BEGIN

#at 483:事件的起点
#210222 10:56:11:事件记录的时间
server id 1:服务器标识,默认1
end_log_pos 563:事件结束的位置,第366字节
CRC320xc52b14e5:checksum主从复制校验值
Xid = 21:事务id

3.模拟线上更改1个表数据,删除1个数据,并查看更改日志

先将 table_test1 表中,id为3的数据更改下

update table_test1 set sex=0 where id=3;
delete from table_test1 where id=2;

在通过命令看下日志
Mysql binlog数据恢复(使用mysqlbinlog_flashback逆向生成SQL语句)_第2张图片
可以看到更改的数据在日志中,且是有库和表的信息的,说明不管多少个库和表,binlog是互不影响的,都是具体到哪个库里的哪个表,
这样后面还原数据的时候就可以指定库和表,防止数据量太大。
还可以用

show binlog events in "mysql-bin.000001"

这个命令查看在这里插入图片描述

4.还原数据

还原数据之前可以先用命令查询下当前binlog的position并刷新下日志,这样当前需要还原的日志里面就不会有新数据进去了,会重新生成一个日志文件,这个步骤看需要。主要就是防止数据过多影响恢复。

#查询position
show master status
#刷新日志,可以不刷新,看需求
flush logs

先将binlog日志导出,

mysqlbinlog --no-defaults -v --base64-output=decode-rows --start-position=1265 --stop-position=1675 --database=binlog_test1 E:\......\mysql-5.6.35-winx64\logs\mysql-bin.000001 > E:\......\mysql-5.6.35-winx64\logs\data.sql

参数说明:

--no-defaults :不要读任何选项文件,不加这个命令会报错
--start-position= :起始pos点,例如:--start-position=110
--stop-position= :结束pos点,例如:--stop-position=200
--start-datetime= :起始时间,例如:--start-datetime="2020-07-18 19:00:00"
--stop-datetime= :截至时间,例如:--stop-datetime="2020-07-18 21:00:00"
--database= :指定哪个库,例如:-database=binlog_test1
-v :生成带注释的sql语句(这是重点,反向还原需要看这个sql)
-v -v:生成列的的描述信息备注等
--base64-output=decode-rows :binlog部分是否显示出来的,decode-rows表示不显示binglog部分

文件导出后,我们再看看文件内容是什么
Mysql binlog数据恢复(使用mysqlbinlog_flashback逆向生成SQL语句)_第3张图片
能看到当时执行sql的完整sql,包括这条数据修改之前的数据,然后我们就可以手动更改还原数据。当然如果数据是批量更改的,且整个binlog中有很多日志,那么就需要过滤条件找到需要还原的数据日志,然后再通过工具,将日志批量转换成反向sql执行。

这里推荐一个逆向工具mysqlbinlog_flashback,
源码地址:https://github.com/58daojia-dba/mysqlbinlog_flashback
使用python实现的,环境python2.6,我试的时候用的2.7也没问题,然后需要装包,特别是pymysql
Mysql binlog数据恢复(使用mysqlbinlog_flashback逆向生成SQL语句)_第4张图片
下载完源码后需要改2个地方,这是目前知道有问题的地方。

第一个是row_event.py,把charset_to_encoding注释掉,发现读取的时候少了编码也没啥问题,如果不注释掉会报错提示找不到,也不知道为啥这个版本的pymysql没有charset_to_encoding
在这里插入图片描述Mysql binlog数据恢复(使用mysqlbinlog_flashback逆向生成SQL语句)_第5张图片
第二个可能是作者的一个bug
Mysql binlog数据恢复(使用mysqlbinlog_flashback逆向生成SQL语句)_第6张图片
这里判断版本大小的时候,如果pymysql的版本是 0.5.1 这样的是没问题的。但是如果版本是 0.10.1这样的,这个判断就是不对的。因为不知道这种判断存在多少,所以最粗暴的方式就是直接去改下pymysql的版本。
Mysql binlog数据恢复(使用mysqlbinlog_flashback逆向生成SQL语句)_第7张图片通过跟踪代码找到版本修改的地方,改成1.10.1,这样判断就ok了。
Mysql binlog数据恢复(使用mysqlbinlog_flashback逆向生成SQL语句)_第8张图片
然后可以通过 Pycharm来运行项目,这种就可以调试代码,假如出问题可以找下原因,或者直接通过cmd来运行。

python mysqlbinlog_back.py --help

可以看看有哪些命令,顺便看看想想是否能正常运行,具体的可以看README.md,有详细介绍。
Mysql binlog数据恢复(使用mysqlbinlog_flashback逆向生成SQL语句)_第9张图片
然后就是最重要的逆向sql生成命令了,

--host="127.0.0.1" --port=3306 --username="root" --password="**********" --schema="数据库名称" --tables="表名称" -S "需要生成的binlog文件" -L "从哪个position开始"
--host="127.0.0.1" --port=3306 --username="root" --password="abcdefg" --schema="test" --tables="table_test" -S "mysql-bin.000001" -L "4"

这里有几个注意点,首先第一个正常情况下,如果要还原数据,我们是不敢直接去连真实数据库去操作的,那么肯定要把binlog拷到本地来,在本地还原好数据后在同步到真实环境。
首先把真实环境的binlog拷到本地的binlog目录,binlog可能是mysql-bin.009999这样的。本地可能只到mysql-bin.000005这样的。如果直接在命令里面去读mysql-bin.009999,它会报错的。
这里可以根据

SHOW BINARY LOGS;

查下本地数据库的binlog列表,然后将本地的binlog备份下,然后把mysql-bin.009999重命令下就可以了,比如将mysql-bin.000001备份下然后删除,在将mysql-bin.009999重命名为mysql-bin.000001,这是第一个细节问题。

第二个如果不是直连真实环境,那么本地新建的数据库名称以及表名需要跟真实环境的保持一致,因为binlog里面是记录这些的,扫描的时候是根据这些进行匹配的。比如真实环境是test库,table_test表,那么本地还原环境也要这样。有这个库和这个表,因为需要根据表信息去生成字段,命令中schema和tables就是本地环境的库和表

--schema="test" --tables="table_test"

执行完命令后会在mysqlbinlog_flashback-master\log地址下生成flashback_binlog_为前缀的sql文件,打开文件可以看到里面的逆向sql。
Mysql binlog数据恢复(使用mysqlbinlog_flashback逆向生成SQL语句)_第10张图片
可以看到我一开始是新增3条数据,这里逆向生成3条删除数据,之前执行的命令

update table_test1 set sex=0 where id=3;
delete from table_test1 where id=2;

逆向生成一个update和insert语句

你可能感兴趣的:(Mysql,mysql,binlog,python,数据还原)