绑定完请刷新页面
取消
刷新

分享好友

×
取消 复制
InnoSQL/MySQL DDL Flashback功能简介
2020-01-14 11:30:39

浅谈数据库误删除恢复

在文章中,曾提到处理数据库误删除的几种方法,其中一种是数据闪回(flashback),目前我们在开源实现的基础上,对ddl flashback方案进行了优化,解决了其存在的兼容性等问题。现对其进行简单介绍。

该文由组内小伙伴原创,略做修改。


背景需求

Flashback概念早出自Oracle,用于快速恢复用户的误操作,Flashback for MySQL是由阿里彭立勋于2012-5-2贡献的patch给MySQL官方5.5.18版本,此版本基于mysqlbinlog工具通过-B,--flashback参数对binlog中的DML逆操作生成闪回日志进行恢复,但此版本不支持DDL flashback。

随后2012-7-10阿里林晓斌贡献的patch支持DDL flashback,原理是通过rename的方式备份数据表,并增加FLASHBACK_EVENT event类型记录rename后的statement信息,通过mysqlbinlog工具-B,--flashback参数生成闪回log进行恢复。

DDL flashback版本存在三个问题:

  1. 兼容性问题:引入了新的event类型FLASHBACK_EVENT,如果是主从复制场景,从库MySQL的版本未引入DDL flashback 功能时,从库回放relay-log时会因解析不了FLASHBACK_EVENT event而造成复制中断。
  2. 可维护性:回收库#bak_database的创建是写在系统库脚本中,随着mysqld的初始化进行创建,未记录binlog,同样如果从库版本没有引入DDL flashback功能,那么复制过来的rename语句会因为不存在#bak_database库而执行失败,造成主从不一致。
  3. 垃圾清理:#bak_database备份库没有进行垃圾回收,会造成磁盘空间冗余占用。

为此我们在InnoSQL 5.7和8.0版本上对DDL Flashback进行了优化改进,解决了上述问题,目前暂时支持drop/truncate两个常用的删除数据的操作,下面将简单介绍实现原理。

实现原理

总体思想是回收站原理,通过rename的方式将drop/truncate的表数据迁移至备库#bak_database中,通过mysqlbinlog工具-B,--flashback参数生成回滚语句进行数据恢复,并在mysqld启动时新增drop_flashback_table自动清理线程,定期自动清理#bak_database中的过期的备份数据,防止磁盘空间冗余占用。下面从这三部分功能的实现进行说明。

数据备份

在MySQL server层修改mysql_execute_command()函数中执行drop/truncate部分的代码,首先判断全局变量is_bak_database_created,如果为true,则说明#bak_database已经被创建,其他DDL操作直接使用备库,否则在DDL执行前先通过“CREATE DATABASE IF NOT EXISTS `#bak_database`”创建备库,这种方式可以通过主从复制同步到从库,这样避免了前述的问题2。

继续判断如果开启sql_flashback,则把执行语句修改成rename操作将数据备份到#bak_database库中,同时将对应的回滚语句通过注释的方式一起记录binlog,如下图1-3中黄色部分,分别列出了drop/truncate语句对应的binlog记录中rename操作和回滚操作内容。

图1 truncate table语句binlog记录

图2 drop table语句binlog记录

图3 drop database语句binlog记录

数据恢复

通过mysqlbinlog工具-B,--flashback参数生成回滚语句进行数据恢复,-B参数是继承DML闪回实现版本,在打印binlog内容的函数Query_log_event::print中增加判断,如果mysqlbinlog开启-B参数并且event类型是QUERY_EVENT时,则解析/* FLASHBACK:xxxx */部分的内容,输出回滚语句进行数据恢复。

这样没有新增event类型,回滚操作通过记录在rename操作binlog注释/**/中,并通过mysqlbinlog解析来完成。避免了前述的问题1。

清理数据

在启动mysqld的过程中,新增drop_flashback_table线程,通过循环查询information_schema.tables中信息判断#bak_database库中是否存在备份表,如果存在,并且备份表的时间戳大于当前系统变量drop_flashback_timeout设置的过期清理时间,则对备份表执行drop操作进行清理,防止磁盘空间冗余占用。避免了前述的问题3。

参数说明

sql_flashback

开启/关闭DDL(drop/truncate)闪回功能,如:set sql_flashback = on/off,默认关闭,提供global和session 2个维度。并通过mysqlbinlog -B生成DDL回滚语句进行闪回。

例1:

create table test(a int);
insert into test values(1);
flush logs;
set sql_flashback=on;
drop table test;
mysqlbinlog -B mysql-bin.000003 > fb.sql

drop_flashback_timeout

设置备份库#bak_database中数据的过期时间,如:

set global drop_flashback_timeout=60; 

默认过期时间是48小时,过期后备份数据将会被自动清理,可设置过期时间范围1min~365days。

例2:过期清理前#bak_database中的备份表。

客户端设置过期时间

set global drop_flashback_timeout=60; 

60s后看过期表已经被清理。

mysql-err.log记录清理提示信息。

分享好友

分享这个小栈给你的朋友们,一起进步吧。

数据库内核开发
创建时间:2019-12-11 16:43:06
网易数据库内核技术专家 8年多数据库和存储系统开发经验,《MySQL内核:InnoDB存储引擎 卷1》作者之一,申请技术专利10+,已授权5+。曾主导了网易公有云RDS、MongoDB等数据库云服务建设 现负责网易MySQL分支InnoSQL开发和维护。专注于数据库内核技术和分布式系统架构,擅长分析解决疑难问题。
展开
订阅须知

• 所有用户可根据关注领域订阅专区或所有专区

• 付费订阅:虚拟交易,一经交易不退款;若特殊情况,可3日内客服咨询

• 专区发布评论属默认订阅所评论专区(除付费小栈外)

栈主、嘉宾

查看更多
  • 温正湖
    栈主

小栈成员

查看更多
  • xzh1980
  • else
  • Jack2k
  • at_1
戳我,来吐槽~