(一)MyFlash介绍
MyFlash是美团开发的一个回滚DML操作的工具,该工具是开源的,github地址为:https://github.com/Meituan-Dianping/MyFlash。通过该工具,可以实现MySQL数据库的闪回。
(二)安装MyFlash
下载源码:
git clone https://github.com/Meituan-Dianping/MyFlash.git
安装依赖包:
yum install -y gcc pkg-config glib2 libgnomeui-devel
编译:
[root@masterdb MyFlash]# gcc -w `pkg-config --cflags --libs glib-2.0` source/binlogParseGlib.c -o binary/flashback
(三)使用MyFlash
MyFlash语法为:
[root@masterdb binary]# pwd /root/MyFlash/binary [root@masterdb binary]# ./flashback --help Usage: flashback [OPTION?] Help Options: -h, --help Show help options Application Options: --databaseNames databaseName to apply. if multiple, seperate by comma(,) --tableNames tableName to apply. if multiple, seperate by comma(,) --start-position start position --stop-position stop position --start-datetime start time (format %Y-%m-%d %H:%M:%S) --stop-datetime stop time (format %Y-%m-%d %H:%M:%S) --sqlTypes sql type to filter . support INSERT, UPDATE ,DELETE. if multiple, seperate by comma(,) --maxSplitSize max file size after split, the uint is M --binlogFileNames binlog files to process. if multiple, seperate by comma(,) --outBinlogFileNameBase output binlog file name base --logLevel log level, available option is debug,warning,error --include-gtids gtids to process --exclude-gtids gtids to skip
语法解析:
(四)MyFlash测试
(4.1)测试MyFlash闪回功能
STEP1:构造测试数据
[root@masterdb binary]# mysql -uroot -p123456 lijiamandb mysql> select * from test01; +----+--------+------------+ | id | name | birthday | +----+--------+------------+ | 1 | 小明 | 1993-01-02 | | 2 | 小华 | 1994-08-15 | | 3 | 小丽 | 1995-07-12 | +----+--------+------------+ 3 rows in set (0.00 sec)
STEP2:执行插入、更新、删除操作
mysql> insert into test01 values(4,'小红','2000-01-01'); Query OK, 1 row affected (0.01 sec) mysql> delete from test01 where id = 1; Query OK, 1 row affected (0.03 sec) mysql> update test01 set birthday = '1994-09-15'; Query OK, 3 rows affected (0.00 sec) Rows matched: 3 Changed: 3 Warnings: 0mysql> select * from test01; +----+--------+------------+ | id | name | birthday | +----+--------+------------+ | 2 | 小华 | 1994-09-15 | | 3 | 小丽 | 1994-09-15 | | 4 | 小红 | 1994-09-15 | +----+--------+------------+ 3 rows in set (0.00 sec)
STEP3:确认上面的DML操作二进制日志
mysql> show master status; +-------------------+----------+--------------+------------------+-------------------+ | File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set | +-------------------+----------+--------------+------------------+-------------------+ | master-bin.000001 | 1079 | | | | +-------------------+----------+--------------+------------------+-------------------+ 1 row in set (0.00 sec)
STEP4:发现误删除(delete)数据,要求恢复(需要2步)
执行闪回操作,将闪回结果存放到binlog_output_base.flashback中
[root@masterdb binary]# ./flashback --databaseNames=lijiamandb --tableNames=test01 --sqlTypes='DELETE' --binlogFileNames=/mysql/binlog/master-bin.000001 [root@masterdb binary]# ls -lrt total 7320 -rwxr-xr-x 1 root root 7463125 Apr 24 14:03 mysqlbinlog20160408 -rwxr-xr-x 1 root root 54272 Apr 24 14:14 flashback -rw-r--r-- 1 root root 263 Apr 24 14:38 binlog_output_base.flashback
应用闪回的日志:
[root@masterdb binary]# mysqlbinlog binlog_output_base.flashback | mysql -uroot -p123456
STEP5:确认结果,已经将“DELETE”删除的数据找了回来
mysql> select * from test01; +----+--------+------------+ | id | name | birthday | +----+--------+------------+ | 1 | 小明 | 1993-01-02 | | 2 | 小华 | 1994-09-15 | | 3 | 小丽 | 1994-09-15 | | 4 | 小红 | 1994-09-15 | +----+--------+------------+ 4 rows in set (0.00 sec)
(4.2)测试MyFlash同时应用多个binlog日志闪回
STEP1:确认初始数据
[root@masterdb binary]# mysql -uroot -p123456 lijiamandb mysql> select * from test01; +----+--------+------------+ | id | name | birthday | +----+--------+------------+ | 1 | 小明 | 1993-01-02 | | 2 | 小华 | 1994-09-15 | | 3 | 小丽 | 1994-09-15 | | 4 | 小红 | 1994-09-15 | +----+--------+------------+ 4 rows in set (0.00 sec)
STEP2:修改数据,并切换日志
mysql> update test01 set birthday = '1998-01-12' where id = 4; Query OK, 1 row affected (0.02 sec) Rows matched: 1 Changed: 1 Warnings: 0mysql> show master status; +-------------------+----------+--------------+------------------+-------------------+ | File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set | +-------------------+----------+--------------+------------------+-------------------+ | master-bin.000001 | 1651 | | | | +-------------------+----------+--------------+------------------+-------------------+ 1 row in set (0.00 sec) mysql> flush logs; Query OK, 0 rows affected (0.01 sec) mysql> show master status; +-------------------+----------+--------------+------------------+-------------------+ | File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set | +-------------------+----------+--------------+------------------+-------------------+ | master-bin.000002 | 154 | | | | +-------------------+----------+--------------+------------------+-------------------+ 1 row in set (0.00 sec) mysql> update test01 set name = 'a' where id = 2; Query OK, 1 row affected (0.00 sec) Rows matched: 1 Changed: 1 Warnings: 0mysql> select * from test01; +----+--------+------------+ | id | name | birthday | +----+--------+------------+ | 1 | 小明 | 1993-01-02 | | 2 | a | 1994-09-15 | | 3 | 小丽 | 1994-09-15 | | 4 | 小红 | 1998-01-12 | +----+--------+------------+ 4 rows in set (0.00 sec) mysql> flush logs -> ; Query OK, 0 rows affected (0.00 sec) mysql> show master status; +-------------------+----------+--------------+------------------+-------------------+ | File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set | +-------------------+----------+--------------+------------------+-------------------+ | master-bin.000003 | 154 | | | | +-------------------+----------+--------------+------------------+-------------------+ 1 row in set (0.00 sec) mysql> update test01 set birthday='2000-12-12' where id = 3; Query OK, 1 row affected (0.00 sec) Rows matched: 1 Changed: 1 Warnings: 0mysql> select * from test01; +----+--------+------------+ | id | name | birthday | +----+--------+------------+ | 1 | 小明 | 1993-01-02 | | 2 | a | 1994-09-15 | | 3 | 小丽 | 2000-12-12 | | 4 | 小红 | 1998-01-12 | +----+--------+------------+ 4 rows in set (0.00 sec) mysql> exit Bye
STEP3:执行闪回操作
[root@masterdb binary]# ./flashback --databaseNames=lijiamandb --tableNames=test01 --sqlTypes='UPDATE' --outBinlogFileNameBase=test01_update.flashback --binlogFileNames=/mysql/binlog/master-bin.000001,/mysql/binlog/master-bin.000002,/mysql/binlog/master-bin.000003 [root@masterdb binary]# ls -lrt total 7332 -rwxr-xr-x 1 root root 7463125 Apr 24 14:03 mysqlbinlog20160408 -rwxr-xr-x 1 root root 54272 Apr 24 14:14 flashback -rw-r--r-- 1 root root 263 Apr 24 14:38 binlog_output_base.flashback -rw-r--r-- 1 root root 495 Apr 24 14:58 test01_update.flashback.flashback.000002 -rw-r--r-- 1 root root 274 Apr 24 14:58 test01_update.flashback.flashback.000001 -rw-r--r-- 1 root root 279 Apr 24 14:58 test01_update.flashback.flashback [root@masterdb binary]# mysqlbinlog test01_update.flashback.flashback test01_update.flashback.flashback.000001 test01_update.flashback.flashback.000002| mysql -uroot -p123456 mysql: [Warning] Using a password on the command line interface can be insecure.
STEP4:确认数据,发现回滚到了最老的数据,不符合要求
[root@masterdb binary]# mysql -uroot -p123456 lijiamandb mysql> select * from test01; +----+--------+------------+ | id | name | birthday | +----+--------+------------+ | 1 | 小明 | 1993-01-02 | | 2 | 小华 | 1994-08-15 | | 3 | 小丽 | 1995-07-12 | | 4 | 小红 | 2000-01-01 | +----+--------+------------+ 4 rows in set (0.00 sec)
思路整理:
我们对数据进行多次更新,但是在使用binlog进行闪回的时候,没有指定开始、结束位置,因此对所有日志都进行了闪回,从而将数据闪回到了最初的数据,不符合我们的要求。如果我们指定合理的开始结束位置,还是可以将数据闪回到任意时刻的。
(五)总结
1.如果binlog日志存在,那么可以使用MyFlash将数据库闪回到任意时刻。
2.可以对整个实例进行闪回、也可以对某个database,或者是某张表进行闪回,还可以指定某种DML操作进行闪回。
3.MyFlash闪回也有一定的局限性。在闪回时,指定出闪回的开始和结束时间/位置依然是最为重要的,但使用flashback是无法查看二进制日志的,意味着在使用MyFlash时,要么预估开始结束时间,进行不精确的闪回,要么使用mysqlbinlog或binlog2sql来分析日志,得到精确的开始结束时间再闪回。
4.从测试来看,binlog2sql似乎比MyFlash更好用,但是为什么在已经有binlog2sql的基础上,还要开发MyFlash呢?最主要还是MyFlash性能非常好,闪回速度非常快,美团测试报告中,使用各个工具对约100万条数据进行闪回的测试如下(原文点这):
【完】