社区所有版块导航
Python
python开源   Django   Python   DjangoApp   pycharm  
DATA
docker   Elasticsearch  
aigc
aigc   chatgpt  
WEB开发
linux   MongoDB   Redis   DATABASE   NGINX   其他Web框架   web工具   zookeeper   tornado   NoSql   Bootstrap   js   peewee   Git   bottle   IE   MQ   Jquery  
机器学习
机器学习算法  
Python88.com
反馈   公告   社区推广  
产品
短视频  
印度
印度  
Py学习  »  NoSql

InnoSQL/MySQL DDL Flashback功能简介

网易云社区 • 5 年前 • 650 次点击  

作者:网易数据库团队

在《删库不跑路!数据库误删有几种恢复方式?》一文中,我们曾提到处理数据库误删除的几种方法,其中一种是数据闪回(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记录清理提示信息。

本文转载自:InnoSQL/MySQL DDL Flashback功能简介

Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/30924
 
650 次点击