加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

PostgreSQL多种恢复实例分析

发布时间:2020-12-13 16:56:37 所属栏目:百科 来源:网络整理
导读:数据库版本:postgresql 9.6.0 作者:高铭杰 邮箱:jackgo73@outlook.com 日期:2017年4月2日 Postgresql归档恢复实例分析(时间线机制) 这篇文章根据实例介绍Postgresql归档恢复的方法,时间线的含义。 1 参数配置 sed -ir "s/# *max_wal_senders . */ max_w

数据库版本:postgresql 9.6.0
作者:高铭杰
邮箱:jackgo73@outlook.com
日期:2017年4月2日


Postgresql归档恢复实例分析(时间线机制)

这篇文章根据实例介绍Postgresql归档恢复的方法,时间线的含义。

1 参数配置

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 数据操作

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,1000))" Sat Apr 1 10:10:53 CST 2017

3 制作基础备份

sed -ir "s/#*max_wal_senders.*/max_wal_senders = 10/" $PGDATA/postgresql.conf
配置pg_hba.conf通道
pg_basebackup -Fp -P -x -D ~/bin/data/pg_root21 -l basebackup21

4 数据库上继续进行业务操作(模拟在基础备份后,业务继续下发,然后发生故障)

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

没有设置archive_timeout,整个数据目录被删除

5 数据目录被rm -rf掉了(模拟误操作)

rm -rf pg_root20/

6 归档恢复

cp -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 恢复结果

test02存在,但是其中的数据被认为是未提交事务,表为空(最后一个xlog文件的内容全部遗失了)。


情况2

设置archive_timeout,整个数据目录被删除,归档timeout为60s,在test02表数据灌入之后,xlog自动切换并归档
(sed -ir "s/#*archive_timeout.*/archive_timeout = 60/" $PGDATA/postgresql.conf)

5 数据目录被rm -rf掉了(模拟误操作)

rm -rf pg_root20/

6 归档恢复

cp -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 恢复结果

test02存在,数据也存在(由于归档设置了超时切换,最后一个xlog会被归档)。


情况3(重要)

设置archive_timeout,根据估计时间点尝试多次恢复,不能确定想恢复到具体哪个时间点,归档timeout为60s
(sed -ir "s/#*archive_timeout.*/archive_timeout = 60/" $PGDATA/postgresql.conf)

5 数据目录被rm -rf掉了(模拟误操作)

rm -rf pg_root20/

6 归档恢复

cp -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’ (基础备份时间之前)

这里------------------------------------------------------------------------
-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--

结果:
恢复时间定到了基础备份之前,所以这里会恢复到最早时间点:基础备份点。
LOG: recovery stopping before commit of transaction 1175,time 2017-04-01 10:15:59.597495+08
注意:无法恢复到基础备份之前的点,所以再做基础备份时,请保证数据一致性。

(2) recovery_target_time = ‘2017-4-1 10:10: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--

结果:
恢复时间定到了基础备份之前,所以这里会恢复到最早时间点:基础备份点。
LOG: recovery stopping before commit of transaction 1175,time 2017-04-01 10:15:59.597495+08
注意:无法恢复到基础备份之前的点,所以再做基础备份时,请保证数据一致性。

(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--

结果:
表test02存在,但没有数据。说明如果时间在基础备份点之后,可以恢复到任意时间点。恢复后会创建新时间线。
LOG: last completed transaction was at log time 2017-04-01 10:15:59.597495+08

(3.1) 在(3)的基础上继续进行恢复: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--

结果:
同3,这次恢复创建了一条新的时间线3,这条时间线上面进行恢复的话,数据库会去archive里面去找时间线2的xlog,但是归档目录中的日志应该都是时间线1的,所以会报错找不到xlog。
cp: cannot stat pathto/archive/00000002000000000000000A': No such file or directory

注意: 根据上述结论,请在每次恢复时都使用原始归档文件,即如果尝试再次恢复,请重新使用基础备份进行恢复,不要在前一次恢复的基础上继续进行,否则由于时间线切换,会找不到归档文件。


其他

  1. 压缩的归档日志
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(几个重要参数)

    Postgresql9.6手册(彭煜玮翻译)

    restore_command (string)
    用于获取 WAL 文件系列的一个已归档段的本地 shell 命令。这个参数是归档恢复所必需的,但是对于流复制是可选的。在该字符串中的任何%f会被替换为从归档中获得的文件的名字,并且任何%p会被在服务器上的复制目标路径名替换(该路径名是相对于当前工作目录的,即集簇的数据目录)。任何%r会被包含上一个可用重启点的文件的名字所替换。在那些必须被保留用于使得一次恢复变成可重启的文件中,这个文件是其中最早的一个,因此这个信息可以被用来把归档截断为支持从当前恢复重启所需的最小值。%r通常只被温备配置(见Section 26.2)所使用。要嵌入一个真正的%字符,需要写成%%。很重要的一点是,该命令只有在成功时才返回一个为零的退出状态。该命令将会被询问不存在于归档中的文件名,当这样被询问时它必须返回非零。

    recovery_target_time (timestamp)
    这个参数指定恢复将进入的时间戳。

    recovery_target_xid (string)
    这个参数指定恢复将进入的事务 ID。记住虽然事务 ID 是在事务开始时顺序分配的,但是事务可能以不同的数字顺序完成。那些在指定事务之前(也可以包括该事务)提交的事务将被恢复。精确的停止点也受到recovery_target_inclusive的影响。

    recovery_target_timeline (string)
    指定恢复到一个特定的时间线中。默认值是沿着基础备份建立时的当前时间线恢复。将这个参数设置为latest会恢复到该归档中能找到的最新的时间线,这在一个后备服务器中有用。除此之外,你只需要在复杂的重恢复情况下设置这个参数,在这种情况下你需要返回到一个状态,该状态本身是在一次时间点恢复之后到达的。相关讨论见Section25.3.5

  2. 关于时间线

    Postgresql9.6手册(彭煜玮翻译)

      将数据库恢复到一个之前的时间点的能力带来了一些复杂性,这和有关时间旅行和平行宇宙的科幻小说有些相似。例如,在数据库的最初历史中,假设你在周二晚上5:15时丢弃了一个关键表,但是一直到周三中午才意识到你的错误。不用苦恼,你取出你的备份,恢复到周二晚上5:14的时间点,并上线运行。在数据库宇宙的这个历史中,你从没有丢弃该表。但是假设你后来意识到这并非一个好主意,并且想回到最初历史中周三早上的某个时间。你没法这样做,在你的数据库在线运行期间,它重写了某些WAL段文件,而这些文件本来可以将你引向你希望回到的时间。因此,为了避免出现这种状况,你需要将完成时间点恢复后生成的WAL记录序列与初始数据库历史中产生的WAL记录序列区分开来。   要解决这个问题,PostgreSQL有一个时间线概念。无论何时当一次归档恢复完成,一个新的时间线被创建来标识恢复之后生成的WAL记录序列。时间线ID号是WAL段文件名的一部分,因此一个新的时间线不会重写由之前的时间线生成的WAL数据。实际上可以归档很多不同的时间线。虽然这可能看起来是一个无用的特性,但是它常常扮演救命稻草的角色。考虑到你不太确定需要恢复到哪个时间点的情况,你可能不得不做多次时间点恢复尝试和错误,直到最终找到从旧历史中分支出去的最佳位置。如果没有时间线,该处理将会很快生成一堆不可管理的混乱。而有了时间线,你可以恢复到任何之前的状态,包括早先被你放弃的时间线分支中的状态。 每次当一个新的时间线被创建,PostgreSQL会创建一个“时间线历史”文件,它显示了新时间线是什么时候从哪个时间线分支出来的。系统在从一个包含多个时间线的归档中恢复时,这些历史文件对于允许系统选取正确的WAL段文件非常必要。因此,和WAL段文件相似,它们也要被归档到WAL归档区域。历史文件是很小的文本文件,因此将它们无限期地保存起来的代价很小,而且也是很合适的(而段文件都很大)。如果你喜欢,你可以在一个历史文件中增加注释来记录如何和为什么要创建该时间线。当你由于试验的结果拥有了一大堆错综复杂的不同时间线时,这种注释将会特别有价值。   恢复的默认行为是沿着相同的时间线进行恢复,该时间线是基础备份创建时的当前时间线。如果你希望恢复到某个子女时间线(即,你希望回到在一次恢复尝试后产生的某个状态),你需要在recovery.conf中指定目标时间线ID。你不能恢复到早于该基础备份之前分支出去的时间线。

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读