MySQL闪回工具—my2sql

my2sql是使用go语言开发的MySQL binlog解析工具,通过解析MySQL binlog ,可以生成原始SQL、回滚SQL、去除主键的INSERT SQL等,也可以生成DML统计信息。类似工具有binlog2sql、MyFlash、my2fback等,本工具基于my2fback、binlog_rollback工具二次开发而来。

my2sql的GitHub地址:https://github.com/liuhr/my2sql

优点:

  • 功能丰富,不仅支持回滚操作,还有其他实用功能。
  • 基于golang实现,速度快,全量解析1.1Gbinlog只需要1分30秒左右,当前其他类似开源工具一般要几十分钟。

my2sql用途

  • 数据快速回滚(闪回)
  • 主从切换后新master丢数据的修复
  • 从binlog生成标准SQL,带来的衍生功能
  • 生成DML统计信息,可以找到哪些表更新的比较频繁
  • IO高TPS高, 查出哪些表在频繁更新
  • 找出某个时间点数据库是否有大事务或者长事务
  • 主从延迟,分析主库执行的SQL语句
  • 除了支持常规数据类型,对大部分工具不支持的数据类型做了支持,比如json、blob、text、emoji等数据类型sql生成

产品性能对比

binlog2sql当前是业界使用最广泛的MySQL回滚工具,下面对my2sql和binlog2sql做个性能对比。

my2sql

binlog2sql

1.1G binlog生成回滚SQL

1分40秒

65分钟

1.1G binlog生成原始SQL

1分30秒

50分钟

1.1G binlog生成表DML统计信息、以及事务统计信息

40秒

不支持

安装

首先需要go语言的环境

# yum方式安装
yum install -y golang
go version
go env | grep GOPATH

# tar包方式安装
 wget https://dl.google.com/go/go1.10.3.linux-amd64.tar.gz
 mv go1.10.3.linux-amd64.tar.gz /usr/local/
 cd /usr/local/
 tar -zxvf  go1.10.3.linux-amd64.tar.gz
 vim /etc/profile
# 在最后一排添加
 export GOROOT=/usr/local/go
 export PATH=$PATH:$GOROOT/bin
# 重新编译profile
source /etc/profile
# 查看版本信息
go version

下载my2sql工具

# 从git上下载zip包并解压
unzip my2sql-master.zip
mv my2sql-master my2sql
cd my2sql/releases/centOS_release_7.x/
mv my2sql /usr/local/bin/my2sql
chmod +x /usr/local/bin/my2sql

使用my2sql的前提条件

需要准备好MySQL环境,需要满足以下条件

  • 使用回滚/闪回功能时,binlog格式必须为row,且binlog_row_image=full, DML统计以及大事务分析不受影响
  • 只能回滚DML, 不能回滚DDL
  • 支持指定-tl时区来解释binlog中time/datetime字段的内容。开始时间-start-datetime与结束时间-stop-datetime也会使用此指定的时区, 但注意此开始与结束时间针对的是binlog event header中保存的unix timestamp。结果中的额外的datetime时间信息都是binlog event header中的unix timestamp
  • 此工具是伪装成从库拉取binlog,需要连接数据库的用户有SELECT, REPLICATION SLAVE, REPLICATION CLIENT权限
  • MySQL8.0版本需要在配置文件中加入default_authentication_plugin =mysql_native_password,用户密码认证必须是mysql_native_password才能解析

关于如何安装MySQL可以参考我的另一篇博客【Linux上的MySQL8搭建与初始化】

MySQL8.0的默认加密方式不是mysql_native_password,所以要在配置文件中加入default_authentication_plugin =mysql_native_password

使用

此次是生产上CI/CD需要MySQL闪回,所以用时间来作为条件进行闪回

create database test;
use test;
create table t1(id int);
insert into t1 values (1);
insert into t1 values (2);
insert into t1 values (3);
insert into t1 values (4);
insert into t1 values (5);

-- 记录一下时间

mysql> select now();
+---------------------+
| now()               |
+---------------------+
| 2021-04-19 14:48:42 |
+---------------------+
1 row in set (0.02 sec)

-- 等几分钟
insert into t1 values (6);
insert into t1 values (7);
insert into t1 values (8);
insert into t1 values (9);
insert into t1 values (10);

mysql> select now();
+---------------------+
| now()               |
+---------------------+
| 2021-04-19 14:54:52 |
+---------------------+
1 row in set (0.02 sec)

此时我们使用闪回工具回到2021-04-19 14:52:57这个第一次插完数据的时间

my2sql -user root -password Mysql_123 -host 127.0.0.1   -port 3306  -work-type rollback -start-file binlog.000001 -start-datetime "2021-04-19 14:48:42" -output-dir /root/tmpdir

[2021/04/19 20:56:04] [info] stats_process.go:166 start thread to analyze statistics from binlog
[2021/04/19 20:56:05] [info] events.go:208 start thread to write redo/rollback sql into file
[2021/04/19 20:56:04] [info] events.go:58 start thread 1 to generate redo/rollback sql
[2021/04/19 20:56:05] [info] binlogsyncer.go:144 create BinlogSyncer with config {1113306 mysql 127.0.0.1 3306 root   utf8 false false <nil> false Local false 0 0s 0s 0 false false 0}
[2021/04/19 20:56:05] [info] binlogsyncer.go:360 begin to sync binlog from position (binlog.000001, 4)
[2021/04/19 20:56:06] [info] repl.go:15 start to get binlog from mysql
[2021/04/19 20:56:06] [info] binlogsyncer.go:777 rotate to (binlog.000001, 4)
[2021/04/19 20:56:06] [info] binlogsyncer.go:777 rotate to (binlog.000002, 4)
[2021/04/19 20:56:06] [info] binlogsyncer.go:777 rotate to (binlog.000003, 4)
[2021/04/19 20:56:07] [info] events.go:239 finish processing binlog.000003 684
[2021/04/19 20:56:12] [info] repl.go:83 deadline exceeded.
[2021/04/19 20:56:12] [info] repl.go:17 finish getting binlog from mysql
[2021/04/19 20:56:12] [info] stats_process.go:266 exit thread to analyze statistics from binlog
[2021/04/19 20:56:12] [info] events.go:183 exit thread 1 to generate redo/rollback sql
[2021/04/19 20:56:12] [info] events.go:257 finish writing rollback sql into tmp files, start to revert content order of tmp files
[2021/04/19 20:56:12] [info] rollback_process.go:15 start thread 2 to revert rollback sql files
[2021/04/19 20:56:12] [info] rollback_process.go:41 start to revert tmp file /root/tmpdir/.rollback.1.sql into /root/tmpdir/rollback.1.sql
[2021/04/19 20:56:12] [info] rollback_process.go:156 finish reverting tmp file /root/tmpdir/.rollback.1.sql into /root/tmpdir/rollback.1.sql
[2021/04/19 20:56:12] [info] rollback_process.go:15 start thread 1 to revert rollback sql files
[2021/04/19 20:56:12] [info] events.go:270 finish reverting content order of tmp files
[2021/04/19 20:56:12] [info] events.go:275 exit thread to write redo/rollback sql into file

此时可以发现我们的回滚sql已经生成完毕了,切换到我们刚才指定的outdir

cd /root/tmpdir
vim rollback.1.sql

# 内容如下
DELETE FROM `test`.`t1` WHERE `id`=10;
DELETE FROM `test`.`t1` WHERE `id`=9;
DELETE FROM `test`.`t1` WHERE `id`=8;
DELETE FROM `test`.`t1` WHERE `id`=7;
DELETE FROM `test`.`t1` WHERE `id`=6;

此时已经成功生成了回滚sql,然后执行sql就可以回到2021-04-19 14:48:42这个时间点的状态了。

总结

这只是my2sql的一个简单测试使用,还有更多的功能需要自己动手去实践