南大通用GBase 8a通过非正常手段恢复最后一次误删的数据

GBase 8a本身没有回收站功能,被删除的数据是不能通过SQL命令直接恢复的。本文介绍一种非正常手段,用来【尝试】恢复最后一次删除的数据。

警告

本操作属于非正常手段:
如果你有备份,请用备份恢复
如果你能重新录入数据,请重新录入

另外本操作如果手工操作失误,可能导致当前数据主副本不一致,或者数据状态不对,从而影响后续使用,所以只有在丢失的数据极其重要时,考虑的一个【尝试性】方案。

前提

该表做完delete后,没有其它的DML,DDL等操作。否则数据已经改动了,你恢复的最后一次,可能不再是你认为的【最后一次】。

集群

2节点集群

[root@rh6-1 ~]# gcadmin
CLUSTER STATE:  ACTIVE
CLUSTER MODE:   NORMAL

=================================================================
|             GBASE COORDINATOR CLUSTER INFORMATION             |
=================================================================
|   NodeName   |     IpAddress     |gcware |gcluster |DataState |
-----------------------------------------------------------------
| coordinator1 |    10.0.2.201     | OPEN  |  OPEN   |    0     |
-----------------------------------------------------------------
=============================================================
|              GBASE DATA CLUSTER INFORMATION               |
=============================================================
|NodeName |     IpAddress     |gnode |syncserver |DataState |
-------------------------------------------------------------
|  node1  |    10.0.2.201     | OPEN |   OPEN    |    0     |
-------------------------------------------------------------
|  node2  |    10.0.2.202     | OPEN |   OPEN    |    0     |
-------------------------------------------------------------

测试表

一张单列的表

gbase> create table tt(id int);
Query OK, 0 rows affected (Elapsed: 00:00:00.28)

测试数据

插入3行数据。

gbase> select * from tt;
Empty set (Elapsed: 00:00:00.01)

gbase> insert into tt values(1),(2),(3);
Query OK, 3 rows affected (Elapsed: 00:00:00.16)
Records: 3  Duplicates: 0  Warnings: 0

gbase> select * from tt;
+------+
| id   |
+------+
|    1 |
|    2 |
|    3 |
+------+
3 rows in set (Elapsed: 00:00:00.01)

删除数据

通过delete删除一行数据。

gbase> delete tt where id=1;
Query OK, 1 row affected (Elapsed: 00:00:00.23)

gbase> select * from tt;
+------+
| id   |
+------+
|    2 |
|    3 |
+------+
2 rows in set (Elapsed: 00:00:00.01)

建议备份

在尝试恢复前,建议对表的当前可用数据做备份。如果手工恢复出问题了,最多就是真的丢失了被删除的数据。

create table tt_bak like tt;
insert into tt_bak select * from tt;

如果恢复失败,可以通过如下步骤恢复备份

rename table tt to tt_BAD;
rename table tt_bak to tt;

尝试恢复被删除的数据

如下操作【有可能】要在每个节点执行,这涉及到你删除的数据,到底影响了哪些分片。只有有数据被本次删除的分片,才需要恢复。如果不涉及到本次删除的分片被操作了,那么可能回退到了一个你无法确认的状态了。

获得数据节点的分片号

其中的IP是主节点,后面的segment ID就是分片号。比如针对tt表,在10.0.2.202上,分片号是1,其分片表的名字就是 tt_n1。在10.0.2.210上,分片表的名字就是tt_n2。

后面的duplicate是备份表所在IP,分片名字和主分片是一样的。

[root@rh6-1 ~]# gcadmin showdistribution

              Distribution ID: 2 | State: new | Total segment num: 2

     Primary Segment Node IP                           Segment ID         Duplicate Segment node IP
========================================================================================================================
|    10.0.2.202                                  |       1          |    10.0.2.201                                    |
------------------------------------------------------------------------------------------------------------------------
|    10.0.2.201                                  |       2          |    10.0.2.202                                    |
========================================================================================================================
[root@rh6-1 ~]#

查看数据节点的每个分片信息

通过information_schema.tables表,拿到该节点的分片的SCN号和最后更新信息。 需要根据update_time,判断最后删除操作,是否涉及了这个分片。

如下的输出,tt_n1的更新时间是14:20:33,而tt_n2是14:20:11,可以看出上次的delete操作,只影响了n1分片,而没有影响n2分片。对于多个数据节点的集群,每个分片都要检查一次,找到上次delete影响的分片号。

注意,各个节点的【时钟】如果不同,且表的DML操作很频繁,则【非常容易】出现【误判】,导致恢复失败。

[gbase@rh6-1 ~]$ gncli testdb

GBase client 8.6.2.43-R28 .125499. Copyright (c) 2004-2021, GBase.  All Rights Reserved.

gbase> select scn,UPDATE_TIME from information_schema.tables where table_name='tt_n1';
+---------+---------------------+
| scn     | UPDATE_TIME         |
+---------+---------------------+
| 5242933 | 2021-06-17 14:20:33 |
+---------+---------------------+
1 row in set (Elapsed: 00:00:00.00)

gbase> select now();
+---------------------+
| now()               |
+---------------------+
| 2021-06-17 14:21:11 |
+---------------------+
1 row in set (Elapsed: 00:00:00.00)

gbase> select scn,UPDATE_TIME from information_schema.tables where table_name='tt_n2';
+---------+---------------------+
| scn     | UPDATE_TIME         |
+---------+---------------------+
| 5242931 | 2021-06-17 14:20:11 |
+---------+---------------------+
1 row in set (Elapsed: 00:00:00.00)

gbase>

尝试回退该分片

再次声明:该操作如果评估错误,将导致数据内容处于一个不可知的状态。

根据测试的2节点集群,n1分片需要恢复,通过如下的revert语句,尝试恢复。

可以看到,tt_n1表,被删除的id=1的数据回来了。查看tables表,可以看到scn从 5242933 减少到了5242932。

[gbase@rh6-1 ~]$ gncli -h10.0.2.202 testdb

GBase client 8.6.2.43-R28 .125499. Copyright (c) 2004-2021, GBase.  All Rights Reserved.

gbase> select * from testdb.tt_n1;
+------+
| id   |
+------+
|    2 |
|    3 |
+------+
2 rows in set (Elapsed: 00:00:00.00)

gbase> revert table testdb.tt_n1 scn_number 5242933;
Query OK, 0 rows affected (Elapsed: 00:00:00.04)

gbase> select * from testdb.tt_n1;
+------+
| id   |
+------+
|    1 |
|    2 |
|    3 |
+------+
3 rows in set (Elapsed: 00:00:00.00)

gbase> select scn,UPDATE_TIME from information_schema.tables where table_name='tt_n1';
+---------+---------------------+
| scn     | UPDATE_TIME         |
+---------+---------------------+
| 5242932 | 2021-06-17 14:20:21 |
+---------+---------------------+
1 row in set (Elapsed: 00:00:00.00)

针对副本,也要做相同的操作

[gbase@rh6-1 ~]$ gncli -h10.0.2.201 testdb

GBase client 8.6.2.43-R28 .125499. Copyright (c) 2004-2021, GBase.  All Rights Reserved.

gbase> select * from testdb.tt_n1;
+------+
| id   |
+------+
|    2 |
|    3 |
+------+
2 rows in set (Elapsed: 00:00:00.01)

gbase> revert table testdb.tt_n1 scn_number 5242933;
Query OK, 0 rows affected (Elapsed: 00:00:00.04)

gbase> select * from testdb.tt_n1;
+------+
| id   |
+------+
|    1 |
|    2 |
|    3 |
+------+
3 rows in set (Elapsed: 00:00:00.00)

gbase>

回到集群查询验证

可以看到被我们删除的id=1的数据已经恢复了。

[gbase@rh6-1 ~]$ gccli testdb

GBase client 8.6.2.43-R28 .125499. Copyright (c) 2004-2021, GBase.  All Rights Reserved.

gbase> select * from testdb.tt;
+------+
| id   |
+------+
|    1 |
|    2 |
|    3 |
+------+
3 rows in set (Elapsed: 00:00:00.02)

意外处理

如果前面的revert弄错了,你可以通过revert再回退到最新的版本,这个revert你可以理解成【切换】的意思。但如果多个分片,切换错了,那么数据就会处于一种未知的状态了。

[gbase@rh6-1 ~]$ gncli -h10.0.2.202 testdb

GBase client 8.6.2.43-R28 .125499. Copyright (c) 2004-2021, GBase.  All Rights Reserved.

gbase> select * from testdb.tt_n1;
+------+
| id   |
+------+
|    1 |
|    2 |
|    3 |
+------+
3 rows in set (Elapsed: 00:00:00.00)

gbase> select scn,UPDATE_TIME from information_schema.tables where table_name='tt_n1';
+---------+---------------------+
| scn     | UPDATE_TIME         |
+---------+---------------------+
| 5242932 | 2021-06-17 14:20:21 |
+---------+---------------------+
1 row in set (Elapsed: 00:00:00.00)

gbase> revert table testdb.tt_n1 scn_number 5242932;
Query OK, 0 rows affected (Elapsed: 00:00:00.03)

gbase> select scn,UPDATE_TIME from information_schema.tables where table_name='tt_n1';
+---------+---------------------+
| scn     | UPDATE_TIME         |
+---------+---------------------+
| 5242933 | 2021-06-17 14:20:33 |
+---------+---------------------+
1 row in set (Elapsed: 00:00:00.01)

gbase> select * from testdb.tt_n1;
+------+
| id   |
+------+
|    2 |
|    3 |
+------+
2 rows in set (Elapsed: 00:00:00.00)