當前位置:首頁 >  站長 >  數(shù)據(jù)庫 >  正文

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

 2021-06-04 17:20  來源: 腳本之家   我來投稿 撤稿糾錯

  域名預(yù)訂/競價,好“米”不錯過

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

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

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

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

實例模擬講解

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

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

Postgres201 : 線上數(shù)據(jù)庫服務(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)建一個需要恢復(fù)對象表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 這個獲取一個時間:用于后面基于數(shù)據(jù)庫PITR恢復(fù)(當然現(xiàn)實操作后只能記住一個大概的時間;還往往是不準;可能記住的時間是誤操作之后。后面有講解如何獲取需要恢復(fù)到那個時間點)

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 進行drop表

lottu=# drop table tbl_lottu_drop;
DROP TABLE

 

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

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ù)庫上

[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ù)庫上pg_xlog目錄下;從哪個日志開始拷貝?

[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開始到正在寫入的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 啟動數(shù)據(jù)庫;并驗證數(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ù)庫操作略。

延伸點

下面講解下如何找到誤操作的時間。即recovery_target_time = '2018-04-28 20:47:31.617808+08'的時間點。上文是前面已經(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ù)時間點選2018-04-28 20:47:31.617808+08沒毛病);即也是在事務(wù)id為1690操作的。并在事務(wù)id為1691進行刪除操作。

所以上面的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'

 

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

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

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

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ù)庫上繼續(xù)進行業(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

 

時間軸(第三行的縮寫代表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

沒有設(shè)置archive_timeout,整個數(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ù)被認為是未提交事務(wù),表為空(最后一個xlog文件的內(nèi)容全部遺失了)。

情況2

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

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è)置了超時切換,最后一個xlog會被歸檔)。

情況3(重要)

設(shè)置archive_timeout,根據(jù)估計時間點嘗試多次恢復(fù),不能確定想恢復(fù)到具體哪個時間點,歸檔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ǔ)備份時間之前)

這里------------------------------------------------------------------------
-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ù)時間定到了基礎(chǔ)備份之前,所以這里會恢復(fù)到最早時間點:基礎(chǔ)備份點。

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

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

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

---------這里---------------------------------------------------------------
-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ù)時間定到了基礎(chǔ)備份之前,所以這里會恢復(fù)到最早時間點:基礎(chǔ)備份點。

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

注意:無法恢復(fù)到基礎(chǔ)備份之前的點,所以再做基礎(chǔ)備份時,請保證數(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存在,但沒有數(shù)據(jù)。說明如果時間在基礎(chǔ)備份點之后,可以恢復(fù)到任意時間點。恢復(fù)后會創(chuàng)建新時間線。

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

(3.1) 在(3)的基礎(chǔ)上繼續(xù)進行恢復(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)建了一條新的時間線3,這條時間線上面進行恢復(fù)的話,數(shù)據(jù)庫會去archive里面去找時間線2的xlog,但是歸檔目錄中的日志應(yīng)該都是時間線1的,所以會報錯找不到xlog。

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

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

其他

壓縮的歸檔日志

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(幾個重要參數(shù))

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

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

recovery_target_time (timestamp)這個參數(shù)指定恢復(fù)將進入的時間戳。

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

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

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

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

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

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

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

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

文章來源:腳本之家

來源地址:https://www.jb51.net/article/204286.htm

申請創(chuàng)業(yè)報道,分享創(chuàng)業(yè)好點子。點擊此處,共同探討創(chuàng)業(yè)新機遇!

相關(guān)文章

熱門排行

信息推薦