南大通用GBase 8a 通过物理文件操作实现表备份还原的方法

1. 概述

GBase 数据库当前的备份恢复工具,需要锁集群只读状态,无法满足一些场景的需求。本文通过物理文件备份方式,对表级备份恢复提供一种解决方案,一些限制和说明请参考总结部分。

1.1. 目标

通过物理文件的操作实现表数据的备份和还原。

  • 备份数据完整性,表在还原后可正常使用
  • 不影响非备份表的正常使用

1.2. 名词和约定

1.2.1. DbaUser

指数据库运行的【操作系统】用户,一般是gbase,后续全部用gbase做样例。

1.2.2. 安装目录

指数据库安装的具体目录。可以从环境变量里获得。比如

[root@rh6-1 ~]# cat /home/gbase/.gbase_profile |grep GCLUSTER_BASE=
export GCLUSTER_BASE=/opt/gcluster

[root@rh6-1 ~]# cat /home/gbase/.gbase_profile |grep GBASE_BASE=
export GBASE_BASE=/opt/gnode

表示安装目录是 /opt,后面例子我们也用这个目录作为安装目录演示。

1.2.3. 调度节点和计算节点

调度节点指 coordinator 服务节点,对应的目录为/opt/gcluster
计算/数据节点指 node服务节点,对应的目录为/opt/gnode

在GBase 8a里,调度节点只有表结构,不保存具体数据,所以备份时,只需要处理计算节点即可。

如下是gcadmin的输出,其中红色部分是调度节点,黄色部分是计算节点

后续例子,以这2节点集群为例。

1.2.4. 库文件

在计算节点里,库文件保存在库名相同的目录下

/opt/gnode/userdata/gbase/库名

后面例子中我们用testdb库做演示

/opt/gnode/userdata/gbase/testdb

1.2.5. 元数据目录和数据目录

在GBase 里,表数据分成2部分,其中

元数据保存路径为:/opt/gnode/userdata/gbase/testdb/metadata
数据保存路径为:/opt/gnode/userdata/gbase/testdb/sys_tablespace

1.2.6. 表和表结构

GBase 分成2种类型的表,复制表和分布表。表结构可以从如下SQL获得:

show create table 库名.表名

1.2.6.1. 复制表

在每个计算节点有一份完整的数据。比如表100万行,10个节点,那么每个节点都有100万上。如下是一个复制表的样例。

1.2.6.2. 分布表

数据在每个计算节点,按照分布规则(随机、Hash)分布式保存。同样100万行,10个节点,每个节点只保存部分数据,比如随机分布时,平均每个节点保存100/10=10万行。

如下是一个随机分布表的表结构例子:

如下是一个hash分布表的表结构例子:

因为复制表数据量少且每个节点都相同,容易修复,本备份还原主要针对分布表,后续例子以td表为例,数据3300万行,2个节点。

1.2.7. 表分片

针对分布表,计算节点上在表名字后面增加了分片号,并用下划线分割。如下是td分布表的表分片样例,包括2个分片,对应td_n1和td_n2。其中

metadata/td_n1.frm 文件为分片的表结构。一般随着建表语句自动生成,【无需】单独备份。

metadata/td_n1.GED 是元数据的目录,是我们的备份目标;
sys_tablesapce/td_n1是数据目录,是我们的备份目标;

对应的td_n2同样处理。

1.2.8. 分片的顺序和位置

通过如下命令,获得分布表在每个节点的顺序和位置。

gcadmin showdistribution

  • 本例中有2个分片(Segment)1和2, 如下红色部分。
  • 主分片(Primary segment)分别对应202和201上,如下红色部分;
  • 备份分片(Duplicate Segment),分别对应201和202,如下蓝色部分;

提醒:本例只有2个节点,看上去是互备的,实际在节点多时,多数是循环备份的,比如3节点集群,1的备份在2,2的备份在3,3的备份在1。

该对应关系建议提前配置好,可以通过增加f参数输出XML格式方便程序解析。

gcadmin showdistribution f

1.2.9. 节点可连接状态

查看整个集群,哪些点可用,可以连接。

gcadmin

其中OPEN是正常, CLOSE表示服务停了,OFFLINE,表示节点无法连接(超时)。DataState部分,为0就是节点正常,1就是有表故障。

gcadmin输出的更多集群状态信息,可以参考 https://www.gbase8.cn/17

1.2.10. 节点nodeid

Nodeid是根据节点的标识,和IP对应,可以通过如下命令获得:

其中ID是节点的nodeid, ip是地址,后面的是主备情况和节点状态。

更多nodeid细节可以参考 https://www.gbase8.cn/1018

1.2.11. 表分片有效性

当主副本分片出现不一致时,可以通过如下方式,判断哪一个分片当前可用。

show datacopy map 库名.表名

其中dp_state为0代表正常。

更多细节可以参考 https://www.gbase8.cn/5788

如果是其它值,则表示该分片有故障,不能用于备份。

2. 表备份

2.1. 准备表结构

一定要准备表结构,避免整个表都出现故障,比如被误删,时恢复。请参考前面的表和表结构的部分,用show create table XXX获得。也可以业务提前准备好原始的建表语句。

2.2. 锁表

通过如下SQL语句,拿到表独占锁。如果有其它业务,包括DML和DDL操作,则会等待。

Lock table 表名 write;

拿到锁后,后来的DML/DDL操作同样会等待本连接释放锁。

gbase> lock table tdwrite;

Query OK, 0 rows affected (Elapsed: 00:00:00.00)

后续的操作,必须保证该连接不能断,否则锁会因为连接断开而被释放掉。

2.3. 备份表数据

按照每个节点的元数据和数据目录备份。其中对于有副本的,可以只备份一份,也就是td_n1只需要备份一份即可。

根据节点状态,表分片状态,备份每一个可用分片的数据。备份内容包括元数据目录和数据目录。

如下是通过scp从远端,统一备份到本地的操作,请根据实际情况备份文件。

scp -r gbase@10.0.2.201:/opt/gnode/userdata/gbase/testdb/sys_tablespace/td_n1 /opt/bak/testdb/td/
scp -r gbase@10.0.2.201:/opt/gnode/userdata/gbase/testdb/sys_tablespace/td_n2 /opt/bak/testdb/td/
scp -r gbase@10.0.2.201:/opt/gnode/userdata/gbase/testdb/metadata/td_n1.GED /opt/bak/testdb/td/
scp -r gbase@10.0.2.201:/opt/gnode/userdata/gbase/testdb/metadata/td_n2.GED /opt/bak/testdb/td/

备份结果如下,注意这里只有数据,没有表结构。

2.4. 释放锁

备份完毕后,通过unlock tables释放锁。

gbase> unlock tables;

Query OK, 0 rows affected (Elapsed: 00:00:00.00)

3. 表还原

3.1. 还原表结构

如果表已经丢失,或损坏严重,比如主副本都损坏且无法恢复,可以删除当前残留的表,然后通过备份的表结构,重建表。

另外,DROP表也会自动清除了表的故障event信息。

3.2. 锁表

请参考备份时的操作。

3.3. 还原数据

注意:

  • 集群所有节点均【可以连接】时再做还原,除非【不可连接】节点处于节点故障需要替换状态。
  • 备份时,我们只需要备份一个可用的分片即可,但还原时,如果副本可用,需要同时还原副本的分片。
  • 还原时,请用操作系统gbase用户复制,可以确保数据文件复制后的属主正确,能被gbase用户读写访问。

根据当前集群的节点状态,按照分片主备顺序,将备份的分片,复制到对应的节点目录下。

比如td_n1分片,需要同时复制到当前可用的201和202节点。

scp -r /opt/bak/testdb/td/td_n1 gbase@10.0.2.201:/opt/gnode/userdata/gbase/testdb/sys_tablespace/
scp -r /opt/bak/testdb/td/td_n1 gbase@10.0.2.202:/opt/gnode/userdata/gbase/testdb/sys_tablespace/

注意主备分片的顺序,将元数据和数据分别复制到主备分片。

3.4. 修改数据文件属主

如果数据不是通过操作系统gbase用户复制,那么需要通过chown -R gbase:gbase 将每个节点复制过来的文件属主,改成正确的。否则数据可能无法读写访问,造成报错。比如

chown -R gbase:gbase /opt/gnode/userdata/gbase/testdb/sys_tablespace/td_n1
chown -R gbase:gbase /opt/gnode/userdata/gbase/testdb/metadata/td_n1.GED
。。。。。。

其它的同样处理

3.5. 刷新表

通过如下SQL,刷新表缓冲数据,之后就可以查询到表数据了。

refresh table 库名.表名;

本例中中间做了2次insert 操作测试表锁,所以比前面检查的多了2行。

3.6. 释放锁

请参考备份时的操作。

4. 总结

  • 如果表结构有变动,增加减少了列,需要在备份数据时,对应备份表结构。
  • 本方法无法实现增量备份,所以多次备份时请考虑是否要增加时间版本信息,以便恢复到指定日期的备份。
  • 本方法只能实现单表级备份,无法保证多表之间的关系一致性。但如果一次性lock多个表,并立即同时备份可以达到该目的,但备份周期将延长,请根据实际情况取舍。
  • 备份期间,表可以正常查询,但不能有DML/DDL操作,直到释放锁或连接断开。