binlog2sql闪回

概述

在生产环境中经常会遇到误删除、改错数据的情况,现在介绍一款很方便、又省时的MySQL闪回工具binlog2sql,它可以实现数据的快速回滚,从binlog中提取SQL,并能生成回滚SQL语句。binlog以event作为单位记录数据库变更的数据信息,闪回就是可以重现这些变化数据信息之前的操作。也就是说,对于insert操作,会生成delete吾句,反之delete操作会生成insert吾句。对于update操作,也会生成相反的update语句。这款工具只能在binlog格式为row模式下才能使用。

 

安装必需的工具包

安装准备各种依赖的工具包

python-pip PyMYSQL python-mysql-replication wheel argparse

tar -xzf pip-9.0.1.tar.gz 
cd pip-9.0.1
python setup.py install

tar -xzf PyMySQL-0.7.11.tar.gz
cd PyMySQL-0.7.11
python setup.py install

tar -xzf mysql-replication-0.13.tar.gz
cd mysql-replication-0.13
python setup.py install

tar -xzf wheel-0.29.0.tar.gz
cd wheel-0.29.0
python setup.py install

tar -xzf argparse-1.4.0.tar.gz
cd argparse-1.4.0

 

安装binlog2sql工具

binlog2sql闪回工具下载地址:
https://github.com/danfengcao/binlog2sql

安装binlog2sql工具:
unzip binlog2sql-master.zip
cd binlog2sql-master
pip install -r requirements.txt

 

查看binlog2sql命令解释

python binlog2sql.py --help

可通过python binlog2sql.py -help命令查看参数的使用方式。 
-B,--flashback:生成回滚语句。
--start-file:需要解析的binlog文件。
--start-position:解析 binlog 的起始位置。
--stop-position:解析 binlog 的结束位置。
--start-datetime:从哪个时间点的binlog开始解析,格式必须为datetime。 
--stop-datetime:到哪个时间点的binlog停止解析,格式必须为datetime。 
-d,--databases:只输出目标 db 的 SQL。
-t,--tables:只输出目标 tables 的 SQL。

binlog2sql的注意事项: 
(1)    要保证MySQL服务是开启的,离线无法进行分析binlog。
(2)    binlog_format 必须是 row 格式。
(3)    DDL语句无法做到闪回,只能解析DML语句。

 

闪回测试步骤

(1)    创建用户,用于闪回

grant select,replication slave,replication client on *.* to 'flashback'@'%' identified by 'XXXXX';
flush privileges;

(2)    创建测试表并准备数据

use test;

CREATE TABLE TEST_FLASHBACK
(EMPNO INT(10),
    ENAME VARCHAR(10),
    JOB VARCHAR(9),
    MGR INT(10),
    HIREDATE DATETIME,
    SAL INT(10),
    COMM INT(10),
    DEPTNO INT(10));
 
INSERT INTO TEST_FLASHBACK VALUES (7369,'SMITH','CLERK',7902,'1980-12-17',800,NULL,20);
INSERT INTO TEST_FLASHBACK VALUES (7499,'ALLEN','SALESMAN',7698,'1981-02-20',1600,300,30);
INSERT INTO TEST_FLASHBACK VALUES (7521,'WARD','SALESMAN',7698,'1981-02-22',1250,500,30);

(3)    删除数据

delete from TEST_FLASHBACK;

(4)    闪回数据

show master status;
python binlog2sql.py -h192.168.0.13 -P3306 -uflashback -pXXXXX -dtest -tTEST_FLASHBACK --start-file='mysql-bin.000005' --start-datetime='2020-02-22 15:40:00' --stop-datetime='2020-02-22 15:50:00'
python binlog2sql.py -h192.168.0.13 -P3306 -uflashback -pXXXXX -dtest -tTEST_FLASHBACK --start-file='mysql-bin.000005' --start-position=1845 --stop-position=2201 -B > TEST_FLASHBACK_ROLLBACK.sql

闪回测试记录

[root@source mysql]# mysql -p

root@db 15:40:  [(none)]> grant select,replication slave,replication client on *.* to 'flashback'@'%' identified by 'XXXXX';
Query OK, 0 rows affected, 1 warning (0.01 sec)

root@db 15:42:  [(none)]> flush privileges;
Query OK, 0 rows affected (0.02 sec)

root@db 15:42:  [(none)]> show master status;
+------------------+----------+--------------+------------------+-------------------+
| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------+-------------------+
| mysql-bin.000005 |      622 |              |                  |                   |
+------------------+----------+--------------+------------------+-------------------+
1 row in set (0.00 sec)
root@db 15:42:  [(none)]> use test;
Database changed

root@db 15:43:  [test]> show tables;
+----------------+
| Tables_in_test |
+----------------+
| BONUS          |
| DEPT           |
| EMP            |
| SALGRADE       |
+----------------+
4 rows in set (0.00 sec)
root@db 15:43:  [test]> CREATE TABLE TEST_FLASHBACK
    -> (EMPNO INT(10),
    -> ENAME VARCHAR(10),
    -> JOB VARCHAR(9),
    -> MGR INT(10),
    -> HIREDATE DATETIME,
    -> SAL INT(10),
    -> COMM INT(10),
    -> DEPTNO INT(10));
Query OK, 0 rows affected (0.58 sec)
root@db 15:44:  [test]> INSERT INTO TEST_FLASHBACK VALUES (7369,'SMITH','CLERK',7902,'1980-12-17',800,NULL,20);
Query OK, 1 row affected (0.02 sec)

root@db 15:44:  [test]> INSERT INTO TEST_FLASHBACK VALUES (7499,'ALLEN','SALESMAN',7698,'1981-02-20',1600,300,30);
Query OK, 1 row affected (0.02 sec)

root@db 15:44:  [test]> INSERT INTO TEST_FLASHBACK VALUES (7521,'WARD','SALESMAN',7698,'1981-02-22',1250,500,30);
Query OK, 1 row affected (0.00 sec)
root@db 15:44:  [test]> SELECT * FROM TEST_FLASHBACK;
+-------+-------+----------+------+---------------------+------+------+--------+
| EMPNO | ENAME | JOB      | MGR  | HIREDATE            | SAL  | COMM | DEPTNO |
+-------+-------+----------+------+---------------------+------+------+--------+
|  7369 | SMITH | CLERK    | 7902 | 1980-12-17 00:00:00 |  800 | NULL |     20 |
|  7499 | ALLEN | SALESMAN | 7698 | 1981-02-20 00:00:00 | 1600 |  300 |     30 |
|  7521 | WARD  | SALESMAN | 7698 | 1981-02-22 00:00:00 | 1250 |  500 |     30 |
+-------+-------+----------+------+---------------------+------+------+--------+
3 rows in set (0.00 sec)
root@db 15:44:  [test]> show master status;
+------------------+----------+--------------+------------------+-------------------+
| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------+-------------------+
| mysql-bin.000005 |     1845 |              |                  |                   |
+------------------+----------+--------------+------------------+-------------------+
1 row in set (0.00 sec)
root@db 15:45:  [test]> delete from TEST_FLASHBACK;
Query OK, 3 rows affected (0.00 sec)

root@db 15:45:  [test]> select * from TEST_FLASHBACK;
Empty set (0.00 sec)
root@db 15:45:  [test]> show master status;
+------------------+----------+--------------+------------------+-------------------+
| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------+-------------------+
| mysql-bin.000005 |     2232 |              |                  |                   |
+------------------+----------+--------------+------------------+-------------------+
1 row in set (0.00 sec)
[root@source binlog2sql]# python binlog2sql.py -h192.168.0.13 -P3306 -uflashback -pXXXXX -dtest -tTEST_FLASHBACK --start-file='mysql-bin.000005' --start-datetime='2020-02-22 15:40:00' --stop-datetime='2020-02-22 15:50:00'
[root@source binlog2sql]# python binlog2sql.py -h192.168.0.13 -P3306 -uflashback -pXXXXX -dtest -tTEST_FLASHBACK --start-file='mysql-bin.000005' --start-position=1845 --stop-position=2201 -B > TEST_FLASHBACK_ROLLBACK.sql
[root@source binlog2sql]# ll
total 40
-rwxr-xr-x 1 root root  7747 Oct 12  2018 binlog2sql.py
-rwxr-xr-x 1 root root 11581 Oct 12  2018 binlog2sql_util.py
-rw-r--r-- 1 root root 10616 Feb 22 16:40 binlog2sql_util.pyc
-rw-r--r-- 1 root root    92 Oct 12  2018 __init__.py
-rw-r--r-- 1 root root   689 Feb 22 17:06 TEST_FLASHBACK_ROLLBACK.sql
[root@source binlog2sql]# more TEST_FLASHBACK_ROLLBACK.sql 

INSERT INTO `test`.`TEST_FLASHBACK`(`ENAME`, `SAL`, `EMPNO`, `MGR`, `JOB`, `COMM`, `HIREDATE`, `DEPTNO`) VALUES ('WARD', 1250, 7521, 7698, 'SALESMAN', 500, '1981-02-22 00:00:00', 30);

INSERT INTO `test`.`TEST_FLASHBACK`(`ENAME`, `SAL`, `EMPNO`, `MGR`, `JOB`, `COMM`, `HIREDATE`, `DEPTNO`) VALUES ('ALLEN', 1600, 7499, 7698, 'SALESMAN', 300, '1981-02-20 00:00:00', 30); 

INSERT INTO `test`.`TEST_FLASHBACK`(`ENAME`, `SAL`, `EMPNO`, `MGR`, `JOB`, `COMM`, `HIREDATE`, `DEPTNO`) VALUES ('SMITH', 800, 7369, 7902, 'CLERK', NULL, '1980-12-17 00:00:00', 20);
root@db 17:08:  [test]> show tables;
+----------------+
| Tables_in_test |
+----------------+
| BONUS          |
| DEPT           |
| EMP            |
| SALGRADE       |
| TEST_FLASHBACK |
+----------------+
5 rows in set (0.00 sec)
root@db 17:08:  [test]> select * from TEST_FLASHBACK;
Empty set (0.00 sec)

root@db 17:08:  [test]> system pwd
/opt/soft/binlog2sql-master/binlog2sql

root@db 17:08:  [test]> source /opt/soft/binlog2sql-master/binlog2sql/TEST_FLASHBACK_ROLLBACK.sql
root@db 17:08:  [test]> select * from TEST_FLASHBACK;
+-------+-------+----------+------+---------------------+------+------+--------+
| EMPNO | ENAME | JOB      | MGR  | HIREDATE            | SAL  | COMM | DEPTNO |
+-------+-------+----------+------+---------------------+------+------+--------+
|  7521 | WARD  | SALESMAN | 7698 | 1981-02-22 00:00:00 | 1250 |  500 |     30 |
|  7499 | ALLEN | SALESMAN | 7698 | 1981-02-20 00:00:00 | 1600 |  300 |     30 |
|  7369 | SMITH | CLERK    | 7902 | 1980-12-17 00:00:00 |  800 | NULL |     20 |
+-------+-------+----------+------+---------------------+------+------+--------+
3 rows in set (0.00 sec)


my2sql闪回

使用限制

  • my2sql 是模拟一个从库去在线获取主库 binlog,然后进行解析,因此执行操作的数据库用户需要具有 SELECT,REPLICATION SALVE,REPLICATION CLIENT 的权限。
  • 与 binlog2sql、MyFlash 差不多,my2sql 目前也不支持 8.0;闪回功能需要开启 binlog_format=row,binlog_row_image=full;只能闪回 DML 操作,不支持 DDL 的闪回。
  • 无法离线解析 binlog(MyFlash 支持)。
  • 不能以 GTID 事务为单位进行解析(MyFlash 支持),具体 file+pos 点位需要先通过手工解析 binlog 后确认。
  • 闪回/前滚 SQL 中,没有提供具体的 begin/commit 的位置,使用时无法分隔事务,需要人工判断。
  • 使用事务分析功能时,只能给出具体的大/长事务发生时间、点位、涉及的对象和操作类型,不能给出具体的 SQL 语句,完整的语句仍然需要去 binlog 中进行查看(需设置 binlog_rows_query_log_events=on)

实施步骤

一、下载及安装已编译版本
软件下载:https://github.com/liuhr/my2sql
将my2sql-master.zip软件传到tmp目录下

cd /tmp
cp /tmp/my2sql-master.zip  /usr/local/bin
unzip /usr/local/bin/my2sql-master.zip

得到/usr/local/bin/my2sql-master/releases/centOS_release_7.x
将软件添加到系统变量~/.bash_profile

export PATH=$PATH:/soft/mysql/bin:/usr/local/bin/my2sql-master/releases/centOS_release_7.x

二、查看 lsih.test 表数据,删除nm小于80的数据

mysql --login-path=root -A -e "select * from lsih.text;"
mysql --login-path=root -A
delete from lsih.text where nm<80;
select * from lsih.text;

三、解析binlog找到闪回的binlog及其pos

修改下面命令中的database,datetime,binlog目录,保存文件路径

mysqlbinlog --base64-output=decode-rows -v --database=lsih --start-datetime="2023-04-01 20:00:00" --stop-datetime="2023-04-01 20:25:00"  "/mysql/mysqldata/binlog/bin.000xx" > huifu.sql

查找 delete 语句起始及截至的 at xxxx号 如 at 8344894
less 或 cat huifu.sql |grep “230401 20:00” -B5 方式查找

四、生成闪回语句

mkdir /tmp/my2sql_test

my2sql -user lsih -password lsih -host 192.xxx.x.xxx -port 3306 -databases lsih -tables test  -server-id 8344894 -mode repl -sql delete -work-type rollback -start-file mysql-bin.000301 -start-pos 8348684  -stop-file mysql-bin.000301 -stop-pos 9987 --add-extraInfo -output-dir /tmp/my2sql_test

五、查看反向生成的回滚语句,确认其准确性

cat /tmp/my2sql_test/rollback.1.sql

参考文档

https://github.com/liuhr/my2sql


my2sql补充

my2sql工具介绍

说起MySQLbinlog解析工具,相信大家第一反应是binlog2sql,在日常工作中对于逻辑的误操作,误删除等可以通过此工具进行rollback操作。今天为大家介绍的是另一个binlog解析工具my2sql,他是一款是一款基于GO语言、参考my2fback工具所二次开发的MySQL回滚工具。其原理和binlog2sql一样都是通过解析binlog生成原始SQL与回滚SQL以数据数据的回滚或者主从切换后的数据补偿等功能,其核心特点如下:

1.解析效率上my2sql速度更快,可以设置多个线程进行解析

2.支持对DML操作进程统计,当服务器出现IO高,TPS高的情况时,可以通过此工具统计出更新批复的库表

3.支持查找某个时间段数据库是否有大事务或者长事务

下载地址及注意事项

下载地址:

wget https://raw.githubusercontent.com/liuhr/my2sql/master/releases/centOS_release_7.x/my2sql

下载到本地后给此文件执行权限即可使用:

chmod +x ./my2sq

主要事项:

1.my2sql需要伪装成从库获取主库 binlog进行解析,因此执行操作的数据库用户需要具有 SELECT,REPLICATION SALVE,REPLICATION CLIENT 的权限

2.使用回滚/闪回功能时,binlog 格式必须为 row ,且 binlog_row_image=full ,DML 统计以及大事务分析不受影响

3. 使用rollback功能时,要解析的binlog段表结构要保持一致

4.MySQL8.0版本需要在配置文件中加入default_authentication_plugin =mysql_native_password,用户密码认证必须是mysql_native_password才能解析

my2sql常用参数介绍:

--help 查看帮助

-mode:默认为repl,代表伪装成从库获取主库的binlog文件,如果为file则是从本地文件系统获取 binlog 文件

-local-binlog-file:当-mode=file时所指定的binlog文件路径

-sql:要解析的SQL类型,可选参数有insert 、update、delete,默认全部解析

-file-per-table:为每个表生成一个 sql 文件

-output-dir: 将生成的结果存放到指定目录

-threads:线程数,默认2个,支持并发

-work-type:如果为2sql则是生成原始sql,如果为rollback则生成回滚SQL,如果为stats则只统计DML信息

-databases 、 -tables:指定库表

my2sql使用简介

1.根据时间点解析binlog生成执行SQL或回滚SQL

伪装成从库方式
./my2sql -user root -password xxxx -host 127.0.0.1 -port 3306 -mode repl -work-type 2sql -start-file mysql-bin.000087 -start-datetime "2023-03-16 16:20:00" -stop-datetime "2023-03-16 18:00:00" -output-dir /root/test
./my2sql -user root -password xxxx -host 127.0.0.1 -port 3306 -mode repl -work-type rollback -start-file mysql-bin.000087 -start-pos 4 -stop-file mysql-bin.000087 -stop-pos 694 -output-dir /root/test

直接读取binlog方式
./my2sql -user root -password xxxx -host 127.0.0.1 -port 3306 -mode file -local-binlog-file /data/mysql/binlog_3306/mysql-bin.000087 -work-type 2sql -start-file mysql-bin.000087 -start-datetime "2023-03-16 16:20:00" -stop-datetime "2023-03-16 18:00:00" -output-dir /root/test
./my2sql -user root -password xxxx -host 127.0.0.1 -port 3306 -mode file -local-binlog-file /data/mysql/binlog_3306/mysql-bin.000087 -work-type rollback -start-file mysql-bin.000087 -start-datetime "2023-03-16 16:20:00" -stop-datetime "2023-03-16 18:00:00" -output-dir /root/test

备注:mode类型是repl时如果只指定-start-file则会解析指定的binlog和其之后的binlog,如果只想解析87号binlog则需要加-stop-file mysql-bin.000088(stop file必须大于start file,stop file写成88不会分析此binlog)
可以不加start datatime,stop datatime参数来解析这个binlog

2.根据binlog pos点解析生长执行SQL或回滚SQL

伪装成从库方式
./my2sql -user root -password 123456 -host 127.0.0.1 -port 3306 -mode repl -work-type 2sql -start-file mysql-bin.000087 -start-pos 4 -stop-file mysql-bin.000087 -stop-pos 67386 -output-dir /root/test
./my2sql -user root -password 123456 -host 127.0.0.1 -port 3306 -mode repl -work-type rollback -start-file mysql-bin.000087 -start-pos 4 -stop-file mysql-bin.000087 -stop-pos 67386 -output-dir /root/test

直接读取binlog方式
./my2sql -user root -password 123456 -host 127.0.0.1 -port 3306 -mode file -local-binlog-file /data/mysql/binlog_3306/mysql-bin.000087 -work-type 2sql -start-file mysql-bin.000087 -start-pos 4 -stop-file mysql-bin.000087 -stop-file mysql-bin.000087 -stop-pos 67386 -output-dir /root/test
./my2sql -user root -password 123456 -host 127.0.0.1 -port 3306 -mode file -local-binlog-file /data/mysql/binlog_3306/mysql-bin.000087 -work-type rollback -start-file mysql-bin.000087 -start-pos 4 -stop-file mysql-bin.000087 -stop-file mysql-bin.000087 -stop-pos 67386 -output-dir /root/test

3.统计大事务:

./my2sql -user root -password 123456 -host 127.0.0.1 -port 3306 -mode file -local-binlog-file /data/mysql/binlog_3306/mysql-bin.000087 -work-type stats -start-file mysql-bin.000087  -big-trx-row-limit 500 -long-trx-seconds 300 -output-dir /root/test
上述是统计整个binlog信息,也可以统计一段时间内的大事务情况,增加-start-datetime -stop-datetime参数即可

实验操作:

1)伪装从库方式解析sql(测试表名为allstar):

binlog闪回_binlog2sql

解析sql:

./my2sql -user root -password 123456 -host 127.0.0.1 -port 3306 -mode repl -work-type 2sql -start-file mysql-bin.000089 -start-datetime "2023-03-29 14:20:00" -stop-datetime "2023-03-29 14:30:00" -output-dir /root/test

binlog闪回_mysql_02

输出的结果在指定的/root/test目录下(只需要指定目录即可,my2sql会自动创建相关的文件):

binlog闪回_my2sql_03

2)伪装从库方式生成flashback语句:

将韦德和科比的总冠军数改成6个后发现该错了,需要找到回滚SQL

binlog闪回_binlog2sql_04

./my2sql -user root -password 123456 -host 127.0.0.1 -port 3306 -mode repl -work-type rollback -start-file mysql-bin.000089 -start-datetime "2023-03-29 14:30:00" -stop-datetime "2023-03-29 15:30:00" -output-dir /root/test

binlog闪回_my2sql_05