weidagang2046的专栏

物格而后知致
随笔 - 8, 文章 - 409, 评论 - 101, 引用 - 0
数据加载中……

关于 PostgreSQL 备份恢复的心得

这段时间对 PostgreSQL 的备份恢复进行了一些研究, 有一些心得和大家分享一下.

我们知道, PostgreSQL 拥有 WAL(预写式日志) 已经有一段时间了.
WAL 的一个重要好处就是能在系统崩溃(数据库崩溃甚至操作系统崩溃)的情况下,
仍然能够保证数据的安全. 理想情况下就是恢复到系统崩溃前一刻的一致状态.

WAL 是如何实现这一点的呢? 这里简单探讨一下.

PostgreSQL 数据目录中包括一个子目录叫 pg_xlog, 这里包含一些很 "整齐" 的文件
(文件名全都是16进制的数, 大小都是16MB(默认情况下)).
这些文件是联机重做日志文件, 也就是很多 PostgreSQL 文档中说的 XLog.
预写式日志就表现在对 XLog 操作上. 当一个事务要提交, 已被修改的数据
必须先被写到(严格来说应该是追加)到 XLog 中, 事务才能标识为 "已提交".
这样, 就算主数据文件在崩溃中已经包含不完整的数据了, 仍然可以通过下面
的方法恢复到一致状态:

1 找到前一个一致的数据库状态点(这称为CheckPoint)
2 将 XLog 以快进的方式重新施加到主数据文件上, 直到崩溃前的时刻.

从这个角度来将, PostgreSQL 已经做得非常好了, 但仍然有一些问题.
比如, 如果介质(磁盘)发生故障, 整个数据库文件, 包括主数据文件和日志
都不能读取, 又该怎么办呢?

目前, 我们只能定时通过 pg_dump 等工具把整个数据库 dump 下来, 或者
关闭数据库, 将数据目录整个复制到另外的地方.
然后使用这样的备份来恢复由介质故障引起的数据库灾难.
很显然, 这不能满足我们的要求, 通常, 我们都不可能以非常高
的频率进行 pg_dump. 一旦发生灾难, 就最多恢复到上一次执行 pg_dump 的时刻了.

没有更好的办法了吗?

如果我们能对数据库的做不间断的增量备份, 不就可以到达我们的目的了吗?
这个想法到是好, 可怎么捕捉对数据文件做的修改(同时还不要忘记事务的原子性)?
对数据文件的修改是分布于整个数据文件各处的, 很难对它们进行
所以, 这个方法是不现实的.

现实的方法还是要通过 WAL 系统来实现. 请注意前面我们已经讨论过的, 对 XLog
的写实际上是追加. 这一点使得要增量备份 XLog 成为可能.
目前, PostgreSQL 为了能限制 XLog 的大小, 采用了多个段(也就是多个文件)的方式,
循环利用磁盘空间 -- 当写满前一个 XLog 文件, 就产生一个新的, 并且让
文件名代表 XLog 的编号, 同时, 如果可能, 删除过期的 XLog 文件.
如果我们能在 PostgreSQL 删除过期的 XLog 之前将它们复制到另外一个磁盘甚至其他
计算机, 不就能够实现增量备份日志了吗?
当灾难发生的时候, 就可以在一个完整备份的基础上, 连续施加备份的 XLog 进行
redu, 直至恢复到最后一次归档(复制到其他目录或计算机)的日志.

实际上, 这种方法也正是 Oracle 数据库的归档模式所采用的方法.

下面这个实验可以加深理解

1 初始化数据库目录

$ initdb -D db

2 创建数据库

$ 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 全备份数据库: 在不关闭数据库(也就是说, 不要运行 pg_ctl -D db stop)
的情况下复制数据库目录. 注意, 这里采用了一种非常规手段, 仅仅是为了实验,
不要在正式应用中使用. 目的是为了让将来的恢复能自动开始.

$ cp -a db db.backup

4 继续修改数据库

$ 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 模拟灾难

$ pg_ctl -D db stop
$ rm -rf db # 可以不用真的删除, 只是认为它已经不存在了

7 进行灾难恢复

$ 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)

可见, 数据库已经已经恢复了到了灾难发生前的一刻.

当然, 这个实验数据量很小只产生并复制了一个日志文件, 而且复制的日志文件
还是当前正在工作的, 和前面描述的不完全一致. 更深入的实验大家可以下来做.

实际的联机热备份(也叫PITR(Point In Time Recovery))还有很多细节, 不过
总的来说, PostgreSQL 离实现联机热备份已经很近很近了! 也许下一个版本我们就能看到
这个令人兴奋的功能了. 我们热切地期待着!

她已经为我们做了这么多, 我们能为她做点什么呢?


以上内容仅代表我自己的理解, 不正之处敬请指出.

kernel
2004.4.15


转自:
http://bbs.pgsqldb.com/index.php?t=msg&th=3739&start=0

posted on 2005-04-19 13:39 weidagang2046 阅读(9684) 评论(1)  编辑  收藏 所属分类: Database

评论

# re: 关于 PostgreSQL 备份恢复的心得  回复  更多评论   

PostgreSQL .NET
.NET data provider to direct access PostgreSQL database
2007-04-11 13:46 | qwe

只有注册用户登录后才能发表评论。


网站导航: