暂无图片
暂无图片
1
暂无图片
暂无图片
暂无图片

MogDB异常恢复研究-直接复制数据库目录

原创 范计杰 2022-09-05
968

[[toc]]

概念描述

在异常恢复场景中,如磁盘故障、文件系统固定,仅能找回部分文件,如PGDATA/base/{待恢复用户数据库目录}时,通过创建新的cluster,创建空库,使用{待恢复用户数据库目录}替换到新的PGDATA/base/{新建空库},来读取数据是可行的。 主要有以下几点依据 1、PGDATA/base/{database oid}下包含本库的数据字典
2、$PGDATA/base/{database oid}下包含用户数据文件
3、读取数据可见性依赖的clog、csnlog,可以人工重建(会丢失部分事务信息)
4、读取数据可见性依赖的控制文件中记录的NextXID,NextOID等主要信息,也可以人工更改

测试验证

1、环境描述
要恢复的cluster目录
/opt/ogdata/pdata

新建的空的cluster目录
/home/omm/data

2、待恢复库准备测试数据
准备好数据后直接kill数据库进程,模拟异常终止

生成测试数据
\c test
create table t1(id int,c varchar(100));
insert into t1 select i,'test'||i from generate_series(1,100) i;

create table t2(id int,c varchar(100));
insert into t2 select i,'test'||i from generate_series(1,100) i;
delete from t2 where id<50;

checkpoint

3、初始划一个空的cluster,并创建一个空库

$ gs_initdb -D /home/omm/data --nodename test -E utf8
$ gs_ctl start -D /home/omm/data -Z single_node -l logfile

4、创建空库,并查看database oid

postgres=# create database test;
CREATE DATABASE
postgres=# select oid from pg_database where datname='test';
  oid
-------
 16385
(1 row)

确定该库目录为$PGDATA/base/16385

5、停止新库,复制替换数据库
$ gs_ctl stop -D ~/data
$ cp -rp /opt/ogdata/pdata/base/16389/* ~/data/base/16385/

6、尝试从旧的cluster目录找到控制文件信息
pg_controldata /opt/ogdata/pdata/

找到重要的几个信息,用于新cluster pg_resetxlog
Latest checkpoint’s NextXID: 21378 <<<<
Latest checkpoint’s NextOID: 24581 <<<<
Latest checkpoint’s NextMultiXactId: 2 <<<<
Latest checkpoint’s NextMultiOffset: 0

7、pg_resetxlog重置新库控制文件
$ pg_resetxlog -o 24581 -x 21378 -m 2 -O 0 ./data
Transaction log reset

8、人工生成CLOG
根据当前的NextXID,判断生成多少个clog文件,256K一个

手工生成COMMITTED状态的CLOG日志,默认认为还没冻结或设置t_informask XMIN,XMAX提交状态的tuple上的事务都是已提交的
提示:正常情况下ABORT事务较少,多数为COMMITED

=======4种事务状态===========
#define TRANSACTION_STATUS_IN_PROGRESS 0x00
#define TRANSACTION_STATUS_COMMITTED 0x01
#define TRANSACTION_STATUS_ABORTED 0x02
#define TRANSACTION_STATUS_SUB_COMMITTED 0x03

#define CLOG_BITS_PER_XACT 2 #使用2bit保存事务状态
#define CLOG_XACTS_PER_BYTE 4 #每字节可以保存4个事务的事务状态

0x55为4个commit事务状态。
In [4]: bin(0x55)
Out[4]: ‘0b1010101’

echo -e -n “\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55” > clog.dat

每次1K,可以通过dd方式生成更多clog
$ ls -l clog.dat
-rw-r–r-- 1 postgres dba 1024 6月 20 16:31 clog.dat

$ hexdump clog.dat
0000000 5555 5555 5555 5555 5555 5555 5555 5555
*
0000400

for((i=1;i<=255;i++));
do
dd if=clog.dat of=data/pg_clog/000000000000 bs=1024 count=1 seek=$i conv=notrunc
done

[omm@centos7 ~]$ ls -l data/pg_clog/000000000000
-rw-r–r–. 1 omm dbgrp 262144 Jun 20 17:59 data/pg_clog/000000000000

10、生成csnlog
根据当前的NextXID,判断生成多少个csnlog,每个文件256k。

dd if=/dev/zero of=data2/pg_csnlog/000000000000 bs=1024 count=256

提示:
只有在 latestCompletedXid<=>nextXid 之间的事务才需要csn判断可见性
重启库后,latestCompletedXid=nextXid,历史数据不太可能需要csn判断可见性

9、启动新库,验证数据
起库,验证数据可读
$ gs_ctl start -D ./data

如果验证可读后,导出数据备份
然后验证数据库可读写,可以使用,但推荐创建新库,导入数据,防止留坑。

中间的一点小波折

第一次没有生成提交状态的CLOG,导致读取不到数据。

表存在,但数据没查到,奇怪
test=# select count(*) from t1;
 count
-------
     0
(1 row)

mog_filedump 查看数据是存在的,但infomask 加了标志位,XMIN_INVALID,怀疑为第一次查询时,因为tuple中不能确定事务状态,是clog中查找XID 23100的事务,查找不到,被标记为XMIN_INVALID

mog_filedump -o -i -D int,varchar ~/data/base/16385/32773

COPY: 98        test98
 Item  14 -- Length:   35  Offset: 7632 (0x1dd0)  Flags: NORMAL
  XMIN: 23100  XMAX: 0  CID|XVAC: 0
  Block Id: 1  linp Index: 14   Attributes: 2   Size: 24
  infomask: 0x0a02 (HASVARWIDTH|XMIN_INVALID|XMAX_INVALID)

COPY: 99        test99
 Item  15 -- Length:   36  Offset: 7592 (0x1da8)  Flags: NORMAL
  XMIN: 23100  XMAX: 0  CID|XVAC: 0 <<<<XMIN: 23100 
  Block Id: 1  linp Index: 15   Attributes: 2   Size: 24
  infomask: 0x0a02 (HASVARWIDTH|XMIN_INVALID|XMAX_INVALID) <<<<XMIN_INVALID,查询后,加了标记XMIN_INVALID

COPY: 100       test100

我重新复制数据目录,并把CLOG中XID 23100标记为已提交,再起库,数据可查看,问题解决

In [6]: (23100-1)/4,(23100-1)%4
Out[6]: (5774.75, 3)

clog 5774字节的,第4个

XID 23100事务clog改成提交(01)重新复制测试
00000001
In [3]: int('00000001',2)
Out[3]: 1

[root@centos7 dump]# ./dump -decoder byte1 -bs 1 -n 5774 -file /home/omm/data/pg_clog/000000000000 -setname data -setval uint8#01
{0 [] 1 map[data:0xc0000a0240] [0xc0000a0240]}
======read and dump block 5774=======
@0    data                           size:1    hex:0x0                            val:0
===============after modify================
@0    data                           size:1    hex:0x1                            val:1

gs_ctl stop -D ~/data

$ rm -rf ~/data/base/16385/*
$ cp -rp /opt/ogdata/pdata/base/24581/* ~/data/base/16385/

gs_ctl start -D ~/data

知识总结

1、只要数据字典存在,数据文件存在,通过复制目录恢复数据就是可行的
2、过程中主要难点在于,判断最大的XID,生成CLOG
3、如果数据字典丢失或损坏,理论找到表结构,重建,重命名数据文件也能读取数据,但一难数据文件无法判断是哪个表!!!

参考文档

「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

文章被以下合辑收录

评论