巫雪艷 发表于 2025-7-21 08:17:37

误操作后快速恢复数据 binlog 解析为反向 SQL

误操作后快速恢复数据 binlog 解析为反向 SQL

1.前言

本文将介绍使用 reverse_sql 工具将 GreatSQL 数据库的 binlog 解析为反向 SQL 语句。模拟误操作后,恢复数据。该工具可以帮助客户在发生事故时快速恢复数据,避免进一步的损失。使用 reverse_sql 工具非常简单,客户只需要指定肇事时间和表名即可。该工具会根据指定的时间点,在数据库中查找并还原该表在该时间点之前的数据状态。这样客户就能轻松地实现数据恢复,防止因意外操作或其他问题导致的数据丢失。
2.reverse_sql 工具简介

reverse_sql 是一个用于解析和转换二进制日志(binlog)的工具。它可以将二进制日志文件中记录的数据库更改操作(如插入、更新、删除)转换为反向的 SQL 语句,以便进行数据恢复。其运行模式需二进制日志设置为 ROW 格式。
下载地址:
https://github.com/hcymysql/reverse_sql3.工具特点

该工具的主要功能和特点包括(针对 GreatSQL):
1、解析二进制日志:reverse_sql 能够解析 GreatSQL 的二进制日志文件,并还原出其中的 SQL 语句。
2、生成可读的 SQL:生成原始 SQL 和反向 SQL。
3、支持过滤和筛选:可以根据时间范围、表、DML操作等条件来过滤出具体的误操作 SQL 语句。
4、支持多线程并发解析 binlog 事件。
注意:reverse_sql 只是将二进制日志还原为 SQL 语句,而不会执行这些 SQL 语句来修改数据库。
4.使用前检查

4.1 GreatSQL 环境检查

首先需要确认二进制日志设置是 ROW 格式以及 row_image 是 FULL。
工具运行时,首先会进行GreatSQL的环境检测(if binlog_format != 'ROW' and binlog_row_image != 'FULL'),如果不同时满足这两个条件,程序直接退出。
greatsql> SHOW VARIABLES LIKE '%binlog%';
+------------------------------------------------+----------------------+
| Variable_name                                  | Value                |
+------------------------------------------------+----------------------+
| binlog_cache_size                              | 32768                |
| binlog_checksum                              | CRC32                |
| binlog_ddl_skip_rewrite                        | OFF                  |
| binlog_direct_non_transactional_updates      | OFF                  |
| binlog_encryption                              | OFF                  |
| binlog_error_action                            | ABORT_SERVER         |
| binlog_expire_logs_auto_purge                  | ON                   |
| binlog_expire_logs_seconds                     | 2592000            |
| binlog_format                                  | ROW                  |
| binlog_group_commit_sync_delay               | 0                  |
| binlog_group_commit_sync_no_delay_count      | 0                  |
| binlog_gtid_simple_recovery                  | ON                   |
| binlog_max_flush_queue_time                  | 0                  |
| binlog_order_commits                           | ON                   |
| binlog_rotate_encryption_master_key_at_startup | OFF                  |
| binlog_row_event_max_size                      | 8192               |
| binlog_row_image                               | FULL               |
| binlog_row_metadata                            | MINIMAL            |
| binlog_row_value_options                     |                      |
| binlog_rows_query_log_events                   | OFF                  |
| binlog_skip_flush_commands                     | OFF                  |
| binlog_space_limit                           | 0                  |
| binlog_stmt_cache_size                         | 32768                |
| binlog_transaction_compression               | OFF                  |
| binlog_transaction_compression_level_zstd      | 3                  |
| binlog_transaction_dependency_history_size   | 25000                |
| binlog_transaction_dependency_tracking         | WRITESET             |
| have_backup_safe_binlog_info                   | YES                  |
| innodb_api_enable_binlog                     | OFF                  |
| log_statements_unsafe_for_binlog               | ON                   |
| max_binlog_cache_size                        | 4294967296         |
| max_binlog_size                              | 1073741824         |
| max_binlog_stmt_cache_size                     | 18446744073709547520 |
| rpl_read_binlog_speed_limit                  | 0                  |
| sync_binlog                                    | 1                  |
+------------------------------------------------+----------------------+
35 rows in set (0.01 sec)4.2 参数binlog_format解析

GreatSQL 支持三种二进制日志格式:

[*]STATEMENT (基于语句的复制 - SBR)

[*]记录实际执行的 SQL 语句
[*]优点:日志文件较小,记录的是语句而非数据变更
[*]缺点:某些非确定性函数(如 NOW(), UUID(), RAND())可能导致主从数据不一致

[*]ROW (基于行的复制 - RBR) GreatSQL 默认使用 ROW 作为二进制日志格式。

[*]记录每行数据的变化情况
[*]优点:最安全的复制方式,能准确复制数据变更
[*]缺点:日志文件较大,特别是批量操作时

[*]MIXED (混合模式)

[*]默认使用 STATEMENT 格式,但在某些情况下自动切换到 ROW 格式

4.3 参数binlog_row_image解析

binlog_row_image 是 GreatSQL 中控制二进制日志记录的参数,它决定了在使用基于行的复制时,二进制日志中的行镜像如何被记录。
参数选项
binlog_row_image 参数有三个可选值:

[*]FULL:记录每一行的变更,包括所有列的前后镜像。--生产环境建议设置为 FULL 最佳。
[*]MINIMAL:binlog日志的前镜像只记录唯一识别列(唯一索引列、主键列),后镜像只记录修改列。只记录必要的列,即在更新操作中只记录变更的列和用于识别行的最小列集。
[*]NOBLOB:类似于 FULL,但不包括 BLOB 和 TEXT 类型的列,除非它们是必要的。
使用场景

[*]当设置为 FULL 时,GreatSQL 记录所有列的变更,这可以确保数据的完整性,但可能会导致二进制日志的大小增加。
[*]设置为 MINIMAL 可以减少日志的大小,因为它只记录变更的列和必要的列,这对于减少磁盘 I/O 和网络传输是有益的。
[*]NOBLOB 选项适用于那些不希望记录大型 BLOB 或 TEXT 数据的场景,但仍然需要记录其他类型列的变更。
5.工具与数据库用户赋权

5.1 工具赋予执行权限

在服务器上解压后,授权:
$ ll rev*
-rwxr-xr-x 1 root root 50780824 Apr 28 14:23 reverse_sql_mysql8
$ chmod 755 reverse_sql_mysql8 5.2 数据库用户赋权(最小化用户权限)

greatsql> CREATE USER 'test'@'%' identified BY 'test';
Query OK, 0 rows affected (0.15 sec)

greatsql> GRANT REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO `test`@`%`;
Query OK, 0 rows affected (0.01 sec)

greatsql> GRANT SELECT ON `test`.* TO `test`@`%`;
Query OK, 0 rows affected (0.01 sec)

greatsql> SHOW grants FOR test;
+------------------------------------------------------------------+
| Grants FOR test@%                                                |
+------------------------------------------------------------------+
| GRANT REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO `test`@`%` |
| GRANT SELECT ON `test`.* TO `test`@`%`                           |
+------------------------------------------------------------------+
2 rows in set (0.00 sec)5.3 查看使用帮助信息

$ ./reverse_sql_mysql8 --help
usage: reverse_sql_mysql8 [-h] [-ot ONLY_TABLES ] [-op ONLY_OPERATION] -H MYSQL_HOST -P MYSQL_PORT -u MYSQL_USER -p MYSQL_PASSWD -d MYSQL_DATABASE [-c MYSQL_CHARSET] --binlog-file BINLOG_FILE
                        [--binlog-pos BINLOG_POS] --start-time ST --end-time ET [--max-workers MAX_WORKERS] [--print] [--replace] [-v]

Binlog数据恢复,生成反向SQL语句。

options:
-h, --help            show this help message and exit
-ot ONLY_TABLES , --only-tables ONLY_TABLES
                        设置要恢复的表,多张表用,逗号分隔
-op ONLY_OPERATION, --only-operation ONLY_OPERATION
                        设置误操作时的命令(insert/update/delete)
-H MYSQL_HOST, --mysql-host MYSQL_HOST
                        MySQL主机名
-P MYSQL_PORT, --mysql-port MYSQL_PORT
                        MySQL端口号
-u MYSQL_USER, --mysql-user MYSQL_USER
                        MySQL用户名
-p MYSQL_PASSWD, --mysql-passwd MYSQL_PASSWD
                        MySQL密码
-d MYSQL_DATABASE, --mysql-database MYSQL_DATABASE
                        MySQL数据库名
-c MYSQL_CHARSET, --mysql-charset MYSQL_CHARSET
                        MySQL字符集,默认utf8
--binlog-file BINLOG_FILE
                        Binlog文件
--binlog-pos BINLOG_POS
                        Binlog位置,默认4
--start-time ST       起始时间
--end-time ET         结束时间
--max-workers MAX_WORKERS
                        线程数,默认4(并发越高,锁的开销就越大,适当调整并发数)
--print               将解析后的SQL输出到终端
--replace             将update转换为replace操作
-v, --version         show program's version number and exit

Example usage:
    shell> ./reverse_sql -ot table1 -op delete -H 192.168.198.239 -P 3336 -u admin -p hechunyang -d hcy \
            --binlog-file mysql-bin.000124 --start-time "2023-07-06 10:00:00" --end-time "2023-07-06 22:00:00" 6.案例演示

6.1 创建测试数据,模拟误更新

greatsql> CREATE TABLE t1 (
         id INT AUTO_INCREMENT PRIMARY KEY,
         name VARCHAR(50),
         age INT,
         email VARCHAR(100),
         gender ENUM('Male', 'Female', 'Other'),
         salary DECIMAL(10,2),
         join_date DATE,
         is_active BOOLEAN
   );
Query OK, 0 rows affected (0.04 sec)

greatsql> INSERT INTO t1 (name, age, email, gender, salary, join_date, is_active) VALUES
   ('张三', 28, 'zhangsan@example.com', 'Male', 8500.00, '2020-05-15', TRUE),
   ('李四', 32, 'lisi@example.com', 'Male', 9200.50, '2019-08-22', TRUE),
   ('王五', 25, 'wangwu@example.com', 'Male', 7800.00, '2021-03-10', TRUE),
   ('赵六', 29, 'zhaoliu@example.com', 'Female', 8800.75, '2020-11-05', TRUE),
   ('肖七', 35, 'xiaoqi@example.com', 'Female', 10500.00, '2018-06-18', FALSE),
   ('孙八', 27, 'sunba@example.com', 'Male', 8100.00, '2021-01-30', TRUE),
   ('周九', 31, 'zhoujiu@example.com', 'Other', 9500.25, '2019-09-12', TRUE),
   ('吴十', 24, 'wushi@example.com', 'Female', 7600.50, '2022-02-14', TRUE),
   ('郑十一', 30, 'zhengshiyi@example.com', 'Male', 8900.00, '2020-07-25', FALSE),
   ('王十二', 33, 'wangshier@example.com', 'Female', 10000.00, '2019-04-08', TRUE);
Query OK, 10 rows affected (0.01 sec)
Records: 10Duplicates: 0Warnings: 0

greatsql> SELECT * FROM t1;
+----+-----------+------+------------------------+--------+----------+------------+-----------+
| id | name      | age| email                  | gender | salary   | join_date| is_active |
+----+-----------+------+------------------------+--------+----------+------------+-----------+
|1 | 张三      |   28 | zhangsan@example.com   | Male   |8500.00 | 2020-05-15 |         1 |
|2 | 李四      |   32 | lisi@example.com       | Male   |9200.50 | 2019-08-22 |         1 |
|3 | 王五      |   25 | wangwu@example.com   | Male   |7800.00 | 2021-03-10 |         1 |
|4 | 赵六      |   29 | zhaoliu@example.com    | Female |8800.75 | 2020-11-05 |         1 |
|5 | 肖七      |   35 | xiaoqi@example.com   | Female | 10500.00 | 2018-06-18 |         0 |
|6 | 孙八      |   27 | sunba@example.com      | Male   |8100.00 | 2021-01-30 |         1 |
|7 | 周九      |   31 | zhoujiu@example.com    | Other|9500.25 | 2019-09-12 |         1 |
|8 | 吴十      |   24 | wushi@example.com      | Female |7600.50 | 2022-02-14 |         1 |
|9 | 郑十一    |   30 | zhengshiyi@example.com | Male   |8900.00 | 2020-07-25 |         0 |
| 10 | 王十二    |   33 | wangshier@example.com| Female | 10000.00 | 2019-04-08 |         1 |
+----+-----------+------+------------------------+--------+----------+------------+-----------+
10 rows in set (0.00 sec)

greatsql> UPDATE t1   
   SET salary = 9800.00, is_active = TRUE   
   WHERE id = 5;
Query OK, 1 row affected (0.01 sec)
Rows matched: 1Changed: 1Warnings: 0

greatsql> SELECT * FROM t1;
+----+-----------+------+------------------------+--------+----------+------------+-----------+
| id | name      | age| email                  | gender | salary   | join_date| is_active |
+----+-----------+------+------------------------+--------+----------+------------+-----------+
|1 | 张三      |   28 | zhangsan@example.com   | Male   |8500.00 | 2020-05-15 |         1 |
|2 | 李四      |   32 | lisi@example.com       | Male   |9200.50 | 2019-08-22 |         1 |
|3 | 王五      |   25 | wangwu@example.com   | Male   |7800.00 | 2021-03-10 |         1 |
|4 | 赵六      |   29 | zhaoliu@example.com    | Female |8800.75 | 2020-11-05 |         1 |
|5 | 肖七      |   35 | xiaoqi@example.com   | Female |9800.00 | 2018-06-18 |         1 |
|6 | 孙八      |   27 | sunba@example.com      | Male   |8100.00 | 2021-01-30 |         1 |
|7 | 周九      |   31 | zhoujiu@example.com    | Other|9500.25 | 2019-09-12 |         1 |
|8 | 吴十      |   24 | wushi@example.com      | Female |7600.50 | 2022-02-14 |         1 |
|9 | 郑十一    |   30 | zhengshiyi@example.com | Male   |8900.00 | 2020-07-25 |         0 |
| 10 | 王十二    |   33 | wangshier@example.com| Female | 10000.00 | 2019-04-08 |         1 |
+----+-----------+------+------------------------+--------+----------+------------+-----------+
10 rows in set (0.00 sec)6.2 解析binlog

查看 binlog 当前信息
greatsql> SHOW MASTER STATUS \G
*************************** 1. row ***************************
             File: binlog.000002
         Position: 2918
   Binlog_Do_DB:
Binlog_Ignore_DB:
Executed_Gtid_Set: 2a3248f7-e762-11ef-ae09-00163e11ac96:1,
3837053e-e762-11ef-ade8-00163e2cc6be:1-4008,
615fadb3-234d-11f0-ab29-00163e2cc6be:1-5,
aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaa1:1-1067166
1 row in set (0.00 sec)执行解析命令
./reverse_sql_mysql8 -u 'test' -p 'test' -H 172.17.136.70 -P 3301 -d test_111 -ot t1 --binlog-file /greatsql/dbdata/3301/log/binlog.000009 --start-time "2025-05-22 16:30:00" --end-time "2025-05-22 16:40:00" Processing binlogevents: 100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 1/1 [00:00
页: [1]
查看完整版本: 误操作后快速恢复数据 binlog 解析为反向 SQL