友情提示:Postgres2015全国用户大会将于11月20至21日在北京丽亭华苑酒店召开。 报名链接:http://postgres2015.eventdove.com/

本期热点嘉宾:李海翔

网名那海蓝蓝,从事数据库研发、数据库测试与技术管理等工作10余年,对数据库的内核有深入研究,长于PostgreSQL和MySQL等开源数据库的内核与架构。现任职于Oracle公司MySQL全球开发团队,从事查询优化技术的研究和MySQL查询优化器的开发工作。业余时间喜欢分享个人心得于博客http://blog.163.com/li_hx/和微博“@那海蓝蓝”。著有《数据库查询优化器的艺术》一书。本次大会上的演讲主题为:《PostgreSQL,视图优化》。


嘉宾佳作:Postgresql日志系统的实现(一)

1、概述

PG9.x版本提供了较为完善的备份与恢复机制,包括有备份(物理备份和逻辑备份)与恢复机制。下面就PG的实现,进行了初步分析。

2、术语

2.1 物理备份
物理备份是指将数据库文件从一个物理位置复制到另一个位置。需要进行备份的数据库文件包括数据文件和控制文件等。这种备份方式是以操作系统下的“文件”为单位进行的。
物理备份按照备份时数据库的状态可以分为如下两种类型:
1)联机备份,也称为“热备份”,是在数据库服务期启动并可在进行其他操作时进行的备份;
2)脱机备份,也称为“冷备份”,是在数据库服务器关闭时进行的备份。
2.2 物理恢复 在数据库瘫痪或者状态不一致之后,将数据库恢复到某一个一致状态。
物理恢复通常包含了两个概念:数据库修复(Restore)和数据库恢复(Recovery)。
1)数据库修复(database restore)
利用备份的数据库文件来替换已经损坏的数据库文件,这项操作主要是利用操作系统的命令完成的(也是基于操作系统文件的角度进行的)。
2)数据库恢复(database recovery)
利用日志恢复丢失的数据,这项操作是数据库服务器完成的。
2.3 逻辑备份
逻辑备份是指利用一些客户端工具(PG使用pg_dump等)通过执行SQL语句的方式将数据库中的数据读取出来,然后再写入一个二进制文件中。此种方式可以选择数据库中存在的许多不同“对象”,如表、视图、存储过程等,不是基于文件方式,所以称为“逻辑”。
2.4 逻辑还原
逻辑还原是指利用一些客户端工具(PG使用pg_restore/psql等工具)从备份出来的二进制文件中读取数据,并通过执行SQL语句的方式将他们写入到数据库中。

3、使用日志进行恢复的基本原理

要想恢复系统丢失的数据,做好备份工作很重要。但是,基于日志进行恢复的方式却是备份的前提。这需要了解恢复的一些基本原理。
3.1. 事务故障的恢复
事务故障是指事务在运行至正常终止点前被终止,这时恢复子系统应利用日志文件撤销(UNDO)此事务已对数据库进行的修改(但如果使用预写日志方式,则不需要多虑事务故障)。事务故障恢复由系统自动完成。恢复步骤:
(1)反向扫描日志文件,查找该事务的更新操作。
(2)对该事务的更新操作执行逆操作。即将日志文件中“更新前的值”写入数据库。这样,如果记录中是插入操作,则相当于做删除操作,若记录中是删除操作,则做插入操作;若是修改操作,则相当于用修改前值代替修改后值。
(3)继续反向扫描日志文件,查找该事务的其他更新操作,并做同样处理。
(4)如此处理下去,直至读到此事务的开始标记,事务故障恢复完成。
3.2. 系统故障的恢复
系统故障是指造成系统停止运转的任何事件,使得系统要重新启动。系统故障造成数据库不一致状态的原因有两个:一是未完成事务对数据库的更新可能已经写入数据库,二是已提交事务对数据库的更新可能还留在缓冲区没来得及写入数据库。因此恢复操作就是要撤销故障发生时未完成的事务,重做已完成的事务。这种操作就要依赖有备份好的数据、日志等信息。恢复步骤:
(1)  正向扫描日志文件,找出故障发生前已经提交的事务(这些事务既有BEGIN TRANSACTION记录,也有COMMIT记录),将其事务标识记入重做(REDO)队列。同时找出故障发生时尚未完成的事务(这些事务只有BEGIN TRANSACTION记录,无相应的COMMIT记录),将其事务标识记入撤销(UNDO)队列。
(2)  对撤销队列中的各个事务进行撤销(UNDO)处理
反向扫描日志文件,对每个UDO事务的更新操作执行逆操作。即将日志记录中“更新前的值”写入数据库。
(3)  对重做队列中的各个事务进行重做(REDO)处理
正向扫描日志文件,对每个REDO事务重新执行日志文件登记的操作。即将日志记录中“更新后的值”写入数据库。
3.3. 介质故障的恢复
发生介质故障后,磁盘上的物理文件和日志文件被破坏,恢复方法是重装数据库,拷贝物理备份的文件到数据库系统目录下,然后利用日志重做已完成的事务:
(1)装入数据库后备副本,使数据库恢复到最近一次转储时的一致性状态。对于动态转储的数据库副本,还需要同时装入开始转储时刻的日志文件副本,利用恢复系统故障的方法(REDO+UNDO)才能将数据库恢复到一致性状态。PG使用WAL方式记载日志信息,所以在恢复阶段,只用了Redo的方式。
(2)装入相应的日志文件副本(转储结束时刻的日志文件副本),重做已完成的事务。
(3)介质故障的恢复和系统故障恢复的入口都是startupxlog(),但是介质故障的恢复要读入备份文件,设定恢复的参数,然后调用相应资源的恢复方法函数进行恢复。
(4)即时恢复(PITR):在任何时候,PostgreSQL 都在集群的数据目录的 pg_xlog/ 子目录里维护着一套预写日志(WAL)。 这些日志记录着每一次对数据库的数据文件的修改的细节。这些日志存在是为了防止崩溃:如果系统崩溃, 数据库可以通过"重放"上次检查点以来的日志记录以恢复数据库的完整性。 但是,日志的存在让它还可以用于第三种备份数据库的策略:我们可以组合文件系统备份与 WAL 文件的备分。 如果需要恢复,我们就恢复备份,然后重放备份了的WAL文件,把备份恢复到当前的时间或指定的时间点上。之所以能这样做,是因为PG在记录日志信息的时候,记载了系统的时间信息到日志中。
(5)时间线: 我们可以把数据库恢复到管理员(DBA)开始备份以来的任意时刻的状态。PostgreSQL 有个叫时间线的概念。 每次即时恢复到一个比 WAL 序列的结尾要早的时刻,那么就创建一个新的时间线, 以表示在该次恢复之后生成的 WAL 记录。(不过,如果恢复动作一直处理到 WAL 的结尾, 我们就不会开始一个新的时间线:我们只是扩展现有个那个。)时间线 ID 号是 WAL 段文件名的一部分, 因此新的时间线并不会覆盖以前的时间线生成的WAL 数据。实际上我们可以归档许多不同的时间线。 虽然这些看起来像没用的特性,但它却可能常常是救命稻草。考虑一下你并不很确信应该恢复到那个时刻的情况, 这个时候你不得不做好几次试验性即时恢、复然后从中找到旧历史中最好的分支。 如果没有时间线,那么这个过程可能很快就会导致无法管理的混乱。 有了时间线,你可以恢复到任意以前的状态, 包括恢复到后来放弃的时间线分支的状态。 实际上,这里讲到的一些涉及恢复的内容,也可以应用到发生系统故障的时候,要想少丢失数据,这通常依赖与管理员的备份恢复策略和其实际需求。

4、PG备份方式

4.1 PG8.x提供的备份方式
(1)SQL 转储:使用“pg_dump”或“pg_dumpall”完成,逻辑备份的一种方式。
(2)文件系统级别备份:拷贝相关文件,属于物理备份方式。
(3)在线备份:即“归档”,但是PG提出本方式,需要配合文件级的物理备份方式进行,先完成一次文件级的物理完全备份,以后不断的做日志(xlog)的归档,以完成完全备份之后新的信息的备份,属于文件级别的备份,但不需要停止数据库的运行。
4.2      PG8.x提供的备份方式使用方法
4.2.1 SQL转储方式
可以把数据库中的信息当作文本或其他格式输出
语法:
  pg_dump [OPTION]... [DBNAME]
可选项:
  -f, --file=FILENAME   输出的文件名称
  -F, --format=c|t|p       输出的文件格式 (custom, tar, plain text)
  -i, --ignore-version     处理服务器因版本不同带来的差异(即:忽略服务器版本不同造成的差异,有可能导致一些信息丢失)
  -v, --verbose           输出详细信息
  -Z, --compress=0-9     对于被压缩格式来讲,设置压缩级别
  --help                只输出帮助信息
  --version              只输出版本信息
 
控制输出内容的选项:
  -a, --data-only          只导出数据,不导出schema信息
  -c, --clean              在clean (drop) schema prior to create
  -C, --create             在导出信息中包括创建数据库的命令
  -d, --inserts            以“insert”语句方式导出数据,非“copy”方式(PG提供直接copy数据到数据库的方式)
  -D, --column-inserts     以“insert”语句方式导出数据,“insert”语句中带有列名
  -E, --encoding=ENCODING    以某种编码方式导出数据
  -n, --schema=SCHEMA      只导出指定的schema中的信息
  -o, --oids                     导出信息中包括“OID”列信息
  -O, --no-owner               在“plain”文本格式中使用,忽略对象的所属关系
  -s, --schema-only                     只导出指定的schema信息,不包括数据
  -S, --superuser=NAME         在“plain”文本格式中使用,指定超级用户的用户名
  -t, --table=TABLE              只导出指定的表信息(包括数据)
  -x, --no-privileges                不导出权限信息
  -X disable-dollar-quoting, --disable-dollar-quoting
                           使用标准的SQL符号,不允许存在“$”符号
  -X disable-triggers, --disable-triggers
                           disable triggers during data-only restore
  -X use-set-session-authorization, --use-set-session-authorization
                           use SESSION AUTHORIZATION commands instead of
                           OWNER TO commands
 
连接选项:
  -h, --host=HOSTNAME      数据库服务器主机名称
  -p, --port=PORT              端口号
  -U, --username=NAME        用户名
  -W, --password               密码

5、PG的恢复方式

5.1.SQL 转储:使用“pg_restore”完成,逻辑恢复的一种方式,命令中参数同“pg_dumpall”等。
5.2.文件系统级别备份:把备份的文件拷贝再拷回到系统的数据目录下,属于物理恢复方式。
5.3.从在线备份中恢复:(摘自:http://www.pgsqldb.org/pgsqldoc-8.1c/backup-online.html )
(1)停止 postmaster,如果它还在运行的话。
(2)如果你还有足够的空间,把整个集群数据目录和所有表空间拷贝到一个临时位置, 以防万一你之后还需要它们。请注意这个预防措施要求你在系统里有足够的剩余空间来保存现有库的两份拷贝。 如果你没有足够的空间,那么你至少需要把集群数据目录的 pg_xlog 子目录的内容拷贝到安全的地方, 因为它们可能包含系统宕掉的时候还没有归档的日志。
(3)然后清理掉所有在该集群数据目录里的现存文件, 以及所有你使用的表空间里根目录下的现存文件。
(4)从你的备份转储中恢复数据库文件。要小心用正确的所有者(数据库系统用户,而不是 root!)和权限恢复它们。如果你使用了表空间,你可能需要核实在 pg_tblspc/ 里的符号连接都得到正确恢复。
(5)删除任何目前还在 pg_xlog/ 里的文件;这些文件来自备份转储,因此它们可能比目前的老。 如果你就根本没有归档 pg_xlog/,那么重建之,要注意也要重建子目录 pg_xlog/archive_status/。
(6)如果你有在步骤 2 里面保存的 WAL 段文件,那么把它们拷贝到 pg_xlog/。 (最好是拷贝它们,而不是把它们移动回来,这样即使发生了糟糕的事情,你需要重启的时候, 你也依然拥有未修改的文件。)
(7)在集群数据目录里创建一个恢复命令文件 recovery.conf(参阅 Recovery Settings)。 你可能还需要临时修改pg_hba.conf 以避免普通用户连接,直到你确信恢复已经正常了为止。
(8)启动 postmaster。postmaster 将进入恢复模式并且继续读取它需要的归档的 WAL 文件。 在恢复过程完成后,postmaster 将把 recovery.conf 改名为 recovery.done (以避免不小心因后面的崩溃再次进入恢复模式)然后开始正常的数据库操作。
(9)检查数据库的内容以确保你已经恢复到你期望的位置。 如果还没有,回到步骤 1。如果全部正常,则恢复pg_hba.conf 成正常状态,允许你的用户登录。

  • 2015Postgres全国大会官方报名地址:http://postgres2015.eventdove.com/
  • 官方网站:http://www.postgres.cn
  • 报名地址:http://postgres2015.eventdove.com/
  • 官方QQ群:
    1. PostgreSQL专业1群: 3336901(已满)
    2. PostgreSQL专业2群: 100910388
    3. PostgreSQL专业3群: 150657323
  • 官方微信公众号:PostgresChina
  • 官方认证新浪微博:PostgreSQL用户会
  • 请在登录后发表评论,否则无法保存。
    © 2010 PostgreSQL中文社区