[[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 <<<
1、只要数据字典存在,数据文件存在,通过复制目录恢复数据就是可行的
2、过程中主要难点在于,判断最大的xid,生成clog
3、如果数据字典丢失或损坏,理论找到表结构,重建,重命名数据文件也能读取数据,但一难数据文件无法判断是哪个表!!!
无
「喜欢文章,快来给作者赞赏墨值吧」 【米乐app官网下载的版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。 文章被以下合辑收录
评论