阅读目录

回到顶部

1. 简介

mysqlbinlog flashback(闪回)用于快速恢复由于误操作丢失的数据。在DBA误操作时,可以把数据库恢复到以前某个时间点(或者说某个binlog的某个pos)。比如忘了带where条件的update、delete操作,传统的恢复方式是利用全备+二进制日志前滚进行恢复,相比于传统的全备+增备,flashback显然更为快速、简单。

目前MySQL的flashback功能是利用binlog完成的,第一个实现该功能的是阿里云的彭立勋, 他在MySQL 5.5版本上就已实现,并将其提交给MariaDB。

 

回到顶部

2. 闪回原理

原理:flashback工具(-B 参数)可对rows格式的binlog可以进行逆向操作,delete反向生成insert、update生成反向的update、insert反向生成delete。

MySQL的binlog以event的形式,记录了MySQL中所有的变更情况,利用binlog我们就能够重现所记录的所有操作。

MySQL引入binlog主要有两个用途/目的:一是为了主从复制;二是用于备份恢复后需要重新应用部分binlog,从而达到全备+增备的效果。

MySQL的binlog有三种格式:

  • statement,基于SQL语句的模式,一般来说生成的binlog尺寸较小,但是某些不确定性SQL语句或函数在复制过程可能导致数据不一致甚至出错;
  • row,基于数据行的模式,记录的是数据行的完整变化。相对更安全,推荐使用(但通常生成的binlog会比其他两种模式大很多);
  • mixed,混合模式,可以根据情况自动选用statement抑或row模式;这个模式下也可能造成主从数据不一致。它属于MySQL 5.1版本时期的过渡方案,已不推荐使用了。

注意:使用mysqlbinlog flashback 工具必须设置:binlog_format = row

 

回到顶部

3. flashback安装

下载flashback工具 mysqlbinlog : https://pan.baidu.com/s/1c1Ub1x2,并将mysqlbinlog文件移至mysql安装路径的bin目录下(可备份原来的mysqlbinlog为mysqlbinlog_bak),执行mysqlbinlog --help命令,可能会报错(系统版本为 rhel6.5,mysql5.7.22):

[root@centos64-slave1 bin]# mysqlbinlog --help

mysqlbinlog: /usr/lib64/libstdc++.so.6: version `GLIBCXX_3.4.15' not found (required by mysqlbinlog)

需要安装新版本的libstdc++.so.6,下载链接:https://pan.baidu.com/s/1gfIarCn 

[root@centos64-slave1 ~]# cp libstdc++.so.6.0.20  /usr/lib64/

[root@centos64-slave1 ~]# cd /usr/lib64/

[root@centos64-slave1 lib64]# mv libstdc++.so.6 libstdc++.so.6_bak

[root@centos64-slave1 lib64]# ln -s libstdc++.so.6.0.20 libstdc++.so.6

[root@centos64-slave1 lib64]# ll libstdc*

lrwxrwxrwx  1 root root      19 4月   6 09:30 libstdc++.so.6 -> libstdc++.so.6.0.20

-rwxr-xr-x. 1 root root  987096 7月  19 2013 libstdc++.so.6.0.13

-rw-r--r--  1 root root 1011824 4月   6 09:28 libstdc++.so.6.0.20

lrwxrwxrwx. 1 root root      19 1月  14 12:25 libstdc++.so.6_bak -> libstdc++.so.6.0.13

安装完后执行mysqlbinlog --help,若报错:mysqlbinlog: /lib64/libc.so.6: version `GLIBC_2.14' not found (required by /usr/lib64/libstdc++.so.6),需要更新/lib64库文件。下载链接:https://pan.baidu.com/s/1kViGrIZ

# tar zxvf  glibc-2.14.tar.gz

# cd glibc-2.14

# mkdir build

# cd build

# ../configure  --prefix=/opt/glibc-2.14

## 检查是否有问题。

# make  ## (4核可加-j4 ,8核可加-j8)

# make install

# strings libc.so | grep GLIBC   ## 这是我们需要的lib了,然后去更新系统的库

# cp libc.so  /lib64/libc-2.14.so

# mv /lib64/libc.so.6   /lib64/libc.so.6_bak

# LD_PRELOAD=/lib64/libc-2.14.so ln -s  /lib64/libc-2.14.so  /lib64/libc.so.6  

# strings /lib64/libc.so.6 | grep GLIBC

安装完成后执行:

[root@centos64-slave1 ~]# mysqlbinlog -V

mysqlbinlog Ver 3.4-InnoSQL for Linux at x86_64

[root@centos64-slave1 ~]# mysqlbinlog --help |grep flashback

  -B, --flashback     Flashback data to start_postition or start_datetime.

  -E, --fb-event=name only flashback this type of

flashback                         FALSE

发现mysqlbinlog版本已变为3.4-InnoSQL(之前的版本为3.4),且多了一个 -B 参数,此参数即用于实现flashback功能。到此,mysqlbinlog已安装完成!

 

回到顶部

4. 使用简介

先创建一张表user,向user表中插入一条数据,查看binlog日志内容,可以找到刚才插入的记录:

[root@service1 mysql]# mysqlbinlog -vv mysql-bin.000012

/*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=1*/;

/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/;

DELIMITER /*!*/;

# at 4

#180928  5:46:15 server id 117  end_log_pos 123 CRC32 0x14b8489c Start: binlog v 4, server v 5.7.22-log created 180928  5:46:15 at startup

# Warning: this binlog is either in use or was not closed properly.

ROLLBACK/*!*/;

BINLOG '

J8CtWw91AAAAdwAAAHsAAAABAAQANS43LjIyLWxvZwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

AAAAAAAAAAAAAAAAAAAnwK1bEzgNAAgAEgAEBAQEEgAAXwAEGggAAAAICAgCAAAACgoKKioAEjQA

AZxIuBQ=

'/*!*/;

# at 123

#180928  5:46:15 server id 117  end_log_pos 154 CRC32 0x83440acc Previous-GTIDs

# [empty]

# at 154

#180928  5:46:48 server id 117  end_log_pos 219 CRC32 0xed1fe71d Anonymous_GTID last_committed=0 sequence_number=1

SET @@SESSION.GTID_NEXT= 'ANONYMOUS'/*!*/;

# at 219

#180928  5:46:48 server id 117  end_log_pos 292 CRC32 0x2fbb1f1c Query thread_id=8 exec_time=0 error_code=0

SET TIMESTAMP=1538113608/*!*/;

SET @@session.pseudo_thread_id=8/*!*/;

SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=0, @@session.unique_checks=1, @@session.autocommit=1/*!*/;

SET @@session.sql_mode=1436549152/*!*/;

SET @@session.auto_increment_increment=1, @@session.auto_increment_offset=1/*!*/;

/*!\C utf8 *//*!*/;

SET @@session.character_set_client=33,@@session.collation_connection=33,@@session.collation_server=8/*!*/;

SET @@session.lc_time_names=0/*!*/;

SET @@session.collation_database=DEFAULT/*!*/;

然后使用flashback工具(-B参数)查看binlog内容,可以找到刚才插入记录的逆向操作:

[root@service1 mysql]# mysqlbinlog -vv mysql-bin.000012 -B

/*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=1*/;

/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/;

#180928  5:46:15 server id 117  end_log_pos 123 CRC32 0x14b8489c Start: binlog v 4, server v 5.7.22-log created 180928  5:46:15 at startup

# Warning: this binlog is either in use or was not closed properly.

ROLLBACK;

BINLOG '

J8CtWw91AAAAdwAAAHsAAAABAAQANS43LjIyLWxvZwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

AAAAAAAAAAAAAAAAAAAnwK1bEzgNAAgAEgAEBAQEEgAAXwAEGggAAAAICAgCAAAACgoKKioAEjQA

AZxIuBQ=

';

#180928  5:46:48 server id 117  end_log_pos 344 CRC32 0x4ae27e70 Table_map: `test1`.`test1` mapped to number 108

#180928  5:47:08 server id 117  end_log_pos 608 CRC32 0xa61492c0 Table_map: `test1`.`test1` mapped to number 108

#180928  7:01:34 server id 117  end_log_pos 872 CRC32 0xcf14deeb Table_map: `test1`.`test1` mapped to number 108

#180928  7:04:17 server id 117  end_log_pos 1136 CRC32 0xe7453269 Table_map: `test1`.`test1` mapped to number 108

#180928  7:22:43 server id 117  end_log_pos 1400 CRC32 0x63757563 Table_map: `test1`.`test1` mapped to number 108

#180928  7:22:43 server id 117  end_log_pos 1443 CRC32 0xd5dcdaa2 Write_rows: table id 108 flags: STMT_END_F

 

BINLOG '

w9atWxN1AAAANAAAAHgFAAAAAGwAAAAAAAEABXRlc3QxAAV0ZXN0MQACAw8CFAACY3V1Yw==

w9atWyB1AAAAKwAAAKMFAAAAAGwAAAAAAAEAAgAC//wWAAAAAjIyotrc1Q==

';

### DELETE FROM `test1`.`test1`

### WHERE

###   @1=22 /* INT meta=0 nullable=0 is_null=0 */

###   @2='22' /* VARSTRING(20) meta=20 nullable=1 is_null=0 */

#180928  7:04:17 server id 117  end_log_pos 1179 CRC32 0x7ca5a22c Write_rows: table id 108 flags: STMT_END_F

 

BINLOG '

cdKtWxN1AAAANAAAAHAEAAAAAGwAAAAAAAEABXRlc3QxAAV0ZXN0MQACAw8CFAACaTJF5w==

cdKtWyB1AAAAKwAAAJsEAAAAAGwAAAAAAAEAAgAC//wVAAAAAjIxLKKlfA==

';

### DELETE FROM `test1`.`test1`

### WHERE

###   @1=21 /* INT meta=0 nullable=0 is_null=0 */

###   @2='21' /* VARSTRING(20) meta=20 nullable=1 is_null=0 */

#180928  7:01:34 server id 117  end_log_pos 915 CRC32 0x424ea423 Write_rows: table id 108 flags: STMT_END_F

 

BINLOG '

ztGtWxN1AAAANAAAAGgDAAAAAGwAAAAAAAEABXRlc3QxAAV0ZXN0MQACAw8CFAAC694Uzw==

ztGtWyB1AAAAKwAAAJMDAAAAAGwAAAAAAAEAAgAC//wUAAAAAjIwI6ROQg==

';

### DELETE FROM `test1`.`test1`

### WHERE

###   @1=20 /* INT meta=0 nullable=0 is_null=0 */

###   @2='20' /* VARSTRING(20) meta=20 nullable=1 is_null=0 */

#180928  5:47:08 server id 117  end_log_pos 651 CRC32 0x5fb25f3a Write_rows: table id 108 flags: STMT_END_F

 

BINLOG '

XMCtWxN1AAAANAAAAGACAAAAAGwAAAAAAAEABXRlc3QxAAV0ZXN0MQACAw8CFAACwJIUpg==

XMCtWyB1AAAAKwAAAIsCAAAAAGwAAAAAAAEAAgAC//wTAAAAAjE5Ol+yXw==

';

### DELETE FROM `test1`.`test1`

### WHERE

###   @1=19 /* INT meta=0 nullable=0 is_null=0 */

###   @2='19' /* VARSTRING(20) meta=20 nullable=1 is_null=0 */

#180928  5:46:48 server id 117  end_log_pos 387 CRC32 0x3ce57804 Write_rows: table id 108 flags: STMT_END_F

 

BINLOG '

SMCtWxN1AAAANAAAAFgBAAAAAGwAAAAAAAEABXRlc3QxAAV0ZXN0MQACAw8CFAACcH7iSg==

SMCtWyB1AAAAKwAAAIMBAAAAAGwAAAAAAAEAAgAC//wSAAAAAjE4BHjlPA==

';

### DELETE FROM `test1`.`test1`

### WHERE

###   @1=18 /* INT meta=0 nullable=0 is_null=0 */

###   @2='18' /* VARSTRING(20) meta=20 nullable=1 is_null=0 */

DELIMITER ;

# End of log file

/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;

/*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=0*/;

同理,delete操作将会被转换为insert,update被转换为反向的update;若在一个事务中既有insert、update、delete语句,通过使用-B参数后,不仅三种DML语句完成了逆向转换,并且语句顺序也会发生颠倒。

在binlog中找到误操作的pos变化区间后,使用mysqlbinlog -B 恢复:

[root@service1 mysql]# mysqlbinlog -B --start-position=1179 --stop-position=1474 mysql-bin.000012 | mysql -uroot -p

Enter password:

[root@service1 mysql]#

 

Note:恢复时,可主库mysql> show master status;

+------------------+----------+--------------+------------------+-------------------+

| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |

+------------------+----------+--------------+------------------+-------------------+

| mysql-bin.000012 |     1474 |              |                  |                   |

+------------------+----------+--------------+------------------+-------------------+

1 row in set (0.01 sec)

 

 

回到顶部

5. Flashback工具使用注意点

  • binlog日志格式必须是ROW格式:binlog_format = row ;
  • 一个事务中的DML语句不仅会逆向转换,并且语句顺序也会发生颠倒;
  • 只支持 insert、update、delete , 不支持drop 、truncate、alter等DDL语句。

 

回到顶部

美团点评又出了另一款闪回工具MyFlash,据说比 mysqlbinlog 具有更高效的闪回效果,项目地址:https://github.com/Meituan-Dianping/MyFlash