背景
生产数据库执行 sql 脚本,一般会经过正规的审批流程才能运行。但有些情况是例外的,业务部门在提出一些删除数据的需求后打算撤回,或者在运营后台不小心删除了一些数据,然后找到 dba 团队协助,希望能恢复数据。
经调研,binlog2sql 是大众点评开源的一款用于解析 mysql binlog 的工具,根据不同选项,可以得到原始sql、回滚sql、去除主键的insert sql 等,适用于数据快速回滚(闪回)和主从切换后新 master 丢数据的修复工作。
目标
验证 binlog2sql 工具是否可以快速恢复数据。
步骤
准备工作
安装 binlog2sql 工具。
> git clone https://github.com/danfengcao/binlog2sql.git && cd binlog2sql # > yum install python3-pip # > whereis pip # > pip3.6 install -r requirements.txt > pip install -r requirements.txt
mysql 服务端配置以下参数,请注意,binlog2sql 仅支持 row 格式。
[mysqld] server_id = 1 log_bin = /var/log/mysql/mysql-bin.log max_binlog_size = 1g binlog_format = row binlog_row_image = full
指定执行脚本的数据库用户授权。
-- select 权限:查询 information_schema.columns -- replication slave:通过 binlog_dump 协议获取 binlog 内容 -- replication client:执行 show master status 获取 binlog 信息 grant select, replication slave, replication client on *.* to user
准备一张用户表 user,并填充 1w 条数据。
create table `user` ( `id` int(11) not null auto_increment, `name` varchar(10) default null, `gmt_create` date default null, primary key (`id`) ) engine=innodb auto_increment=1 default charset=utf8mb4 delimiter $$ create procedure insertrandomdata() begin declare i int default 1; declare randomname char(10); declare randomdate date; while i <= 10000 do -- 生成随机 name (随机字符串) set randomname = concat( char(floor(rand() * 26) + 65), char(floor(rand() * 26) + 65), char(floor(rand() * 26) + 65), char(floor(rand() * 26) + 65), char(floor(rand() * 26) + 65) ); -- 生成随机日期 (2013-11-11 起始,随机范围约为一年内) set randomdate = date_add('2023-01-01', interval floor(rand() * 365) day); -- 插入数据 insert into `user` (`name`, `gmt_create`) values (randomname, randomdate); set i = i + 1; end while; end$$ delimiter ; -- 调用存储过程 call insertrandomdata();
查看大于 11 月份的数据总数,共 363 条。
mysql > select count(*) from user where gmt_create > '2023-11-01 00:00:00'; +----------+ | count(*) | +----------+ | 363 | +----------+
模拟误删除,假设在 15:30 左右删除了 11 月份之后的数据。
mysql > delete from user where gmt_create > '2023-11-01 00:00:00';
恢复数据
查看主库 binlog 状态,最新的文件为 mysql-bin.000003。
-- 低版本使用 show master status; mysql > show binary logs; +------------------+-----------+-----------+ | log_name | file_size | encrypted | +------------------+-----------+-----------+ | mysql-bin.000001 | 1871 | no | | mysql-bin.000002 | 181 | no | | mysql-bin.000003 | 917878 | no | +------------------+-----------+-----------+ 3 rows in set (0.04 sec)
筛选出需要回滚的sql,误操作人一般知道大致的误操作时间,我们首先根据时间做一次过滤。
shell> python binlog2sql/binlog2sql.py -h地址 -p端口 -u用户 -p'密码' -d库民 -t表名 --start-file='mysql-bin.000003' --start-datetime='2023-11-02 15:00:00' --stop-datetime='2023-11-02 16:00:00' > /tmp/raw.sql
raw.sql输出:
delete from `test`.`user` where `gmt_create`='2023-11-01 00:00:00' and `id`=1351 and `name`='tpudj' limit 1; #start 105311 end 262311 time 2023-11-02 15:31:10
delete from `test`.`user` where `gmt_create`='2023-11-01 00:00:00' and `id`=1352 and `name`='ykiis' limit 1; #start 105311 end 262311 time 2023-11-02 15:31:10
...
delete from `test`.`user` where `gmt_create`='2023-12-31 00:00:00' and `id`=1714 and `name`='shkbc' limit 1; #start 105311 end 265754 time 2023-11-02 15:31:10
根据 raw.sql 的位置信息,可以判断误操作的 sql 来自同一个事务,准确位置在 105311-265754 之间,根据位置过滤,使用 -b 选项生成回滚 sql。
shell> python binlog2sql/binlog2sql.py -h地址 -p端口 -u用户 -p'密码' -d库民 -t表名 --start-file='mysql-bin.000003' --start-position=105311 --stop-position=265754 -b > /tmp/rollback.sql
rollback.sql输出:
insert into `test`.`user`(`gmt_create`, `id`, `name`) values ('2023-11-01 00:00:00', 1351, 'tpudj'); #start 105311 end 262311 time 2023-11-02 15:31:10
insert into `test`.`user`(`gmt_create`, `id`, `name`) values ('2023-11-01 00:00:00', 1352, 'ykiis'); #start 105311 end 262311 time 2023-11-02 15:31:10
...
insert into `test`.`user`(`gmt_create`, `id`, `name`) values ('2023-12-31 00:00:00', 1714, 'shkbc'); #start 105311 end 265754 time 2023-11-02 15:31:10
结果验证
确认回滚 sql 总行数是否对应误删除的 363 条。
shell> wc -l /tmp/rollback.sql
363 /tmp/rollback.sql
与业务方确认回滚 sql 没问题,执行回滚语句。登录 mysql,确认回滚成功。
shell> mysql -h地址 -p端口 -u用户 -p'密码' < /tmp/rollback.sql mysql> select count(*) from user where gmt_create > '2023-11-01 00:00:00'; +----------+ | count(*) | +----------+ | 363 | +----------+
结论
binlog2sql 适用于在线恢复误操作的数据,但不适用于以下情况:
- 数据恢复建议控制在 50w 以内,数据量越大,逆向生成的语句越多,超过这个数值,恢复时间可能会超过 15 分钟。
- 不支持 ddl 恢复操作。因为即使在 row 模式下,binlog对于 ddl 操作不会记录每行数据的变化。要实现 ddl 快速回滚,必须修改 mysql 源码,使得在执行 ddl 前先备份老数据。阿里林晓斌团队提交了 patch 给 mysql 官方,相关实现方案可以查阅 mysql闪回方案讨论及实现。
- 根据官方说法,在线召回数据推荐使用 binlog2sql 工具,离线解析使用 mysqlbinlog 工具,mysql 闪回特性最早由阿里彭立勋开发。
到此这篇关于mysql使用binlog2sql工具实现在线恢复数据功能的文章就介绍到这了,更多相关mysql binlog2sql恢复数据内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论