[[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、如果數據字典丟失或損壞,理論找到表結構,重建,重命名數據文件也能讀取數據,但一難數據文件無法判斷是哪個表!!!
參考文檔
無




