Mysql-数据闪回工具MyFlash
前言
MyFlash 是由美团点评公司技术工程部开发维护的一个回滚DML操作的工具。
- 可以针对实例、数据库、表及指定的DML语句进行回滚
- 如果binlog日志保留,可以闪回到任意时间
限制:
-
binlog格式必须为row,且binlog_row_image=full
-
仅支持 MySQL5.6 与 MySQL5.7
-
只能回滚DML(增、删、改)
一、下载安装
$ cd /export/tmp$ wget https://github.com/Meituan-Dianping/MyFlash/archive/master.zip$ unzip master.zip$ cd MyFlash-master$ yum -y install gcc glib2-devel #配置软链接
$ ln -s /export/tmp/MyFlash-master/binary/flashback /usr/bin/flashback
二、用法
常用参数说明:
--databaseNames
指定需要回滚的数据库名。多个数据库可以用 “,” 隔开。如果不指定该参数,相当于指定了所有数据库。
--tableNames
指定需要回滚的表名。多个表可以用 “,” 隔开。如果不指定该参数,相当于指定了所有表。
--start-position
指定回滚开始的位置。如不指定,从文件的开始处回滚。请指定正确的有效的位置,否则无法回滚。
--stop-position
指定回滚结束的位置。如不指定,回滚到文件结尾。请指定正确的有效的位置,否则无法回滚。
--start-datetime
指定回滚的开始时间。注意格式必须是 %Y-%m-%d %H:%M:%S。如不指定,则不限定时间。
--stop-datetime
指定回滚的结束时间。注意格式必须是 %Y-%m-%d %H:%M:%S。如不指定,则不限定时间。
--sqlTypes
指定需要回滚的 sql 类型。目前支持的过滤类型是 INSERT, UPDATE, DELETE。多个类型可以用 “,” 隔开。
--maxSplitSize
指定解析分割后文件最大大小,单位为 M。
--binlogFileNames
指定需要回滚的 binlog 文件,如有多个,用 “,” 隔开。
--outBinlogFileNameBase
指定输出的 binlog 文件前缀,如不指定,则默认为 binlog_output_base.flashback。
--logLevel
指定输出的日志级别,可选级别有 debug, warning, error,默认级别为 error 级别。
--include-gtids
指定需要回滚的 gtid,支持 gtid 的单个和范围两种形式,如有多种形式,用 “,” 隔开。
--exclude-gtids
指定不需要回滚的 gtid,支持 gtid 的单个和范围两种形式,如有多种形式,用 “,” 隔开。
三、测试验证
mysql版本:5.7.22
# 登录mysql数据库(此处省略)# 创建库
mysql> create database myflash_test;#进入库
mysql> use myflash_test;#创建表并插入数据
mysql> CREATE TABLE test (id INT AUTO_INCREMENT PRIMARY KEY,name VARCHAR(50),age INT
);mysql> INSERT INTO test (name, age) VALUES ('John', 20);
mysql> INSERT INTO test (name, age) VALUES ('Alice', 22);
mysql> INSERT INTO test (name, age) VALUES ('Bob', 25);
mysql> INSERT INTO test (name, age) VALUES ('Ella', 18);
mysql> INSERT INTO test (name, age) VALUES ('David', 21);
模拟误操作:
# 将字段age年龄都改为0
mysql> UPDATE test SET age = 0;# 查询确认
mysql> select * from test;
+----+-------+------+
| id | name | age |
+----+-------+------+
| 1 | John | 20 |
| 2 | Alice | 22 |
| 3 | Bob | 25 |
| 4 | Ella | 18 |
| 5 | David | 21 |
+----+-------+------+
5 rows in set (0.00 sec)# 修改数据
mysql> UPDATE test SET age = 0;# 查询确认
mysql> select * from test;
+----+-------+------+
| id | name | age |
+----+-------+------+
| 1 | John | 0 |
| 2 | Alice | 0 |
| 3 | Bob | 0 |
| 4 | Ella | 0 |
| 5 | David | 0 |
+----+-------+------+
5 rows in set (0.00 sec)# 确认目前使用的binlog文件
mysql> show master status;
+------------------+-----------+--------------+------------------+-----------------------------------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+-----------+--------------+------------------+-----------------------------------------------+
| mysql-bin.000114 | 231898269 | | | 704ba2fe-d2ba-11ed-901b-fa163ef1200f:1-963042 |
+------------------+-----------+--------------+------------------+-----------------------------------------------+# 在binlog目录下过滤关于误操作的关键词
$ mysqlbinlog -vv mysql-bin.000114| less |grep -A 30 test# 解析 binlog,确认误操作的时间段
<----------------------------以下为查询到的binlog内容,做分割----------------------------->
#250521 17:03:21 server id 393307 end_log_pos 231898060 CRC32 0xa7cbc1dc Table_map: `myflash_test`.`test` mapped to number 64090
# at 231898060
#250521 17:03:21 server id 393307 end_log_pos 231898238 CRC32 0xd78ecf9a Update_rows: table id 64090 flags: STMT_END_FBINLOG '
2ZYtaBNbAAYAOwAAAMx70g0AAFr6AAAAAAEADG15Zmxhc2hfdGVzdAAEdGVzdAADAw8DApYABtzB
y6c=
2ZYtaB9bAAYAsgAAAH580g0AAFr6AAAAAAEAAgAD///4AQAAAARKb2huFAAAAPgBAAAABEpvaG4A
AAAA+AIAAAAFQWxpY2UWAAAA+AIAAAAFQWxpY2UAAAAA+AMAAAADQm9iGQAAAPgDAAAAA0JvYgAA
AAD4BAAAAARFbGxhEgAAAPgEAAAABEVsbGEAAAAA+AUAAAAFRGF2aWQVAAAA+AUAAAAFRGF2aWQA
AAAAms+O1w==
'/*!*/;
### UPDATE `myflash_test`.`test`
### WHERE
### @1=1 /* INT meta=0 nullable=0 is_null=0 */
### @2='John' /* VARSTRING(150) meta=150 nullable=1 is_null=0 */
### @3=20 /* INT meta=0 nullable=1 is_null=0 */
### SET
### @1=1 /* INT meta=0 nullable=0 is_null=0 */
### @2='John' /* VARSTRING(150) meta=150 nullable=1 is_null=0 */
### @3=0 /* INT meta=0 nullable=1 is_null=0 */
### UPDATE `myflash_test`.`test`
### WHERE
### @1=2 /* INT meta=0 nullable=0 is_null=0 */
### @2='Alice' /* VARSTRING(150) meta=150 nullable=1 is_null=0 */
### @3=22 /* INT meta=0 nullable=1 is_null=0 */
### SET
### @1=2 /* INT meta=0 nullable=0 is_null=0 */
### @2='Alice' /* VARSTRING(150) meta=150 nullable=1 is_null=0 */
### @3=0 /* INT meta=0 nullable=1 is_null=0 */
### UPDATE `myflash_test`.`test`
### WHERE
### @1=3 /* INT meta=0 nullable=0 is_null=0 */
### @2='Bob' /* VARSTRING(150) meta=150 nullable=1 is_null=0 */
### @3=25 /* INT meta=0 nullable=1 is_null=0 */
### SET
### @1=3 /* INT meta=0 nullable=0 is_null=0 */
### @2='Bob' /* VARSTRING(150) meta=150 nullable=1 is_null=0 */
### @3=0 /* INT meta=0 nullable=1 is_null=0 */
### UPDATE `myflash_test`.`test`
### WHERE
### @1=4 /* INT meta=0 nullable=0 is_null=0 */
### @2='Ella' /* VARSTRING(150) meta=150 nullable=1 is_null=0 */
### @3=18 /* INT meta=0 nullable=1 is_null=0 */
### SET
### @1=4 /* INT meta=0 nullable=0 is_null=0 */
### @2='Ella' /* VARSTRING(150) meta=150 nullable=1 is_null=0 */
### @3=0 /* INT meta=0 nullable=1 is_null=0 */
### UPDATE `myflash_test`.`test`
### WHERE
### @1=5 /* INT meta=0 nullable=0 is_null=0 */
### @2='David' /* VARSTRING(150) meta=150 nullable=1 is_null=0 */
### @3=21 /* INT meta=0 nullable=1 is_null=0 */
### SET
### @1=5 /* INT meta=0 nullable=0 is_null=0 */
### @2='David' /* VARSTRING(150) meta=150 nullable=1 is_null=0 */
### @3=0 /* INT meta=0 nullable=1 is_null=0 */
# at 231898238
#250521 17:03:21 server id 393307 end_log_pos 231898269 CRC32 0x66122cdb Xid = 76160547
COMMIT/*!*/;
SET @@SESSION.GTID_NEXT= 'AUTOMATIC' /* added by mysqlbinlog */ /*!*/;
DELIMITER ;
# End of log file
<----------------------------以上为查询到的binlog内容,做分割-----------------------------># 使用 MyFlash 工具进行回滚,进入到工具的安装目录,执行命令反向解析 binlog,指定要回滚的库、表、开始时间和结束时间,并指定反向解析的 SQL 语句类型:flashback --databaseNames="myflash_test" --tableNames="test" --start-datetime="2025-05-21 17:03:21" --stop-datetime="2025-05-21 17:03:21" --sqlTypes="UPDATE" --binlogFileNames=/export/servers/data/my3307/binlog/mysql-bin.000114 --outBinlogFileNameBase=test.sql# 恢复数据
mysqlbinlog --skip-gtids test.sql.flashback | mysql -S /export/servers/data/my3307/run/mysqld.sock -usysdba -p# 登录数据库并验证数据已正常回滚
mysql> select * from test;
+----+-------+------+
| id | name | age |
+----+-------+------+
| 1 | John | 20 |
| 2 | Alice | 22 |
| 3 | Bob | 25 |
| 4 | Ella | 18 |
| 5 | David | 21 |
+----+-------+------+
5 rows in set (0.00 sec)