tidb 误删库,表,数据恢复

张映 发表于 2021-10-21

分类目录: tidb

标签:, ,

在数据库没有备份的情况,tidb有没有办法做到,误删数据后的恢复。

一,recover,flashback方法

1,recover,flashback恢复表的原理

TiDB 在删除表时,实际上只删除了表的元信息,并将需要删除的表数据范围(行数据和索引数据)写一条数据到 mysql.gc_delete_range 表。TiDB 后台的 GC Worker 会定期从 mysql.gc_delete_range 表中取出超过 GC lifetime 相关范围的 key 进行删除。

所以,RECOVER TABLE 只需要在 GC Worker 还没删除表数据前,恢复表的元信息并删除 mysql.gc_delete_range 表中相应的行记录就可以了。恢复表的元信息可以用 TiDB 的快照读实现,TiDB 中表的恢复是通过快照读获取表的元信息后,再走一次类似于 CREATE TABLE 的建表流程,所以 RECOVER TABLE 实际上也是一种 DDL。

只能用来恢复误删除表的 DDL 操作,例如 truncate table,delete 操作没有办法恢复。
只能在 GC 回收数据之前完成,超过 GC 时间后会报错无法成功恢复。
如果在使用 binlog 的情况下,上游执行 recover table 可能会出现一些非预期的结果。例如下游是 MySQL 数据库,对于这个语法不兼容。上下游的 GC 策略配置不同,再加上复制延迟可能会引起下游的数据在 apply recover table 的时候已经被 GC 了从而导致语句执行失败。

Flashback 的原理和 Recover table 比较类似,不过是 recover 的升级版,在覆盖 recover 的所有功能之外,还可以支持 truncate table 的操作,未来也会逐渐取代 recover 命令。下面是简单的使用示例,其他不再累述。

归纳一下,recover只针对drop table的恢复。flashback可以drop table,truncate table进行恢复,但是对truncate table进行恢复时,不能是同一个表。

2,demo演示

mysql> create database tank_3;
Query OK, 0 rows affected (0.84 sec)

mysql> use tank_3;
Database changed
mysql> CREATE TABLE `test` (
    ->   `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
    ->   `name` varchar(30) DEFAULT NULL COMMENT '姓名',
    ->   `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
    ->   PRIMARY KEY (`id`)
    -> ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin AUTO_INCREMENT=1 COMMENT='测试';
Query OK, 0 rows affected (0.88 sec)

mysql> insert into test(name)values('tank1'),('tank2');
Query OK, 2 rows affected (0.20 sec)
Records: 2  Duplicates: 0  Warnings: 0

mysql> select * from test;
+----+-------+---------------------+
| id | name  | create_time         |
+----+-------+---------------------+
|  1 | tank1 | 2021-10-21 11:27:27 |
|  2 | tank2 | 2021-10-21 11:27:27 |
+----+-------+---------------------+
2 rows in set (0.00 sec)

mysql> drop table test;
Query OK, 0 rows affected (1.25 sec)

mysql> recover table test;   //恢复表
Query OK, 0 rows affected (3.41 sec)

mysql> CREATE TABLE `test` (
    ->   `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
    ->   `name` varchar(30) DEFAULT NULL COMMENT '姓名',
    ->   `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
    ->   PRIMARY KEY (`id`)
    -> ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin AUTO_INCREMENT=1 COMMENT='测试';
Query OK, 0 rows affected (0.88 sec)

mysql> insert into test(name)values('tank1'),('tank2');
Query OK, 2 rows affected (0.23 sec)
Records: 2  Duplicates: 0  Warnings: 0

mysql> truncate table test;
Query OK, 0 rows affected (1.21 sec)

mysql> flashback table test to test1; //恢复数据到test1,test1不需要提前建好
Query OK, 0 rows affected (2.74 sec)

二,快照恢复法

1,修改gc的生存时间

mysql> select VARIABLE_NAME, VARIABLE_VALUE from mysql.tidb where VARIABLE_NAME like 'tikv_gc%';
+--------------------------+-----------------------------------------------------------------------------------------+
| VARIABLE_NAME            | VARIABLE_VALUE                                                                          |
+--------------------------+-----------------------------------------------------------------------------------------+
| tikv_gc_leader_uuid      | 5f0949a74440001                                                                         |
| tikv_gc_leader_desc      | host:testpd, pid:4052, start at 2021-09-27 10:47:40.056042874 +0800 CST m=+40.425507593 |
| tikv_gc_leader_lease     | 20211021-11:04:41 +0800                                                                 |
| tikv_gc_enable           | true                                                                                    |
| tikv_gc_run_interval     | 10m0s                                                                                   |
| tikv_gc_life_time        | 10m0s                                                                                   |
| tikv_gc_last_run_time    | 20211021-10:58:41 +0800                                                                 |
| tikv_gc_safe_point       | 20211021-10:48:41 +0800                                                                 |
| tikv_gc_auto_concurrency | true                                                                                    |
| tikv_gc_mode             | distributed                                                                             |
+--------------------------+-----------------------------------------------------------------------------------------+
10 rows in set (0.01 sec)

mysql> update mysql.tidb set VARIABLE_VALUE="24h" where VARIABLE_NAME="tikv_gc_life_time" ;
Query OK, 1 row affected (0.14 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> select VARIABLE_NAME, VARIABLE_VALUE from mysql.tidb where VARIABLE_NAME like 'tikv_gc%';
+--------------------------+-----------------------------------------------------------------------------------------+
| VARIABLE_NAME            | VARIABLE_VALUE                                                                          |
+--------------------------+-----------------------------------------------------------------------------------------+
| tikv_gc_leader_uuid      | 5f0949a74440001                                                                         |
| tikv_gc_leader_desc      | host:testpd, pid:4052, start at 2021-09-27 10:47:40.056042874 +0800 CST m=+40.425507593 |
| tikv_gc_leader_lease     | 20211021-11:31:41 +0800                                                                 |
| tikv_gc_enable           | true                                                                                    |
| tikv_gc_run_interval     | 10m0s                                                                                   |
| tikv_gc_life_time        | 24h                                                                                     |
| tikv_gc_last_run_time    | 20211021-11:18:41 +0800                                                                 |
| tikv_gc_safe_point       | 20211021-11:08:41 +0800                                                                 |
| tikv_gc_auto_concurrency | true                                                                                    |
| tikv_gc_mode             | distributed                                                                             |
+--------------------------+-----------------------------------------------------------------------------------------+
10 rows in set (0.01 sec)

TiDB 使用周期性运行的 GC(Garbage Collection,垃圾回收)来进行清理,默认情况下每 10 分钟一次。每次 GC 时,TiDB 会计算一个称为 safe point 的时间戳(默认为上次运行 GC 的时间减去 10 分钟),接下来 TiDB 会在保证在 safe point 之后的快照都能够读取到正确数据的前提下,删除更早的过期数据。

快照模式具有通用性,不管是删库,删表,改字段,删改数据都可以恢复,但是有个前提就是即时发现。在下一个GC来临之前,拉长gc生存时间,拉长后就算gc来了,上一个没结束,也不会删除数据。

用快照模式进行恢复时,恢复前最好是把读取和写入都停掉。

2,删除测试

mysql> insert into test(name)values('tank1'),('tank2');
Query OK, 2 rows affected (0.23 sec)

mysql> delete from test;
Query OK, 2 rows affected (0.15 sec)

mysql> select @@tidb_snapshot;
+-----------------+
| @@tidb_snapshot |
+-----------------+
|                 |
+-----------------+
1 row in set (0.00 sec)

mysql> set @@tidb_snapshot="2021-10-21 11:44:25";
Query OK, 0 rows affected (3.12 sec)

mysql> select * from test1;
+-------+-------+---------------------+
| id    | name  | create_time         |
+-------+-------+---------------------+
| 30001 | tank1 | 2021-10-21 11:43:21 |
| 30002 | tank2 | 2021-10-21 11:43:21 |
+-------+-------+---------------------+
2 rows in set (0.01 sec)

3,导出与导入

//导出
mydumper -h ip -P port -u username -p xxxx --tidb-snapshot '2021-10-21 11:44:25' -t 16 -F 64 --skip-tz-utc -B dbname -T table1,table2 -o directory

dumpling -h ip -P port -u username -p xxxx --consistency snapshot --snapshot '2021-10-21 11:44:25' --threads 32 --filetype sql -o directoy -F '64MiB' -T db.table1,db.table2

mysql> set @@tidb_snapshot="";
Query OK, 0 rows affected (0.00 sec)

//导入
myloader -h ip -u root -p xxx -P 4000 -t 32 -d directory

这块要注意顺序,恢复到某一快照后,然后导出数据,导出后在取消快照,是否直接导入,还是程序的方式导入,具体方式具体对待。

 



转载请注明
作者:海底苍鹰
地址:http://blog.51yip.com/tidb/2541.html