喜歡就去追阿~ 晚下手,你就是孩子她舅!早下手,就是喜当爹...
前言
flashback闪回原理上一篇
flashback的概念最早出现于Oracle数据库,用于快速恢复用户的误操作。
flashback for MySQL用于恢复由DML语句引起的误操作,目前不支持DDL语句。例如下面的语句:
1 | mysql> DELETE FROM XXX; UPDATE XXX SET YYY=ZZZ; |
若没有flashback功能,那么当发生误操作时,用户只能通过全备+二进制日志前滚的方式进行恢复。通常来说,这样所需的恢复时间会非常长。为了缩短误操作恢复的时间,通常可以在slave上搭建LVM,通过定期快照的方式来缩短误操作的恢复时间。但是LVM快照的缺点是会对slave的性能产生一定的影响。
官方mysqlbinlog命令为解析MySQL的二进制日志。当二进制日志的格式为ROW格式时,可以输出每个操作的每条记录的前项与后项。那么通过逆操作即可进行回滚操作,例如:
1 | 原始操作:INSERT INTO ... |
目前flashback功能还没有集成于官方mysqlbinlogg命令。于是自己开发了一套 MySQL Flashback 工具 my2fback
介绍
my2fback 实现了基于row格式binlog的回滚闪回功能,让误删除或者误更新数据,可以不停机不使用备份而快速回滚误操作。也可以解释binlog(支持非row格式binlog)生成易读的SQL。可以按配置输出各个表的update/insert/delete统计报表, 也会输出大事务与长事务的分析, 应用是否干了坏事一目了然, 也会输出所有DDL。
1 | cat my.cnf |
my2fback 连接数据库帐号的权限:
- MySQL5.6/MariaDB10.1/MariaDB10.2版本
1 | mysql> GRANT SELECT, REPLICATION SLAVE, REPLICATION CLIENT, PROCESS ON *.* TO 'user'@'localhost' IDENTIFIED BY 'xxxxxx'; |
- MySQL5.7版本
1
2mysql> CREATE USER 'user'@'localhost' IDENTIFIED BY 'xxxxxx';
mysql> GRANT SELECT, REPLICATION SLAVE, REPLICATION CLIENT, PROCESS ON *.* TO 'user'@'localhost';
my2fback 通过解释mysql/mariadb binlog/relaylog实现以下三大功能:
flashback/闪回/回滚, DML回滚到任意时间或者位置。
- 生成的文件名为rollback.xxx.sql或者db.tb.rollback.xxx.sql
- 生成的SQL形式如下
1
2
3
4begin
DELETE FROM `test`.`t1` WHERE `id`=1
# datetime=2019-06-15_16:23:58 database=test table=t1 binlog=mysql-bin.000012 startpos=417 stoppos=575
commit
前滚,把binlog/relaylog的DML解释成易读的SQL语句。
- 支持非row格式的binlog, 默认不解释非row格式的DML, 需要指定参数 -stsql
- 生成的文件名为forward.xxx.sql或者db.tb.forward.xxx.sql
- 生成的SQL形式如下
1
2
3
4begin
# datetime=2019-06-15_16:23:58 database=test table=t1 binlog=mysql-bin.000012 startpos=417 stoppos=575
INSERT INTO `test`.`t1` (`id`,`name`,`sr`,`icon`,`points`,`sa`,`sex`) VALUES (1,'张三1','华南理工大学&SCUT',X'89504e47',1.1,1.1,1)
commit
输出row格式下的原始SQL(5.7)
- 结果文件名为original_sql.binlogxxx.sql
统计分析, 输出各个表的DML统计, 输出大事务与长事务, 输出所有的DDL
- DML统计结果文件:
binlog_status.txt
- 大事务与长事务结果文件:
binlog_biglong_trx.txt
- DDL结果文件:
ddl_info.txt
- DML统计结果文件:
特点
- 支持V4版本的binlog, 支持传统与GTID的binlog, 支持mysql5.1与mairiadb5.5及以上版本的binlog, 也同样支持relaylog(结果中注释的信息binlog=xxx startpos=xxx stoppos=xx是对应的主库的binlog信息)
- –mtype=mariadb
- 支持以时间及位置条件过滤, 并且支持单个以及多个连续binlog的解释。
- 区间范围为左闭右开, [-sxx, -exxx)
- 解释binlog的开始位置:
- -sbin mysql-bin.000101
- -spos 4
- 解释binlog的结束位置:
- -ebin mysql-bin.000105
- -epos 4
- 解释binlog的开始时间
- -sdt “2019-06-15 00:00:00”
- 解释binlog的结束时间
- -edt “2019-06-15 11:00:00”
- 支持以库及表条件过滤, 以逗号分隔
- 支持正则表达式,如-dbs “db\d+,db_sh\d+”。正则表达式中请使用小写字母,因为数据库名与表名会先转成小写再与正则表达式进行匹配
- -dbs db1,db2
- -tbs tb1,tb2
- 支持以DML类型(update,delete,insert)条件过滤
- -sql delete,update
- 支持分析本地binlog,也支持复制协议, my2fback作为一个从库从主库拉binlog来本地解释
- -m file //解释本地binlog
- -m repl //my2fback作为slave连接到主库拉binlog来解释
- 输出的结果支持一个binlog一个文件, 也可以一个表一个文件
- -f
- 例如对于binlog mysql-bin.000101, 如果一个表一个文件, 则生成的文件形式为
- db.tb.rollback.101.sql(回滚)
- db.tb.forward.101.sql(前滚),
- 否则是rollback.101.sql(回滚),forward.101.sql(前滚)
- -f
- 输出的结果是大家常见的易读形式的SQL,支持表名前是否加数据库名
- -d
1
2
3
4
5
6begin
# datetime=2019-06-15_00:14:34 database=test table=t1 binlog=mysql-bin.000012 startpos=21615 stoppos=22822
UPDATE `test`.`t1` SET `sa`=1001 WHERE `id`=5;
# datetime=2019-06-15_00:14:45 database=test table=t1 binlog=mysql-bin.000012 startpos=22822 stoppos=23930
UPDATE `test`.`t1` SET `name`=null WHERE `id`=5;
commit
- -d
否则为
1 | begin |
- 输出结果支持是否保留事务
- -k
1
2
3
4
5
6begin
# datetime=2019-06-15_00:14:34 database=test table=t1 binlog=mysql-bin.000012 startpos=21615 stoppos=22822
UPDATE `test`.`t1` SET `sa`=1001 WHERE `id`=5;
# datetime=2019-06-15_00:14:45 database=test table=t1 binlog=mysql-bin.000012 startpos=22822 stoppos=23930
UPDATE `test`.`t1` SET `name`=null WHERE `id`=5;
commit
- -k
不保留则是这样:
1 | # datetime=2019-06-15_00:14:34 database=test table=t1 binlog=mysql-bin.000012 startpos=21615 stoppos=22822 |
如果复制因为特别大的事务而中断, 则可以以不保留事务的形式生成前滚的SQL, 在从库上执行, 然后跳过这个事务, 再启动复制, 免去重建从库的
麻烦, 特别是很大的库
- 支持输出是否包含时间与binlog位置信息
- -e
- 包含额外的信息则为
1
2
3
4# datetime=2019-06-15_00:14:34 database=test table=t1 binlog=mysql-bin.000012 startpos=21615 stoppos=22822
UPDATE `test`.`t1` SET `sa`=1001 WHERE `id`=5;
# datetime=2019-06-15_00:14:45 database=test table=t1 binlog=mysql-bin.000012 startpos=22822 stoppos=23930
UPDATE `test`.`t1` SET `name`=null WHERE `id`=5;
否则为
1 | UPDATE `test`.`t1` SET `sa`=1001 WHERE `id`=5; |
- 支持生成的SQL只包含最少必须的字段, 前提下是表含有主键或者唯一索引
默认为
1
2UPDATE `test`.`t1` SET `sa`=1001 WHERE `id`=5;
DELETE FROM `test` WHERE `id`=5;-a 则为
1
2UPDATE `test`.`t1` SET `id`=5, `age`=21, `sex`='M',`sa`=1001, `name`='test' WHERE `id`=5 and `age`=21 and `sex`='M' and `sa`=900 and `name`='test';
DELETE FROM `test` WHERE `id`=5 and `age`=21 and `sex`='M' and `sa`=900 and `name`='test';
- 支持优先使用唯一索引而不是主键来构建where条件
- -U
- 有时不希望使用主健来构建wheret条件, 如发生双写时, 自增主健冲突了, 这时使用非主健的唯一索引来避免生成的SQL主健冲突
- 支持生成的insert语句不包含主健
- -I
- 发生双写时, 自增主健冲突了, 这时使用这个参数来让生成的insert语句不包括主健来避免生成的SQL主健冲突
- -I
支持大insert拆分成小insert语句。
- -r 100
- 对于一个insert 1000行的插入, 会生成10个insert语句,每个语句插入100行
支持非row格式binlog的解释
- 当-w 2sql时加上参数-stsql,则会解释非row格式的DML语句。
- 由于不是支持所有要SQL, 如create trigger就不支持, 遇到SQL无法解释时会报错退出, 如需要跳过该SQL并继续解释, 请使用参数-ies。-ies 后接正则表达式,
- 解释错误或者无法解释的SQL如果匹配-ies指定的正则表达式, 则my2fback不会退出而是跳过该SQL继续解释后面的binlog, 否则错误退出。
- -ies 后接的正则表达式请使用小写字母, my2fback会先把SQL转成小写再与之匹配。
安装与下载
安装
如果需要编译, 请使用GO>=1.11.x版本来编译。
开启GO111MODULE参数
编译linux 平台
1
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o releases/my2fback -ldflags "-s -w" main.go
编译windows 平台
1
CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -o releases/my2fback -ldflags "-s -w" main.go
没有开启GO111MODULE参数
编译linux 平台
1
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o releases/my2fback -ldflags "-s -w" main.go
编译windows 平台
1
CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -o releases/my2fback -ldflags "-s -w" main.go
下载
- linux版本: linux_releases
- windows版本:windows_releases
使用帮助
1 | test_dbs2 ~ # /usr/local/bin/my2fback -h |
常用参数
1 | -m string |
例子
测试机器
- CPU 2c
- 内存 4G
- 磁盘 400G
file本地方式解析binlog
1
test_dbs2 ~ # time /usr/local/bin/my2fback -m file -w 2sql -M mysql -t 6 -H ***.***.***.*** -u test -p test -dbs babytree -tbs userbaby -e -f -d -r 20 -k -b 100 -l 10 -o /data/bak/20190626/tosql /data/bak/20190626/mysql-bin.002938
1 | test_dbs2 ~ # ls /data/bak/20190626/tosql/ |
1 | test_dbs2 ~ # cat /data/bak/20190626/tosql/babytree.UserBaby.forward.2938.sql |more |
- file本地方式回滚binlog
1
est_dbs2 ~ # time /usr/local/bin/my2fback -m file -w rollback -M mysql -t 6 -H ***.***.***.*** -u test -p test -dbs babytree -tbs userbaby -e -f -d -r 20 -k -b 100 -l 10 -o /data/bak/20190626/tosql /data/bak/20190626/mysql-bin.002938
-w 修改为 rollback
看上面解析的SQl,用grep 进行搜索下,是不是回滚对了。还有一定要和业务方确认,业务方确认,业务方确认。重要的事情说三遍
1 | test_dbs2 ~ # cat /data/bak/20190626/tosql/babytree.UserBaby.rollback.2938.sql|grep -C 2 83758158 |
- relp 方式解析binlog
- 数据库上的binlog文件起始文件和结束文件
1 | test_dbs2 ~ # time /usr/local/bin/my2fback -m repl -w 2sql -M mysql -t 6 -H ***.***.***.*** -u test -p test -dbs babytree -tbs userbaby -e -f -d -r 20 -k -b 100 -l 10 -sbin mysql-bin.003045 -spos 4 -ebin mysql-bin.003079 -epos 4 -o /data/bak/20190626/tosql/ |
系统资源
执行截图
binlog文件共计有36个。文件大小为36G。解析时间:57m24.978s
- repl 方式回滚binlog
1
test_dbs2 ~ # time /usr/local/bin/my2fback -m repl -w rollback -M mysql -t 6 -H ***.***.***.*** -u test -p test -dbs babytree -tbs userbaby -e -f -d -r 20 -k -b 100 -l 10 -sbin mysql-bin.003045 -spos 4 -ebin mysql-bin.003045 -epos 888888 -o /data/bak/20190626/tosql/
就不贴图了。和file方式一致。
解析文件可以是一个时间范围,也可以是一个positiions范围。
最后
一个小菜鸟撸的菜鸟工具,如果有BUG。请大家多多包容。
测试通过,已经在宝宝树线上使用。累计恢复数据120G。
如果不放心。请使用binlog2sql。