Native Flashback功能可以通过SQL语句查询或恢复指定时间点的数据,保证在误操作后可以快速获取历史数据。

功能说明

数据库运维过程中的误操作可能会给业务带来严重的影响,常见的恢复手段Binlog Flashback操作较为复杂、容易出错且耗时较长,而通过备份集恢复则需要额外的系统资源,在数据量较大时恢复时间不可控。

AliSQL在InnoDB引擎上设计和实现了Native Flashback功能,无需复杂的恢复操作,通过简单的SQL语句即可查询或恢复误操作前的历史数据,节省了大量宝贵的时间,保证业务平稳运行。

前提条件

  • 实例为RDS MySQL 8.0基础版或高可用版。
  • 内核小版本为20210930及以上。如何查看或升级内核小版本,请参见升级内核小版本

注意事项

  • 仅支持使用InnoDB引擎的表。
  • 需要消耗额外的undo表空间,可以通过INNODB_UNDO_SPACE_SUPREMUM_SIZE参数进行配置。
  • Native Flashback的查询结果取最接近指定时间点的数据,不保证查询到的数据与指定时间点的数据完全匹配。
  • 暂不支持跨DDL操作的历史版本数据查询和恢复。例如您无法通过Native Flashback查询某个已经被删除的表的内容。

语法

Native Flashback提供了全新的AS OF语法,通过该语法指定需要回滚的时间。语法规则如下:

SELECT ... FROM <表名>
  AS OF TIMESTAMP <表达式>;

其中,在表达式中指定回滚的时间,该表达式支持多种形式,示例:

SELECT ... FROM tablename
  AS OF TIMESTAMP '2020-11-11 00:00:00';

SELECT ... FROM tablename
  AS OF TIMESTAMP now();

SELECT ... FROM tablename
  AS OF TIMESTAMP (SELECT now());

SELECT ... FROM tablename
  AS OF TIMESTAMP DATE_SUB(now(), INTERVAL 1 minute);

参数说明

Native Flashback功能开放了如下可配置参数:

参数名称 说明
INNODB_RDS_FLASHBACK_TASK_ENABLED
  • 描述:Native Flashback的功能开关。
  • 命令行格式:--innodb-rds-flashback-task-enabled=#
  • 参数范围:全局参数。
  • 数据类型:Boolean。
  • 默认值:OFF。
  • 取值范围:[ON|OFF]。
INNODB_UNDO_RETENTION
  • 描述:undo记录的保留时长,超出该时长的undo记录无法查询,单位:秒。
    说明 该参数的值越大,Native Flashback支持的回档查询时间越长,同时undo表空间占用的存储空间也会上升。
  • 命令行格式:--innodb-undo-retention=#
  • 参数范围:全局参数。
  • 数据类型:Integer。
  • 默认值:0。
  • 取值范围:0~4294967295。
INNODB_UNDO_SPACE_SUPREMUM_SIZE
  • 描述:undo表空间可占用的最大磁盘空间,单位:MB。占用空间超过这个值时,忽略INNODB_UNDO_RETENTION参数强制清理undo记录。
  • 命令行格式:--innodb-undo-space-supremum-size=#
  • 参数范围:全局参数。
  • 数据类型:Integer。
  • 默认值:102400。
  • 取值范围:0~4294967295。
INNODB_UNDO_SPACE_RESERVED_SIZE
  • 描述:预留的undo表空间大小,单位:MB。在INNODB_UNDO_RETENTION参数非0的情况下,将使用这部分空间尽可能多地保留undo记录。
  • 命令行格式:--innodb-undo-space-reserved-size=#
  • 参数范围:全局参数。
  • 数据类型:Integer。
  • 默认值:0。
  • 取值范围:0~4294967295。

使用示例

# 获取时间点
MySQL [mytest]> select now();
+---------------------+
| now()               |
+---------------------+
| 2020-10-14 15:44:09 |
+---------------------+
1 row in set (0.00 sec)

# 查看数据
MySQL [mytest]> select * from mt1;
+----+------+
| id | c1   |
+----+------+
|  1 |    1 |
|  2 |    2 |
|  3 |    3 |
|  4 |    4 |
|  5 |    5 |
+----+------+
5 rows in set (0.00 sec)

# 不带WHERE条件的更新操作
MySQL [mytest]> update mt1 set c1 = 100;
Query OK, 5 rows affected (0.00 sec)
Rows matched: 5  Changed: 5  Warnings: 0

MySQL [mytest]> select * from mt1;
+----+------+
| id | c1   |
+----+------+
|  1 |  100 |
|  2 |  100 |
|  3 |  100 |
|  4 |  100 |
|  5 |  100 |
+----+------+
5 rows in set (0.00 sec)

# 查询历史时间点的数据,成功返回结果
MySQL [mytest]> select * from mt1 AS OF timestamp '2020-10-14 15:44:09';
+----+------+
| id | c1   |
+----+------+
|  1 |    1 |
|  2 |    2 |
|  3 |    3 |
|  4 |    4 |
|  5 |    5 |
+----+------+
5 rows in set (0.00 sec)

# 如果超出保留的历史数据范围,返回失败
MySQL [mytest]> select * from mt1 AS OF timestamp '2020-10-13 14:44:09';
ERROR 7545 (HY000): The snapshot to find is out of range

# 开始恢复数据
MySQL [mytest]> create table mt1_tmp like mt1; # 创建一个与原表结构相同的临时表
Query OK, 0 rows affected (0.03 sec)  
MySQL [mytest]> insert into mt1_tmp
             -> select * from mt1 AS OF
             -> TIMESTAMP '2020-10-14 15:44:09'; # 将原表中的历史数据写入临时表 
Query OK, 5 rows affected (0.01 sec) 
Records: 5  Duplicates: 0  Warnings: 0 
MySQL [mytest]> select * from mt1_tmp; # 确认临时表中的数据是否正确 
+----+------+
| id | c1   |
+----+------+
|  1 |    1 |
|  2 |    2 |
|  3 |    3 |
|  4 |    4 |
|  5 |    5 |
+----+------+
5 rows in set (0.00 sec) 
MySQL [mytest]> rename table mt1 to mt1_bak,
             -> mt1_tmp to mt1; #(进行本操作需要先停止业务读写)更改原表表名为mt1_bak,并将临时表名改成原表表名,完成数据恢复
Query OK, 0 rows affected (0.02 sec)
MySQL [mytest]> select * from mt1; # 确认恢复完成后的数据 
+----+------+
| id | c1   |
+----+------+
|  1 |    1 |
|  2 |    2 |
|  3 |    3 |
|  4 |    4 |
|  5 |    5 |
+----+------+ 
5 rows in set (0.01 sec)