關(guān)于 PostgreSQL 備份恢復(fù)的心得
這段時間對 PostgreSQL 的備份恢復(fù)進行了一些研究, 有一些心得和大家分享一下.
我們知道, PostgreSQL 擁有 WAL(預(yù)寫式日志) 已經(jīng)有一段時間了.
WAL 的一個重要好處就是能在系統(tǒng)崩潰(數(shù)據(jù)庫崩潰甚至操作系統(tǒng)崩潰)的情況下,
仍然能夠保證數(shù)據(jù)的安全. 理想情況下就是恢復(fù)到系統(tǒng)崩潰前一刻的一致狀態(tài).
WAL 是如何實現(xiàn)這一點的呢? 這里簡單探討一下.
PostgreSQL 數(shù)據(jù)目錄中包括一個子目錄叫 pg_xlog, 這里包含一些很 "整齊" 的文件
(文件名全都是16進制的數(shù), 大小都是16MB(默認情況下)).
這些文件是聯(lián)機重做日志文件, 也就是很多 PostgreSQL 文檔中說的 XLog.
預(yù)寫式日志就表現(xiàn)在對 XLog 操作上. 當(dāng)一個事務(wù)要提交, 已被修改的數(shù)據(jù)
必須先被寫到(嚴格來說應(yīng)該是追加)到 XLog 中, 事務(wù)才能標(biāo)識為 "已提交".
這樣, 就算主數(shù)據(jù)文件在崩潰中已經(jīng)包含不完整的數(shù)據(jù)了, 仍然可以通過下面
的方法恢復(fù)到一致狀態(tài):
1 找到前一個一致的數(shù)據(jù)庫狀態(tài)點(這稱為CheckPoint)
2 將 XLog 以快進的方式重新施加到主數(shù)據(jù)文件上, 直到崩潰前的時刻.
從這個角度來將, PostgreSQL 已經(jīng)做得非常好了, 但仍然有一些問題.
比如, 如果介質(zhì)(磁盤)發(fā)生故障, 整個數(shù)據(jù)庫文件, 包括主數(shù)據(jù)文件和日志
都不能讀取, 又該怎么辦呢?
目前, 我們只能定時通過 pg_dump 等工具把整個數(shù)據(jù)庫 dump 下來, 或者
關(guān)閉數(shù)據(jù)庫, 將數(shù)據(jù)目錄整個復(fù)制到另外的地方.
然后使用這樣的備份來恢復(fù)由介質(zhì)故障引起的數(shù)據(jù)庫災(zāi)難.
很顯然, 這不能滿足我們的要求, 通常, 我們都不可能以非常高
的頻率進行 pg_dump. 一旦發(fā)生災(zāi)難, 就最多恢復(fù)到上一次執(zhí)行 pg_dump 的時刻了.
沒有更好的辦法了嗎?
如果我們能對數(shù)據(jù)庫的做不間斷的增量備份, 不就可以到達我們的目的了嗎?
這個想法到是好, 可怎么捕捉對數(shù)據(jù)文件做的修改(同時還不要忘記事務(wù)的原子性)?
對數(shù)據(jù)文件的修改是分布于整個數(shù)據(jù)文件各處的, 很難對它們進行
所以, 這個方法是不現(xiàn)實的.
現(xiàn)實的方法還是要通過 WAL 系統(tǒng)來實現(xiàn). 請注意前面我們已經(jīng)討論過的, 對 XLog
的寫實際上是追加. 這一點使得要增量備份 XLog 成為可能.
目前, PostgreSQL 為了能限制 XLog 的大小, 采用了多個段(也就是多個文件)的方式,
循環(huán)利用磁盤空間 -- 當(dāng)寫滿前一個 XLog 文件, 就產(chǎn)生一個新的, 并且讓
文件名代表 XLog 的編號, 同時, 如果可能, 刪除過期的 XLog 文件.
如果我們能在 PostgreSQL 刪除過期的 XLog 之前將它們復(fù)制到另外一個磁盤甚至其他
計算機, 不就能夠?qū)崿F(xiàn)增量備份日志了嗎?
當(dāng)災(zāi)難發(fā)生的時候, 就可以在一個完整備份的基礎(chǔ)上, 連續(xù)施加備份的 XLog 進行
redu, 直至恢復(fù)到最后一次歸檔(復(fù)制到其他目錄或計算機)的日志.
實際上, 這種方法也正是 Oracle 數(shù)據(jù)庫的歸檔模式所采用的方法.
下面這個實驗可以加深理解
1 初始化數(shù)據(jù)庫目錄
$ initdb -D db
2 創(chuàng)建數(shù)據(jù)庫
$ pg_ctl -D db start
$ createdb test
$ psql test
test=# create table t(a int);
test=# insert into t values(1);
test=# insert into t values(2);
test=# insert into t values(3);
test=# \q
3 全備份數(shù)據(jù)庫: 在不關(guān)閉數(shù)據(jù)庫(也就是說, 不要運行 pg_ctl -D db stop)
的情況下復(fù)制數(shù)據(jù)庫目錄. 注意, 這里采用了一種非常規(guī)手段, 僅僅是為了實驗,
不要在正式應(yīng)用中使用. 目的是為了讓將來的恢復(fù)能自動開始.
$ cp -a db db.backup
4 繼續(xù)修改數(shù)據(jù)庫
$ psql test
test=# insert into t values(100);
test=# insert into t values(200);
test=# insert into t values(300);
test=# \q
5 備份日志(XLog)文件 (由于修改量很小, 實際上只有一個日志文件)
$ mkdir pg_xlog
$ cp db/pg_xlog/* pg_xlog
6 模擬災(zāi)難
$ pg_ctl -D db stop
$ rm -rf db # 可以不用真的刪除, 只是認為它已經(jīng)不存在了
7 進行災(zāi)難恢復(fù)
$ cp -a db.backup db.restore
$ cp -f pg_xlog/* db.restore/pg_xlog
$ postmaster -D db.restore # 沒有用 pg_ctl 啟動,
# 為了更清楚看到日志(此日志非彼日志)輸出
LOG: database system was interrupted at 2004-04-15 18:12:47 CST
LOG: checkpoint record is at 0/9B1058
LOG: redo record is at 0/9B1058; undo record is at 0/0; shutdown TRUE
LOG: next transaction ID: 536; next OID: 17142
LOG: database system was not properly shut down; automatic recovery in progress
LOG: redo starts at 0/9B1098
LOG: record with zero length at 0/9D4458
LOG: redo done at 0/9D4434
LOG: database system is ready
$ psql test # 另外開一個控制臺
test=# select * from t;
a
-----
1
2
3
100
200
300
(6 rows)
可見, 數(shù)據(jù)庫已經(jīng)已經(jīng)恢復(fù)了到了災(zāi)難發(fā)生前的一刻.
當(dāng)然, 這個實驗數(shù)據(jù)量很小只產(chǎn)生并復(fù)制了一個日志文件, 而且復(fù)制的日志文件
還是當(dāng)前正在工作的, 和前面描述的不完全一致. 更深入的實驗大家可以下來做.
實際的聯(lián)機熱備份(也叫PITR(Point In Time Recovery))還有很多細節(jié), 不過
總的來說, PostgreSQL 離實現(xiàn)聯(lián)機熱備份已經(jīng)很近很近了! 也許下一個版本我們就能看到
這個令人興奮的功能了. 我們熱切地期待著!
她已經(jīng)為我們做了這么多, 我們能為她做點什么呢?
以上內(nèi)容僅代表我自己的理解, 不正之處敬請指出.
kernel
2004.4.15
轉(zhuǎn)自: http://bbs.pgsqldb.com/index.php?t=msg&th=3739&start=0
我們知道, PostgreSQL 擁有 WAL(預(yù)寫式日志) 已經(jīng)有一段時間了.
WAL 的一個重要好處就是能在系統(tǒng)崩潰(數(shù)據(jù)庫崩潰甚至操作系統(tǒng)崩潰)的情況下,
仍然能夠保證數(shù)據(jù)的安全. 理想情況下就是恢復(fù)到系統(tǒng)崩潰前一刻的一致狀態(tài).
WAL 是如何實現(xiàn)這一點的呢? 這里簡單探討一下.
PostgreSQL 數(shù)據(jù)目錄中包括一個子目錄叫 pg_xlog, 這里包含一些很 "整齊" 的文件
(文件名全都是16進制的數(shù), 大小都是16MB(默認情況下)).
這些文件是聯(lián)機重做日志文件, 也就是很多 PostgreSQL 文檔中說的 XLog.
預(yù)寫式日志就表現(xiàn)在對 XLog 操作上. 當(dāng)一個事務(wù)要提交, 已被修改的數(shù)據(jù)
必須先被寫到(嚴格來說應(yīng)該是追加)到 XLog 中, 事務(wù)才能標(biāo)識為 "已提交".
這樣, 就算主數(shù)據(jù)文件在崩潰中已經(jīng)包含不完整的數(shù)據(jù)了, 仍然可以通過下面
的方法恢復(fù)到一致狀態(tài):
1 找到前一個一致的數(shù)據(jù)庫狀態(tài)點(這稱為CheckPoint)
2 將 XLog 以快進的方式重新施加到主數(shù)據(jù)文件上, 直到崩潰前的時刻.
從這個角度來將, PostgreSQL 已經(jīng)做得非常好了, 但仍然有一些問題.
比如, 如果介質(zhì)(磁盤)發(fā)生故障, 整個數(shù)據(jù)庫文件, 包括主數(shù)據(jù)文件和日志
都不能讀取, 又該怎么辦呢?
目前, 我們只能定時通過 pg_dump 等工具把整個數(shù)據(jù)庫 dump 下來, 或者
關(guān)閉數(shù)據(jù)庫, 將數(shù)據(jù)目錄整個復(fù)制到另外的地方.
然后使用這樣的備份來恢復(fù)由介質(zhì)故障引起的數(shù)據(jù)庫災(zāi)難.
很顯然, 這不能滿足我們的要求, 通常, 我們都不可能以非常高
的頻率進行 pg_dump. 一旦發(fā)生災(zāi)難, 就最多恢復(fù)到上一次執(zhí)行 pg_dump 的時刻了.
沒有更好的辦法了嗎?
如果我們能對數(shù)據(jù)庫的做不間斷的增量備份, 不就可以到達我們的目的了嗎?
這個想法到是好, 可怎么捕捉對數(shù)據(jù)文件做的修改(同時還不要忘記事務(wù)的原子性)?
對數(shù)據(jù)文件的修改是分布于整個數(shù)據(jù)文件各處的, 很難對它們進行
所以, 這個方法是不現(xiàn)實的.
現(xiàn)實的方法還是要通過 WAL 系統(tǒng)來實現(xiàn). 請注意前面我們已經(jīng)討論過的, 對 XLog
的寫實際上是追加. 這一點使得要增量備份 XLog 成為可能.
目前, PostgreSQL 為了能限制 XLog 的大小, 采用了多個段(也就是多個文件)的方式,
循環(huán)利用磁盤空間 -- 當(dāng)寫滿前一個 XLog 文件, 就產(chǎn)生一個新的, 并且讓
文件名代表 XLog 的編號, 同時, 如果可能, 刪除過期的 XLog 文件.
如果我們能在 PostgreSQL 刪除過期的 XLog 之前將它們復(fù)制到另外一個磁盤甚至其他
計算機, 不就能夠?qū)崿F(xiàn)增量備份日志了嗎?
當(dāng)災(zāi)難發(fā)生的時候, 就可以在一個完整備份的基礎(chǔ)上, 連續(xù)施加備份的 XLog 進行
redu, 直至恢復(fù)到最后一次歸檔(復(fù)制到其他目錄或計算機)的日志.
實際上, 這種方法也正是 Oracle 數(shù)據(jù)庫的歸檔模式所采用的方法.
下面這個實驗可以加深理解
1 初始化數(shù)據(jù)庫目錄
$ initdb -D db
2 創(chuàng)建數(shù)據(jù)庫
$ pg_ctl -D db start
$ createdb test
$ psql test
test=# create table t(a int);
test=# insert into t values(1);
test=# insert into t values(2);
test=# insert into t values(3);
test=# \q
3 全備份數(shù)據(jù)庫: 在不關(guān)閉數(shù)據(jù)庫(也就是說, 不要運行 pg_ctl -D db stop)
的情況下復(fù)制數(shù)據(jù)庫目錄. 注意, 這里采用了一種非常規(guī)手段, 僅僅是為了實驗,
不要在正式應(yīng)用中使用. 目的是為了讓將來的恢復(fù)能自動開始.
$ cp -a db db.backup
4 繼續(xù)修改數(shù)據(jù)庫
$ psql test
test=# insert into t values(100);
test=# insert into t values(200);
test=# insert into t values(300);
test=# \q
5 備份日志(XLog)文件 (由于修改量很小, 實際上只有一個日志文件)
$ mkdir pg_xlog
$ cp db/pg_xlog/* pg_xlog
6 模擬災(zāi)難
$ pg_ctl -D db stop
$ rm -rf db # 可以不用真的刪除, 只是認為它已經(jīng)不存在了
7 進行災(zāi)難恢復(fù)
$ cp -a db.backup db.restore
$ cp -f pg_xlog/* db.restore/pg_xlog
$ postmaster -D db.restore # 沒有用 pg_ctl 啟動,
# 為了更清楚看到日志(此日志非彼日志)輸出
LOG: database system was interrupted at 2004-04-15 18:12:47 CST
LOG: checkpoint record is at 0/9B1058
LOG: redo record is at 0/9B1058; undo record is at 0/0; shutdown TRUE
LOG: next transaction ID: 536; next OID: 17142
LOG: database system was not properly shut down; automatic recovery in progress
LOG: redo starts at 0/9B1098
LOG: record with zero length at 0/9D4458
LOG: redo done at 0/9D4434
LOG: database system is ready
$ psql test # 另外開一個控制臺
test=# select * from t;
a
-----
1
2
3
100
200
300
(6 rows)
可見, 數(shù)據(jù)庫已經(jīng)已經(jīng)恢復(fù)了到了災(zāi)難發(fā)生前的一刻.
當(dāng)然, 這個實驗數(shù)據(jù)量很小只產(chǎn)生并復(fù)制了一個日志文件, 而且復(fù)制的日志文件
還是當(dāng)前正在工作的, 和前面描述的不完全一致. 更深入的實驗大家可以下來做.
實際的聯(lián)機熱備份(也叫PITR(Point In Time Recovery))還有很多細節(jié), 不過
總的來說, PostgreSQL 離實現(xiàn)聯(lián)機熱備份已經(jīng)很近很近了! 也許下一個版本我們就能看到
這個令人興奮的功能了. 我們熱切地期待著!
她已經(jīng)為我們做了這么多, 我們能為她做點什么呢?
以上內(nèi)容僅代表我自己的理解, 不正之處敬請指出.
kernel
2004.4.15
轉(zhuǎn)自: http://bbs.pgsqldb.com/index.php?t=msg&th=3739&start=0
posted on 2005-04-19 13:39 weidagang2046 閱讀(9716) 評論(1) 編輯 收藏 所屬分類: Database