MySQL使用binlog2sql工具实现在线恢复数据功能

 更新时间:2025年03月21日 11:05:51   作者:梦想歌  
binlog2sql 是大众点评开源的一款用于解析 MySQL binlog 的工具,根据不同选项,可以得到原始SQL、回滚SQL等,下面我们就来看看如何使用binlog2sql实现在线恢复数据功能吧

背景

生产数据库执行 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恢复数据内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • SQL删除重复数据的实例教程

    SQL删除重复数据的实例教程

    在使用SQL提数的时候,常会遇到表内有重复值的时候,下面这篇文章主要给大家介绍了关于SQL删除重复数据的相关资料,文中通过示例代码介绍的非常详细,需要的朋友可以参考下
    2022-07-07
  • MySQL 审计级别配置实现步骤

    MySQL 审计级别配置实现步骤

    本文主要介绍了MySQL 审计级别配置,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2026-03-03
  • Mysql实现模糊查询的两种方式(like子句 、正则表达式)

    Mysql实现模糊查询的两种方式(like子句 、正则表达式)

    通配符是一种特殊语句,主要用来模糊查询,下面这篇文章主要给大家介绍了关于给Mysql实现模糊查询的两种方式,分别是like子句 、正则表达式,需要的朋友可以参考下
    2022-09-09
  • 碰到MySQL无法启动1067错误问题解决方法

    碰到MySQL无法启动1067错误问题解决方法

    创建primay key过程中发生了断电,当电脑再次启动时候,发现mysql 服务无法启动,使用 net start 提示 1067错误;后来只能通过手工删除数据文件,日志文件,再启动服务,然后导入数据来完成
    2013-01-01
  • Mysql字段为null的加减乘除运算方式

    Mysql字段为null的加减乘除运算方式

    这篇文章主要介绍了Mysql字段为null的加减乘除运算方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-09-09
  • MySQL最常问的十道面试题(2023年最新详解版)

    MySQL最常问的十道面试题(2023年最新详解版)

    MySQL是一个关系型数据库管理系统,这是学习Java必学的知识点,也是面试java岗位必考的题目,所以大家要有所重视,这篇文章主要给大家介绍了关于MySQL最常问的十道面试题,是2023年最新详细整理的,需要的朋友可以参考下
    2023-10-10
  • MySQL实现免密登录的三种配置方式

    MySQL实现免密登录的三种配置方式

    我们登录MySQL的时候有时候会忘记root密码,这时我们需要免密登录,所以这篇文章给大家介绍了MySQL免密登录的三种方式,文章通过是示例代码给出了详细的配置方案,需要的朋友可以参考下
    2024-03-03
  • MySQL数据库中如何查询近一年的数据

    MySQL数据库中如何查询近一年的数据

    最近碰到一个需求是统计某张表的数据,统计时间维度为近一年,下面这篇文章主要给大家介绍了关于MySQL数据库中如何查询近一年的数据的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参考下
    2024-07-07
  • CentOs7安装部署Sonar环境的详细过程(JDK1.8+MySql5.7+sonarqube7.8)

    CentOs7安装部署Sonar环境的详细过程(JDK1.8+MySql5.7+sonarqube7.8)

    这篇文章主要介绍了CentOs7安装部署Sonar环境(JDK1.8+MySql5.7+sonarqube7.8),本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-06-06
  • windows server2014 安装 Mysql Applying Security出错的完美解决方法

    windows server2014 安装 Mysql Applying Security出错的完美解决方法

    这篇文章给大家介绍了windows server2014 安装 Mysql Applying Security出错的完美解决方法,造成这种问题的主要原因是因为安装一遍之后没有卸载干净,要解决这个问题需要注意以下几点,具体解决方法,大家参考下本文
    2017-07-07

最新评论