Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Succy/bin2sql

Folders and files

NameName
Last commit message
Last commit date

Latest commit

History

13 Commits

Repository files navigation

MySQL binlog转Sql工具

简介

工具起源

​ 一开始,我只想找一个工具去解析mysql的binlog,以便于不时之需恢复数据,首当其冲肯定是想到mysql官方都提供了哪些,因此最开始是研究mysqlbinlog这个工具的,但是后面发现,它只能指定到database级别,并不能到table级别,而且有时候我们不是很关心create/drop之类的sql,比较关心DML,甚至关心我能不能只过滤出来指定的表指定的类型的SQL语句。也正是由于这个原因,我在网上寻找了很多这方便的工具,总结一下网上的工具主要都是如下两方面的:

1、通过伪装成slave拉取binlog来进行处理。以binlog2sql为代表.

2、直接解析binlog文件,然后对数据做二次过滤的,以mysqlbinlog和本程序为代表。

​ 然而binlog2sql在我使用过程中,总得来说也还不错的,就是其运行有点慢,我就想能不能有一个工具可以直接解析binlog又能满足我的要求的?寻求了一圈之后我发现并没有很符合我的要求的,于是我打算自己写一个。一开始我并不打算使用Perl语言写的,因为我对这个语言不是很熟悉,我是想着用go或者python写的,但是在我用go和python写了一段时间之后,都发现在处理文本这块有些许不足,可能也是因为我的水平问题吧,因此我选择了Perl语言,简单看了下语法和网上的一些案例之后,就开始写了,Perl同时有着强大的正则表达式和能直接运行shell命令的强大特点让我在编写过程中节约了很多时间。

​ 这个小工具采用了mysqlbinlog作为主要产生数据的工具,通过Perl调用mysqlbinlog获取到可读的binlog数据,然后再进行流式处理,从而达到目的,在目前我的使用过程中发现,这样的配合执行速度还是不错的。由于我的Perl水平实在是有限,程序也难免会有错误,如果发现有错误或者有更好的写法,欢迎issue和pr或者直接邮件联系本人1459307744@qq.com

功能介绍

这是一款使用perl语言开发的mysql binlog转sql的工具,主要是弥补了mysqlbinlog这个自带的工具不能指定表名的不足,主要包含如下功能

  • 支持指定start-datetime和stop-datetime解析binlog。
  • 支持指定start-position和stop-position解析binlog。
  • 支持解析指定的databases、指定的tables。
  • 支持指定dml类型,仅支持INSERT、UPDATE、DELETE
  • 支持only-dml属性,如果指定该属性,则不会输出dml以外的sql。
  • 支持闪回(flashback)
  • 支持获取远端服务器的Binlog

设计思路

整个脚本设计思路非常简单,大致分为三步

1、通过操作指定的数据源,获取到information_schema存储的表字段信息。

2、通过mysqlbinlog工具,获取指定binlog文件。

3、解析binlog,提取出来sql,替换占位符为字段名,还原SQL,通过反转SQL,起到闪回的目的。

经过本人实践,依托Perl和mysqlbinlog,其性能还是不错的,整个过程都是使用流式处理的,理论上可以应对比较大的binlog文件,但是本人公司内毕竟需要恢复数据的场景并不是那么多(如果非常多误操作,怕是饭碗不保了),因此可能有些地方会略为片面,有需要的可以自行进行测试和修改或者提ISSUE。

注意事项

这里的内容非常关键,请务必注意

Q:如果我把表删了,还能恢复数据吗?

A:如果你把表删了,有备份在,并且表结构也没发生变化,可以恢复的。

Q:我就是把表删了,但是没有重建表结构,能把这个表之前发生的SQL操作恢复吗?

A:不可以。因为我们依赖information_schema获取表的字段名和顺序,根据这个替换binlog的占位符,如果把表删了,并且没有先恢复表结构,会忽略DML的解析的。

Q:如果表结构发生了变化,能恢复吗?

A:不能,都改表了,你恢复以前的数据有什么意义?就算强行解析出来,可能都错位了或者这个SQL就是有问题的了

安装和配置

github: https://github.com/Succy/bin2sql

gitee: https://gitee.com/succy/bin2sql

免安装版本

直接到release下载可执行文件,到Linux系统,添加可执行权限就可以运行了

源码安装

首先说明一下,我都是在Linux下测试的,并且也是针对Linux环境开发的,因为Perl语言在很多Linux发行版都内置,我所使用的是CentOS7,内置的Perl是5.16.3,如果想要在Windows下使用,请安装Perl语言环境,并且修改内部的mysqlbinlog为mysqlbinlog.exe(前提是mysqlbinlog.exe在环境变量内)。

特别注意:MySQL Server一定要开启binlog,而且要开启binlog_format=row,因为只有row模式下,才会记录更新前后的数据,如果您用的是mixed模式,请到mixed分支,mixed模式下,不支持闪回

我测试的Mysql数据库版本是5.7.25 理论上>=5.6的版本都支持。不过我没有做过测试

下面是安装步骤:

1、安装DBI/DBD

由于row模式下,记录了更新前后的数据,并且没有记录表的字段名,都是使用@1这样的占位符来代替字段名,所以,要还原原本的字段名必须通过mysql的information_schema这个库来获取对应表的字段。因此在脚本内,使用了Perl的DBI来操作数据库。

在CentOS7下面,关于安装DBI/DBD::mysql的方法有很多,有直接用yum安装的,也有下载源码安装的,不过有些我也没试过,下面是我本人安装的步骤。

1、通过yum安装cpan(cpan是Perl的一个包管理工具,类似nodejs的npm,python的pip)
yum -y install cpan
2、通过cpan安装DBI,如果是第一次使用cpan,会有一些配置的选项需要询问配置,此时,全部默认即可
cpan install DBI
3、通过cpan安装DBD:mysql
cpan install DBD::mysql

2、克隆项目并授权执行

1、克隆本项目到服务器本地
2、进入项目根目录并且授予可执行权限
cd bin2sql && chmod +x bin2sql
3、运行bin2sql

直接运行bin2sql会出现如下的帮助文档

MySQL Binlog to SQL
Options:
 -h, --host=name Get the binlog from server, default localhost.
 -u, --user=name Connect to the remote server as username, default root.
 -P, --port=# Port number to use for connection or 3306 for default to.
 -p, --password[=name] Password to connect to remote server.
 -t, --tables=name Export tables in table names, delimiter by comma.
 -d, --database=name List entries for just this database (local log only).
 -B, --flashback Is print flashback SQL, only DML could be flashback.
 --start-datetime=name Start reading the binlog at first event having a datetime
 equal or posterior to the argument; the argument must be
 a date and time in the local time zone, in any format
 accepted by the MySQL server for DATETIME and TIMESTAMP
 types, for example: 2004年12月25日 11:25:56 (you should
 probably use quotes for your shell to set it properly).
 --start-position=# Start reading the binlog at position N. Applies to the
 first binlog passed on the command line.
 --stop-datetime=name Stop reading the binlog at first event having a datetime
 equal or posterior to the argument; the argument must be
 a date and time in the local time zone, in any format
 accepted by the MySQL server for DATETIME and TIMESTAMP
 types, for example: 2004年12月25日 11:25:56 (you should
 probably use quotes for your shell to set it properly).
 --stop-position=# Stop reading the binlog at position N. Applies to the
 last binlog passed on the command line.
 --only-dml Only print dml sql, optional, default disabled.
 --sql-type Sql type you want to process, support INSERT, UPDATE, DELETE.
 -f, --binlog=name Read from binlog file.
 --help Print help message.

3、作者建议

如果数据库服务器有多台的话,建议在一台空的服务器运行本脚本,通过设定-h参数远程抓去binlog解析即可,不要随意放在数据库服务器上面运行,其原因有2

  • 不需要到处安装DBI和DBD这些Perl的数据库依赖
  • mysqlbinlog和bin2sql两个进程同时运行,对CPU有一定的消耗,可能会影响到数据库服务器的IO吞吐

用法和示例

1、用法选项

mysql相关连接配置

不管是获取schema信息还是mysqlbinlog获取binlog信息,都是使用同一套mysql的连接参数

-h host; -P port; -u user; -p password
这几个参数都是给mysqlbinlog使用的,这里强调一个参数,就是-u这个参数,必须拥有 REPLICATION SLAVE 权限。
建议授权如下
GRANT SELECT, REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO User

对象过滤

-d, --databases 解析目标db的sql,多个库用逗号隔开,如-d db1,db2。必选。
-t, --tables 解析目标table的sql,多张表用空格隔开,如-t tbl1 tbl2。可选。默认为空。
--only-dml 只解析dml,忽略ddl。可选。默认False。
--sql-type 解析指定类型,支持INSERT, UPDATE, DELETE。多个类型用逗号隔开,如--sql-type INSERT,DELETE。可选。默认为增删改都解析。

范围解析

这里的参数都是配合mysqlbinlog使用的

-f,--binlog 要解析的Binlog文件名,无需全路径 。必须。
--start-position 起始解析位置。可选。
--stop-position 终止解析位置。可选。
--start-datetime 起始解析时间,格式'%Y-%m-%d %H:%M:%S'。可选。默认不过滤。
--stop-datetime 终止解析时间,格式'%Y-%m-%d %H:%M:%S'。可选。默认不过滤。

闪回

-B, --flashback 生成回滚SQL,可选,默认为false,只有DML才支持闪回,DDL不支持闪回。

2、示例

创建示例表

CREATE TABLE `user` (
 `id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'ID',
 `username` varchar(255) DEFAULT NULL COMMENT '用户名',
 `address` varchar(255) DEFAULT NULL COMMENT '地址',
 `create_time` datetime DEFAULT NULL COMMENT '创建时间',
 `phone_no` varchar(255) DEFAULT NULL COMMENT '电话号码',
 PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

查看表原有数据

mysql> select * from user;
+----+-----------+-----------------+---------------------+--------------+
| id | username | address | create_time | phone_no |
+----+-----------+-----------------+---------------------+--------------+
| 1 | Succy | 广西南宁市 | 2021-05-03 21:05:14 | 1300000001 |
| 2 | 王小花 | 山西太原市 | 2021-05-03 21:05:46 | 15099999999 |
| 3 | 江小白 | 重庆市 | 2021-05-03 21:06:21 | 19788888888 |
| 4 | 郭靖 | 湖北襄阳 | 2021-05-03 21:06:43 | 188888898999 |
| 5 | 杨过 | 江苏苏州 | 2021-05-03 21:07:10 | 16666666878 |
| 6 | 陆无双 | 山东济南市 | 2021-05-03 21:07:35 | 155236995454 |
+----+-----------+-----------------+---------------------+--------------+
6 rows in set (0.00 sec)

随机对数据进行修改,添加,删除,然后查询其binlog记录的sql。

解析出user表所有操作的sql

shell> ./bin2sql -d demo -f mysql-bin.000002 -h 127.0.0.1 -t user
#210503 21:03:54 end_log_pos: 7852
CREATE TABLE `demo`.`user` (
 `id` int(0) NOT NULL AUTO_INCREMENT COMMENT 'ID',
 `username` varchar(255) NULL COMMENT '用户名',
 `address` varchar(255) NULL COMMENT '地址',
 `create_time` datetime(0) NULL COMMENT '创建时间',
 `phone_no` varchar(255) NULL COMMENT '电话号码',
 PRIMARY KEY (`id`)
);
#210503 21:05:24 end_log_pos: 8128
INSERT INTO `demo`.`user` VALUES(1, 'Succy', '广西南宁市', '2021年05月03日 21:05:14', '1300000001');
#210503 21:05:53 end_log_pos: 8440
INSERT INTO `demo`.`user` VALUES(2, '王小花', '山西太原市', '2021年05月03日 21:05:46', '15099999999');
#210503 21:06:27 end_log_pos: 8746
INSERT INTO `demo`.`user` VALUES(3, '江小白', '重庆市', '2021年05月03日 21:06:21', '19788888888');
#210503 21:06:50 end_log_pos: 9053
INSERT INTO `demo`.`user` VALUES(4, '郭靖', '湖北襄阳', '2021年05月03日 21:06:43', '188888898999');
#210503 21:07:14 end_log_pos: 9359
INSERT INTO `demo`.`user` VALUES(5, '杨过', '江苏苏州', '2021年05月03日 21:07:10', '16666666878');
#210503 21:07:44 end_log_pos: 9672
INSERT INTO `demo`.`user` VALUES(6, '陆无双', '山东济南市', '2021年05月03日 21:07:35', '155236995454');
#210503 21:10:45 end_log_pos: 10030
UPDATE `demo`.`user` SET `id`=5, `username`='杨过过', `address`='江苏南京市', `create_time`='2021年05月03日 21:07:10', `phone_no`='16666666878' WHERE `id`=5 AND `username`='杨过' AND `address`='江苏苏州' AND `create_time`='2021年05月03日 21:07:10' AND `phone_no`='16666666878';
#210503 21:11:07 end_log_pos: 10340
INSERT INTO `demo`.`user` VALUES(7, '公孙绿萼', '绝情谷', '2021年05月03日 21:11:01', '188777738934');
#210503 21:11:30 end_log_pos: 10645
INSERT INTO `demo`.`user` VALUES(8, '程英', '桃花岛', '2021年05月03日 21:11:24', '1778346836483');
#210503 21:11:33 end_log_pos: 10951
DELETE FROM `demo`.`user` WHERE `id`=3 AND `username`='江小白' AND `address`='重庆市' AND `create_time`='2021年05月03日 21:06:21' AND `phone_no`='19788888888';
#210503 21:11:51 end_log_pos: 11315
UPDATE `demo`.`user` SET `id`=2, `username`='王小花', `address`='广东深圳市', `create_time`='2021年05月03日 21:05:46', `phone_no`='15099999999' WHERE `id`=2 AND `username`='王小花' AND `address`='山西太原市' AND `create_time`='2021年05月03日 21:05:46' AND `phone_no`='15099999999';

后面发现有些数据删错了,更新的也错了,想要把所有删除的和更新的数据恢复

闪回所有误操作的数据

shell> ./bin2sql -d demo -f mysql-bin.000002 -h 127.0.0.1 -t user -B --sql-type DELETE,UPDATE
#210503 21:10:45 end_log_pos: 10030
UPDATE `demo`.`user` SET `id`=5, `username`='杨过', `address`='江苏苏州', `create_time`='2021年05月03日 21:07:10', `phone_no`='16666666878' WHERE `id`=5 AND `username`='杨过过' AND `address`='江苏南京市' AND `create_time`='2021年05月03日 21:07:10' AND `phone_no`='16666666878';
#210503 21:11:33 end_log_pos: 10951
INSERT INTO `demo`.`user` VALUES(3, '江小白', '重庆市', '2021年05月03日 21:06:21', '19788888888');
#210503 21:11:51 end_log_pos: 11315
UPDATE `demo`.`user` SET `id`=2, `username`='王小花', `address`='山西太原市', `create_time`='2021年05月03日 21:05:46', `phone_no`='15099999999' WHERE `id`=2 AND `username`='王小花' AND `address`='广东深圳市' AND `create_time`='2021年05月03日 21:05:46' AND `phone_no`='15099999999';

更多玩法等着你去发掘

鸣谢

binlog2sql 这个项目给我提供了我python版本的借鉴,虽然后面python版本的流产了。

MySQL_Binlog_Table_Filter 本工具借鉴了这个项目,由于我是Perl新手,这个项目给我提供了不少Perl相关写法借鉴。

About

mysql binlog file parse to sql

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

AltStyle によって変換されたページ (->オリジナル) /