當(dāng)前位置:首頁(yè) >  站長(zhǎng) >  數(shù)據(jù)庫(kù) >  正文

PostgreSQL 恢復(fù)誤刪數(shù)據(jù)的操作

 2021-06-04 17:20  來(lái)源: 腳本之家   我來(lái)投稿 撤稿糾錯(cuò)

  域名預(yù)訂/競(jìng)價(jià),好“米”不錯(cuò)過(guò)

在Oracle中;刪除表或者誤刪表記錄;有個(gè)閃回特性,不需要停機(jī)操作,可以完美找回記錄。當(dāng)然也有一些其他的恢復(fù)工具;例如odu工具,gdul工具。都可以找回?cái)?shù)據(jù)。而PostgreSQL目前沒(méi)有閃回特性。如何在不停機(jī)情況下恢復(fù)誤刪數(shù)據(jù)。還好是有完整的熱備份。

本文描述的方法是:利用熱備份在另一臺(tái)服務(wù)器進(jìn)行數(shù)據(jù)恢復(fù);再導(dǎo)入正式環(huán)境;這樣不影響數(shù)據(jù)庫(kù)操作。這方法也適用在Oracle恢復(fù)。必須滿足幾個(gè)條件

1、有完整的基礎(chǔ)數(shù)據(jù)文件備份和歸檔文件備份.所以備份是很重要的。

2、有一臺(tái)裝好同款Postgres軟件的服務(wù)器

實(shí)例模擬講解

過(guò)程模擬誤刪表tbl_lottu_drop后;后續(xù)進(jìn)行dml/ddl操作;表明正式數(shù)據(jù)庫(kù)還是進(jìn)行正常工作。在另外一臺(tái)數(shù)據(jù)庫(kù)基于數(shù)據(jù)庫(kù)PITR恢復(fù)?;謴?fù)表tbl_lottu_drop的數(shù)據(jù)。

1、創(chuàng)建一個(gè)有效的備份

Postgres201 : 線上數(shù)據(jù)庫(kù)服務(wù)器
Postgres202 : 操作服務(wù)器
postgres=# select pg_start_backup(now()::text);
 pg_start_backup
-----------------
 0/F000060
(1 row)
[postgres@Postgres201 ~]$ rsync -acvz -L --exclude "pg_xlog" --exclude "pg_log" $PGDATA /data/backup/20180428
postgres=# select pg_stop_backup();
NOTICE: pg_stop_backup complete, all required WAL segments have been archived
 pg_stop_backup
----------------
 0/F000168
(1 row)

 

2、模擬誤操作

2.1 創(chuàng)建一個(gè)需要恢復(fù)對(duì)象表tbl_lottu_drop。并插入1000記錄。也保證數(shù)據(jù)從數(shù)據(jù)緩存寫入磁盤中。

lottu=> create table tbl_lottu_drop (id int);
CREATE TABLE
lottu=> insert into tbl_lottu_drop select generate_series(1,1000);
INSERT 0 1000
lottu=> \c lottu postgres
You are now connected to database "lottu" as user "postgres".

 

2.2 這個(gè)獲取一個(gè)時(shí)間:用于后面基于數(shù)據(jù)庫(kù)PITR恢復(fù)(當(dāng)然現(xiàn)實(shí)操作后只能記住一個(gè)大概的時(shí)間;還往往是不準(zhǔn);可能記住的時(shí)間是誤操作之后。后面有講解如何獲取需要恢復(fù)到那個(gè)時(shí)間點(diǎn))

lottu=# select now();
    now   
-------------------------------
 2018-04-28 20:47:31.617808+08
(1 row)
lottu=# checkpoint;
CHECKPOINT
lottu=# select pg_xlogfile_name(pg_switch_xlog());
  pg_xlogfile_name 
--------------------------
 000000030000000000000010
(1 row)

 

2.3 進(jìn)行drop表

lottu=# drop table tbl_lottu_drop;
DROP TABLE

 

2.4 后續(xù)進(jìn)行dml/ddl操作;表明正式數(shù)據(jù)庫(kù)還是進(jìn)行正常工作

lottu=# create table tbl_lottu_log (id int);
CREATE TABLE
lottu=# insert into tbl_lottu_log values (1),(2);
INSERT 0 2
lottu=# checkpoint;
CHECKPOINT
lottu=# select pg_xlogfile_name(pg_switch_xlog());
  pg_xlogfile_name 
--------------------------
 000000030000000000000011
(1 row)

 

3、恢復(fù)操作

3.1 將備份拷貝到Postgres202數(shù)據(jù)庫(kù)上

[postgres@Postgres201 20180428]$ cd /data/backup/20180428
[postgres@Postgres201 20180428]$ ll
total 4
drwx------. 18 postgres postgres 4096 Apr 28 20:42 data
[postgres@Postgres201 20180428]$ rsync -acvz -L data postgres@192.168.1.202:/data/postgres
  

 

3.2 刪除不必要的文件

[postgres@Postgres202 data]$ cd $PGDATA
[postgres@Postgres202 data]$ rm backup_label.old postmaster.pid tablespace_map.old

 

3.3 還原備份表空間軟鏈接

[postgres@Postgres202 data]$ cat tablespace_map
16385 /data/pg_data/lottu
[postgres@Postgres202 data]$ mkdir -p /data/pg_data
[postgres@Postgres202 data]$ cd pg_tblspc/
[postgres@Postgres202 pg_tblspc]$ mv 16385/ /data/pg_data/lottu
[postgres@Postgres202 pg_tblspc]$ ln -s /data/pg_data/lottu ./16385
[postgres@Postgres202 pg_tblspc]$ ll
total 0
lrwxrwxrwx. 1 postgres postgres 19 Apr 28 23:12 16385 -> /data/pg_data/lottu

 

3.4 將wal日志拷貝到Postgres202數(shù)據(jù)庫(kù)上pg_xlog目錄下;從哪個(gè)日志開(kāi)始拷貝?

[postgres@Postgres202 data]$ mkdir -p pg_xlog/archive_status
[postgres@Postgres202 data]$ cat backup_label
START WAL LOCATION: 0/F000060 (file 00000003000000000000000F)
CHECKPOINT LOCATION: 0/F000098
BACKUP METHOD: pg_start_backup
BACKUP FROM: master
START TIME: 2018-04-28 20:42:15 CST
LABEL: 2018-04-28 20:42:13.244358+08

 

查看backup_label;知道00000003000000000000000F開(kāi)始到正在寫入的wal日志。

[postgres@Postgres202 pg_xlog]$ ll
total 65540
-rw-------. 1 postgres postgres 16777216 Apr 28 20:42 00000003000000000000000F
-rw-------. 1 postgres postgres  313 Apr 28 20:42 00000003000000000000000F.00000060.backup
-rw-------. 1 postgres postgres 16777216 Apr 28 20:48 000000030000000000000010
-rw-------. 1 postgres postgres 16777216 Apr 28 20:50 000000030000000000000011
-rw-------. 1 postgres postgres 16777216 Apr 28 20:55 000000030000000000000012

 

3.5 編輯recovery.conf文件

[postgres@Postgres202 data]$ vi recovery.conf
restore_command = 'cp /data/arch/%f %p'   # e.g. 'cp /mnt/server/archivedir/%f %p'
recovery_target_time = '2018-04-28 20:47:31.617808+08'
recovery_target_inclusive = false
recovery_target_timeline = 'latest'

 

3.6 啟動(dòng)數(shù)據(jù)庫(kù);并驗(yàn)證數(shù)據(jù)

[postgres@Postgres202 data]$ pg_start
server starting
[postgres@Postgres202 data]$ ps -ef | grep postgres
root  1098 1083 0 22:32 pts/0 00:00:00 su - postgres
postgres 1099 1098 0 22:32 pts/0 00:00:00 -bash
root  1210 1195 0 22:55 pts/1 00:00:00 su - postgres
postgres 1211 1210 0 22:55 pts/1 00:00:00 -bash
postgres 1442  1 1 23:16 pts/0 00:00:00 /opt/pgsql96/bin/postgres
postgres 1450 1442 0 23:16 ?  00:00:00 postgres: checkpointer process
postgres 1451 1442 0 23:16 ?  00:00:00 postgres: writer process
postgres 1459 1442 0 23:16 ?  00:00:00 postgres: wal writer process
postgres 1460 1442 0 23:16 ?  00:00:00 postgres: autovacuum launcher process
postgres 1461 1442 0 23:16 ?  00:00:00 postgres: archiver process last was 00000005.history
postgres 1462 1442 0 23:16 ?  00:00:00 postgres: stats collector process
postgres 1464 1099 0 23:16 pts/0 00:00:00 ps -ef
postgres 1465 1099 0 23:16 pts/0 00:00:00 grep postgres
[postgres@Postgres202 data]$ psql
psql (9.6.0)
Type "help" for help.
postgres=# \c lottu lottu
You are now connected to database "lottu" as user "lottu".
lottu=> \dt
   List of relations
 Schema |  Name  | Type | Owner
--------+----------------+-------+-------
 public | pitr_test  | table | lottu
 public | tbl_lottu_drop | table | lottu
 
 lottu=> select count(1) from tbl_lottu_drop;
 count
-------
 1000
(1 row)

 

lottu=> select count(1) from tbl_lottu_drop; count------- 1000(1 row)

從這看數(shù)據(jù)是恢復(fù)了;copy到線上數(shù)據(jù)庫(kù)操作略。

延伸點(diǎn)

下面講解下如何找到誤操作的時(shí)間。即recovery_target_time = '2018-04-28 20:47:31.617808+08'的時(shí)間點(diǎn)。上文是前面已經(jīng)獲取的;

1. 用pg_xlogdump解析這段日志。

[postgres@Postgres201 pg_xlog]$ pg_xlogdump -b 00000003000000000000000F 000000030000000000000012 > lottu.log
pg_xlogdump: FATAL: error in WAL record at 0/12000648: invalid record length at 0/12000680: wanted 24, got 0

 

2. 從lottu.log中可以找到這段日志

rmgr: Transaction len (rec/tot):  8/ 34, tx:  1689, lsn: 0/100244A0, prev 0/10024460, desc: COMMIT 2018-04-28 20:45:49.736013 CST
rmgr: Standby  len (rec/tot):  24/ 50, tx:   0, lsn: 0/100244C8, prev 0/100244A0, desc: RUNNING_XACTS nextXid 1690 latestCompletedXid 1689 oldestRunningXid 1690
rmgr: Heap  len (rec/tot):  3/ 3130, tx:  1690, lsn: 0/10024500, prev 0/100244C8, desc: INSERT off 9
 blkref #0: rel 16385/16386/2619 fork main blk 15 (FPW); hole: offset: 60, length: 5116
rmgr: Btree  len (rec/tot):  2/ 7793, tx:  1690, lsn: 0/10025140, prev 0/10024500, desc: INSERT_LEAF off 385
 blkref #0: rel 16385/16386/2696 fork main blk 1 (FPW); hole: offset: 1564, length: 452
rmgr: Heap  len (rec/tot):  2/ 184, tx:  1690, lsn: 0/10026FD0, prev 0/10025140, desc: INPLACE off 16
 blkref #0: rel 16385/16386/1259 fork main blk 0
rmgr: Transaction len (rec/tot):  88/ 114, tx:  1690, lsn: 0/10027088, prev 0/10026FD0, desc: COMMIT 2018-04-28 20:46:37.718442 CST; inval msgs: catcache 49 catcache 45 catcache 44 relcache 32784
rmgr: Standby  len (rec/tot):  24/ 50, tx:   0, lsn: 0/10027100, prev 0/10027088, desc: RUNNING_XACTS nextXid 1691 latestCompletedXid 1690 oldestRunningXid 1691
rmgr: Standby  len (rec/tot):  24/ 50, tx:   0, lsn: 0/10027138, prev 0/10027100, desc: RUNNING_XACTS nextXid 1691 latestCompletedXid 1690 oldestRunningXid 1691
rmgr: XLOG  len (rec/tot):  80/ 106, tx:   0, lsn: 0/10027170, prev 0/10027138, desc: CHECKPOINT_ONLINE redo 0/10027138; tli 3; prev tli 3; fpw true; xid 0:1691; oid 40976; multi 1; offset 0; oldest xid 1668 in DB 1; oldest multi 1 in DB 1; oldest/newest commit timestamp xid: 0/0; oldest running xid 1691; online
rmgr: Standby  len (rec/tot):  24/ 50, tx:   0, lsn: 0/100271E0, prev 0/10027170, desc: RUNNING_XACTS nextXid 1691 latestCompletedXid 1690 oldestRunningXid 1691
rmgr: Standby  len (rec/tot):  24/ 50, tx:   0, lsn: 0/10027218, prev 0/100271E0, desc: RUNNING_XACTS nextXid 1691 latestCompletedXid 1690 oldestRunningXid 1691
rmgr: XLOG  len (rec/tot):  80/ 106, tx:   0, lsn: 0/10027250, prev 0/10027218, desc: CHECKPOINT_ONLINE redo 0/10027218; tli 3; prev tli 3; fpw true; xid 0:1691; oid 40976; multi 1; offset 0; oldest xid 1668 in DB 1; oldest multi 1 in DB 1; oldest/newest commit timestamp xid: 0/0; oldest running xid 1691; online
rmgr: XLOG  len (rec/tot):  0/ 24, tx:   0, lsn: 0/100272C0, prev 0/10027250, desc: SWITCH
rmgr: Standby  len (rec/tot):  24/ 50, tx:   0, lsn: 0/11000028, prev 0/100272C0, desc: RUNNING_XACTS nextXid 1691 latestCompletedXid 1690 oldestRunningXid 1691
rmgr: Standby  len (rec/tot):  16/ 42, tx:  1691, lsn: 0/11000060, prev 0/11000028, desc: LOCK xid 1691 db 16386 rel 32784
rmgr: Heap  len (rec/tot):  8/ 2963, tx:  1691, lsn: 0/11000090, prev 0/11000060, desc: DELETE off 16 KEYS_UPDATED
 blkref #0: rel 16385/16386/1247 fork main blk 8 (FPW); hole: offset: 88, length: 5288

 

根據(jù)“32784”日志可以看到是表tbl_lottu_drop在2018-04-28 20:46:37.718442插入1000條記錄(所以恢復(fù)時(shí)間點(diǎn)選2018-04-28 20:47:31.617808+08沒(méi)毛病);即也是在事務(wù)id為1690操作的。并在事務(wù)id為1691進(jìn)行刪除操作。

所以上面的recovery.conf 也可以改寫為:

restore_command = 'cp /data/arch/%f %p'   # e.g. 'cp /mnt/server/archivedir/%f %p'
recovery_target_xid = '1690'
recovery_target_inclusive = false
recovery_target_timeline = 'latest'

 

補(bǔ)充:PostgreSQL多種恢復(fù)實(shí)例分析

Postgresql歸檔恢復(fù)實(shí)例分析(時(shí)間線機(jī)制)

這篇文章根據(jù)實(shí)例介紹Postgresql歸檔恢復(fù)的方法,時(shí)間線的含義。

1 參數(shù)配置

sed -ir "s/#*max_wal_senders.*/max_wal_senders = 10/" $PGDATA/postgresql.conf
sed -ir "s/#*wal_level.*/wal_level = replica/" $PGDATA/postgresql.conf
sed -ir "s/#*archive_mode.*/archive_mode = on/" $PGDATA/postgresql.conf
sed -ir "s/#*archive_command.*/archive_command = 'test ! -f \${PGHOME}\/archive\/%f \&\& cp %p \${PGHOME}\/archive\/%f'/" $PGDATA/postgresql.conf

 

2 數(shù)據(jù)操作

date;psql -c "create table test00 (id int primary key, info text)"
Sat Apr 1 10:09:55 CST 2017
date;psql -c "insert into test00 values(generate_series(1,50000), repeat(md5(random()::text), 1000))"
Sat Apr 1 10:10:10 CST 2017
date;psql -c "create table test01 (id int primary key, info text)"
Sat Apr 1 10:10:48 CST 2017
date;psql -c "insert into test01 values(generate_series(1,50000), repeat(md5(random()::text), 1000))"
Sat Apr 1 10:10:53 CST 2017

 

3 制作基礎(chǔ)備份

1sed -ir "s/#*max_wal_senders.*/max_wal_senders = 10/" $PGDATA/postgresql.conf

配置pg_hba.conf通道

1pg_basebackup -Fp -P -x -D ~/bin/data/pg_root21 -l basebackup21

4 數(shù)據(jù)庫(kù)上繼續(xù)進(jìn)行業(yè)務(wù)操作(模擬在基礎(chǔ)備份后,業(yè)務(wù)繼續(xù)下發(fā),然后發(fā)生故障)

date;psql -c "create table test02 (id int primary key, info text)"
Sat Apr 1 10:15:59 CST 2017
date;psql -c "insert into test02 values(generate_series(1,100000), repeat(md5(random()::text), 1000))"
Sat Apr 1 10:16:09 CST 2017

 

時(shí)間軸(第三行的縮寫代表Create Insert)

-10:09:55----10:10:10-----10:10:48-----10:10:53------10:15:59----10:16:09--
----|-----------|------------|------------|-------------|-----------|------
C test00-----I test00-----C test01-----I test01-----C test01-----I test01--

 

情況1

沒(méi)有設(shè)置archive_timeout,整個(gè)數(shù)據(jù)目錄被刪除

5 數(shù)據(jù)目錄被rm -rf掉了(模擬誤操作)

1rm -rf pg_root20/

6 歸檔恢復(fù)

1cp -r pg_root21 pg_root20

修改pg_hba.conf阻止用戶連接

cp $PGHOME/share/recovery.conf.sample ./recovery.conf
sed -ir "s/#*restore_command.*/restore_command = 'cp \${PGHOME}\/archive\/%f %p'/" $PGDATA/recovery.conf
 

 

7 恢復(fù)結(jié)果

test02存在,但是其中的數(shù)據(jù)被認(rèn)為是未提交事務(wù),表為空(最后一個(gè)xlog文件的內(nèi)容全部遺失了)。

情況2

設(shè)置archive_timeout,整個(gè)數(shù)據(jù)目錄被刪除,歸檔timeout為60s,在test02表數(shù)據(jù)灌入之后,xlog自動(dòng)切換并歸檔

1(sed -ir "s/#*archive_timeout.*/archive_timeout = 60/" $PGDATA/postgresql.conf)

5 數(shù)據(jù)目錄被rm -rf掉了(模擬誤操作)

1rm -rf pg_root20/

6 歸檔恢復(fù)

1cp -r pg_root21 pg_root20

修改pg_hba.conf阻止用戶連接

cp $PGHOME/share/recovery.conf.sample ./recovery.conf
sed -ir "s/#*restore_command.*/restore_command = 'cp \${PGHOME}\/archive\/%f %p'/" $PGDATA/recovery.conf
 

 

7 恢復(fù)結(jié)果

test02存在,數(shù)據(jù)也存在(由于歸檔設(shè)置了超時(shí)切換,最后一個(gè)xlog會(huì)被歸檔)。

情況3(重要)

設(shè)置archive_timeout,根據(jù)估計(jì)時(shí)間點(diǎn)嘗試多次恢復(fù),不能確定想恢復(fù)到具體哪個(gè)時(shí)間點(diǎn),歸檔timeout為60s

1(sed -ir "s/#*archive_timeout.*/archive_timeout = 60/" $PGDATA/postgresql.conf)

5 數(shù)據(jù)目錄被rm -rf掉了(模擬誤操作)

1rm -rf pg_root20/

6 歸檔恢復(fù)

1cp -r pg_root21 pg_root20

修改pg_hba.conf阻止用戶連接

cp $PGHOME/share/recovery.conf.sample ./recovery.conf
sed -ir "s/#*restore_command.*/restore_command = 'cp \${PGHOME}\/archive\/%f %p'/" $PGDATA/recovery.conf
 

 

(1) recovery_target_time = ‘2017-4-1 10:09:47' (基礎(chǔ)備份時(shí)間之前)

這里------------------------------------------------------------------------
-10:09:55----10:10:10-----10:10:48-----10:10:53------10:15:59----10:16:09--
----|-----------|------------|------------|---basebackup---|--------|------
C test00-----I test00-----C test01-----I test01-----C test02-----I test02--

 

結(jié)果:

恢復(fù)時(shí)間定到了基礎(chǔ)備份之前,所以這里會(huì)恢復(fù)到最早時(shí)間點(diǎn):基礎(chǔ)備份點(diǎn)。

1LOG: recovery stopping before commit of transaction 1175, time 2017-04-01 10:15:59.597495+08

注意:無(wú)法恢復(fù)到基礎(chǔ)備份之前的點(diǎn),所以再做基礎(chǔ)備份時(shí),請(qǐng)保證數(shù)據(jù)一致性。

(2) recovery_target_time = ‘2017-4-1 10:10:00' (基礎(chǔ)備份時(shí)間之前)

---------這里---------------------------------------------------------------
-10:09:55----10:10:10-----10:10:48-----10:10:53------10:15:59----10:16:09--
----|-----------|------------|------------|---basebackup---|--------|------
C test00-----I test00-----C test01-----I test01-----C test02-----I test02--

 

結(jié)果:

恢復(fù)時(shí)間定到了基礎(chǔ)備份之前,所以這里會(huì)恢復(fù)到最早時(shí)間點(diǎn):基礎(chǔ)備份點(diǎn)。

1LOG: recovery stopping before commit of transaction 1175, time 2017-04-01 10:15:59.597495+08

注意:無(wú)法恢復(fù)到基礎(chǔ)備份之前的點(diǎn),所以再做基礎(chǔ)備份時(shí),請(qǐng)保證數(shù)據(jù)一致性。

(3) recovery_target_time = ‘2017-4-1 10:16:00'

-------------------------------------------------------------這里-----------
-10:09:55----10:10:10-----10:10:48-----10:10:53------10:15:59----10:16:09--
----|-----------|------------|------------|---basebackup---|--------|------
C test00-----I test00-----C test01-----I test01-----C test02-----I test02--

 

結(jié)果:

表test02存在,但沒(méi)有數(shù)據(jù)。說(shuō)明如果時(shí)間在基礎(chǔ)備份點(diǎn)之后,可以恢復(fù)到任意時(shí)間點(diǎn)?;謴?fù)后會(huì)創(chuàng)建新時(shí)間線。

1LOG: last completed transaction was at log time 2017-04-01 10:15:59.597495+08

(3.1) 在(3)的基礎(chǔ)上繼續(xù)進(jìn)行恢復(fù):recovery_target_time = ‘2017-4-1 10:17:00'

------------------------------------------------------------------------這里
-10:09:55----10:10:10-----10:10:48-----10:10:53------10:15:59----10:16:09--
----|-----------|------------|------------|---basebackup---|--------|------
C test00-----I test00-----C test01-----I test01-----C test02-----I test02--

 

結(jié)果:

同3,這次恢復(fù)創(chuàng)建了一條新的時(shí)間線3,這條時(shí)間線上面進(jìn)行恢復(fù)的話,數(shù)據(jù)庫(kù)會(huì)去archive里面去找時(shí)間線2的xlog,但是歸檔目錄中的日志應(yīng)該都是時(shí)間線1的,所以會(huì)報(bào)錯(cuò)找不到xlog。

1cp: cannot stat pathto/archive/00000002000000000000000A': No such file or directory

注意: 根據(jù)上述結(jié)論,請(qǐng)?jiān)诿看位謴?fù)時(shí)都使用原始?xì)w檔文件,即如果嘗試再次恢復(fù),請(qǐng)重新使用基礎(chǔ)備份進(jìn)行恢復(fù),不要在前一次恢復(fù)的基礎(chǔ)上繼續(xù)進(jìn)行,否則由于時(shí)間線切換,會(huì)找不到歸檔文件。

其他

壓縮的歸檔日志

sed -ir "s/#*archive_command.*/archive_command = 'gzip -c %p > \${PGHOME}\/archive\/%f.gz'/" $PGDATA/postgresql.conf
sed -ir "s/#*restore_command.*/restore_command = 'gzip -d -c \${PGHOME}\/archive\/%f.gz > %p'/" $PGDATA/recovery.conf
 

 

1、recovery.conf(幾個(gè)重要參數(shù))

Postgresql9.6手冊(cè)(彭煜瑋翻譯)

restore_command (string)用于獲取 WAL 文件系列的一個(gè)已歸檔段的本地 shell 命令。這個(gè)參數(shù)是歸檔恢復(fù)所必需的,但是對(duì)于流復(fù)制是可選的。在該字符串中的任何%f會(huì)被替換為從歸檔中獲得的文件的名字,并且任何%p會(huì)被在服務(wù)器上的復(fù)制目標(biāo)路徑名替換(該路徑名是相對(duì)于當(dāng)前工作目錄的,即集簇的數(shù)據(jù)目錄)。任何%r會(huì)被包含上一個(gè)可用重啟點(diǎn)的文件的名字所替換。在那些必須被保留用于使得一次恢復(fù)變成可重啟的文件中,這個(gè)文件是其中最早的一個(gè),因此這個(gè)信息可以被用來(lái)把歸檔截?cái)酁橹С謴漠?dāng)前恢復(fù)重啟所需的最小值。%r通常只被溫備配置(見(jiàn)Section 26.2)所使用。要嵌入一個(gè)真正的%字符,需要寫成%%。很重要的一點(diǎn)是,該命令只有在成功時(shí)才返回一個(gè)為零的退出狀態(tài)。該命令將會(huì)被詢問(wèn)不存在于歸檔中的文件名,當(dāng)這樣被詢問(wèn)時(shí)它必須返回非零。

recovery_target_time (timestamp)這個(gè)參數(shù)指定恢復(fù)將進(jìn)入的時(shí)間戳。

recovery_target_xid (string)這個(gè)參數(shù)指定恢復(fù)將進(jìn)入的事務(wù) ID。記住雖然事務(wù) ID 是在事務(wù)開(kāi)始時(shí)順序分配的,但是事務(wù)可能以不同的數(shù)字順序完成。那些在指定事務(wù)之前(也可以包括該事務(wù))提交的事務(wù)將被恢復(fù)。精確的停止點(diǎn)也受到recovery_target_inclusive的影響。

recovery_target_timeline (string)指定恢復(fù)到一個(gè)特定的時(shí)間線中。默認(rèn)值是沿著基礎(chǔ)備份建立時(shí)的當(dāng)前時(shí)間線恢復(fù)。將這個(gè)參數(shù)設(shè)置為latest會(huì)恢復(fù)到該歸檔中能找到的最新的時(shí)間線,這在一個(gè)后備服務(wù)器中有用。除此之外,你只需要在復(fù)雜的重恢復(fù)情況下設(shè)置這個(gè)參數(shù),在這種情況下你需要返回到一個(gè)狀態(tài),該狀態(tài)本身是在一次時(shí)間點(diǎn)恢復(fù)之后到達(dá)的。相關(guān)討論見(jiàn)Section25.3.5

2、關(guān)于時(shí)間線

Postgresql9.6手冊(cè)(彭煜瑋翻譯)

將數(shù)據(jù)庫(kù)恢復(fù)到一個(gè)之前的時(shí)間點(diǎn)的能力帶來(lái)了一些復(fù)雜性,這和有關(guān)時(shí)間旅行和平行宇宙的科幻小說(shuō)有些相似。例如,在數(shù)據(jù)庫(kù)的最初歷史中,假設(shè)你在周二晚上5:15時(shí)丟棄了一個(gè)關(guān)鍵表,但是一直到周三中午才意識(shí)到你的錯(cuò)誤。不用苦惱,你取出你的備份,恢復(fù)到周二晚上5:14的時(shí)間點(diǎn),并上線運(yùn)行。在數(shù)據(jù)庫(kù)宇宙的這個(gè)歷史中,你從沒(méi)有丟棄該表。但是假設(shè)你后來(lái)意識(shí)到這并非一個(gè)好主意,并且想回到最初歷史中周三早上的某個(gè)時(shí)間。你沒(méi)法這樣做,在你的數(shù)據(jù)庫(kù)在線運(yùn)行期間,它重寫了某些WAL段文件,而這些文件本來(lái)可以將你引向你希望回到的時(shí)間。因此,為了避免出現(xiàn)這種狀況,你需要將完成時(shí)間點(diǎn)恢復(fù)后生成的WAL記錄序列與初始數(shù)據(jù)庫(kù)歷史中產(chǎn)生的WAL記錄序列區(qū)分開(kāi)來(lái)。

要解決這個(gè)問(wèn)題,PostgreSQL有一個(gè)時(shí)間線概念。無(wú)論何時(shí)當(dāng)一次歸檔恢復(fù)完成,一個(gè)新的時(shí)間線被創(chuàng)建來(lái)標(biāo)識(shí)恢復(fù)之后生成的WAL記錄序列。時(shí)間線ID號(hào)是WAL段文件名的一部分,因此一個(gè)新的時(shí)間線不會(huì)重寫由之前的時(shí)間線生成的WAL數(shù)據(jù)。實(shí)際上可以歸檔很多不同的時(shí)間線。雖然這可能看起來(lái)是一個(gè)無(wú)用的特性,但是它常常扮演救命稻草的角色。考慮到你不太確定需要恢復(fù)到哪個(gè)時(shí)間點(diǎn)的情況,你可能不得不做多次時(shí)間點(diǎn)恢復(fù)嘗試和錯(cuò)誤,直到最終找到從舊歷史中分支出去的最佳位置。如果沒(méi)有時(shí)間線,該處理將會(huì)很快生成一堆不可管理的混亂。而有了時(shí)間線,你可以恢復(fù)到任何之前的狀態(tài),包括早先被你放棄的時(shí)間線分支中的狀態(tài)。

每次當(dāng)一個(gè)新的時(shí)間線被創(chuàng)建,PostgreSQL會(huì)創(chuàng)建一個(gè)“時(shí)間線歷史”文件,它顯示了新時(shí)間線是什么時(shí)候從哪個(gè)時(shí)間線分支出來(lái)的。系統(tǒng)在從一個(gè)包含多個(gè)時(shí)間線的歸檔中恢復(fù)時(shí),這些歷史文件對(duì)于允許系統(tǒng)選取正確的WAL段文件非常必要。因此,和WAL段文件相似,它們也要被歸檔到WAL歸檔區(qū)域。歷史文件是很小的文本文件,因此將它們無(wú)限期地保存起來(lái)的代價(jià)很小,而且也是很合適的(而段文件都很大)。如果你喜歡,你可以在一個(gè)歷史文件中增加注釋來(lái)記錄如何和為什么要?jiǎng)?chuàng)建該時(shí)間線。當(dāng)你由于試驗(yàn)的結(jié)果擁有了一大堆錯(cuò)綜復(fù)雜的不同時(shí)間線時(shí),這種注釋將會(huì)特別有價(jià)值。

恢復(fù)的默認(rèn)行為是沿著相同的時(shí)間線進(jìn)行恢復(fù),該時(shí)間線是基礎(chǔ)備份創(chuàng)建時(shí)的當(dāng)前時(shí)間線。如果你希望恢復(fù)到某個(gè)子女時(shí)間線(即,你希望回到在一次恢復(fù)嘗試后產(chǎn)生的某個(gè)狀態(tài)),你需要在recovery.conf中指定目標(biāo)時(shí)間線ID。你不能恢復(fù)到早于該基礎(chǔ)備份之前分支出去的時(shí)間線。

文章來(lái)源:腳本之家

來(lái)源地址:https://www.jb51.net/article/204286.htm

申請(qǐng)創(chuàng)業(yè)報(bào)道,分享創(chuàng)業(yè)好點(diǎn)子。點(diǎn)擊此處,共同探討創(chuàng)業(yè)新機(jī)遇!

相關(guān)文章

熱門排行

信息推薦