searchusermenu
  • 发布文章
  • 消息中心
点赞
收藏
评论
分享
原创

PostgreSQL的备份恢复和主从复制

2023-08-02 10:01:47
100
0

PostgreSQL的数据备份

首先,备份的目的是为了防止数据丢失。

1 逻辑备份

创建一个由SQL命令组成的文件,服务器利用SQL命令重建与转储时状态一样的数据库。通过pg_dump工具实现:

$ pg_dump testdb01 > db01.sql

$ pg_restore testdb02 < db01.sql

2 物理备份

PG数据库建立在文件系统之上,物理备份即是文件系统级别的备份。

2.1 冷备份

最简单直接的方法,即数据库停下来时完成文件备份,拷贝数据库的PGDATA目录即可。

$ tar -cf backup.tar /usr/local/pgsql/data

冷备份的缺点也就是备份时必须停止数据库。

2.2 热备份

在不停止数据库的情况下完成备份。有两种方式:

  1. 通过文件系统或块设备级别的一致性快照实现。但如果数据库跨越多个文件系统,无法对所有卷获得完全同步的快照。
  2. 基于时间点的备份(PITR)

这里重点介绍PITR。

2.2.1 PITR

数据库通过WAL日志保证数据不丢失,日志中记录数据文件的每一次改变。数据库异常崩溃后,通过重放最后一次Checkpoint点之后的日志,可以还原数据库状态,这就是PITR的原理。

Checkpoint是WAL日志中的位点,保证该位点之前所有shared buffer中的脏页均被刷盘

Checkpoint操作会向WAL日志写位点,其步骤如下:

  • 首先记录下Checkpoint开始的位置,记录为redo point。
  • 将shared buffer中的数据刷盘。
  • 此时数据库接收一条SQL INSERT。
  • Checkpoint刷脏结束,redo point之前的数据均已被刷盘,在WAL日志中记录Checkpoint位点。
  • 将最新的Checkpoint位点记录在pg_control文件中。

进行数据库恢复时,从pg_control文件中找到最新的Checkpoint位置,再从Checkpoint找到redo point位置,开始重放日志。数据1和2已经刷盘,只有INSERT 3需要重放。

基于WAL日志机制,可以先把数据库以文件系统的方式备份出来,同时把相应的WAL日志也备份出来。虽然直接复制数据文件会导致文件不一致(如复制多个文件不是同一时间),且一个数据块也可能不一致(刚复制完前4KB部分,数据块又写了整个8KB的块,此时复制的前4KB和后4KB不是一个完整的数据块),但通过重放WAL日志,依然可以把数据推到一致状态。

 

PostgreSQL的主从复制

基于上述的PG备份恢复原理,可以将基础备份恢复到一台新机器作为从库,并不停从原始数据库机器上接收WAL日志,在新机器上持续重放WAL,追上主库。

这里把WAL日志传送到另一台机器上的方法有两种。

1 WAL日志归档

日志归档会把在线的已写完的WAL日志移动到指定的归档目录。

postgresql.conf文件中做如下配置即可:

archive_mode = on
archive_command = 'cp %p /backup/pgarch/%f'

其中%p表示WAL日志文件的全路径名,%f表示不包括路径的WAL日志文件名。

也可以通过如scp命令把WAL日志复制到其他机器上:

archive_mode = on
archive_command = 'scp %p postgres@192.168.1.100:/backup/pgarch/%f'

但是由于已写完的日志文件才会被归档,因此使用这种方法会导致备库落后主库一个WAL日志文件

2 流复制

主库的WAL日志一产生则马上传递到从库,有异步/同步两种方式。

从库一直等待新的WAL日志,有新的日志则自动重放,直到主库宕机。类似MySQL的主从binlog复制。

3 主从部署实例:异步流复制Hot Standby数据库部署

Hot Standby数据库即可以提供只读服务的从库。

主从部署步骤如下:

3.1 主库准备工作

创建用户并授权,用于复制数据:

CREATE ROLE replica LOGIN;
ALTER ROLE replica REPLICATION;

同时还需要在pg_hba.conf中修改访问控制参数。

3.2 从库生成基础备份

使用pg_basebackup工具把整个数据库实例的数据物理地复制出来。

$ pg_basebackup -h 127.0.0.1 -p 5432 -U replica -F p -P -X stream -R -D /usr/local/pgsql/backupdata -l pgbackup202307241034

其中的参数含义:

  1. -h host:指定连接的数据库的IP地址。
  2. -p port:指定连接的端口。
  3. -U username:指定连接的用户名。
  4. -F p:指定输出格式为plain。
  5. -P:在备份过程中实时显示进度。
  6. -X stream:表示备份开始后启动一个流复制连接从主库接受WAL日志。
  7. -R:是否生成recovery.conf文件。
  8. -D directory:指定备份的目标目录。
  9. -l label:指定备份标识。

3.3 启动从库

设置从库hot_standby参数为on,让备库作为Hot Standby,可以对外提供只读服务。

通过pg_ctl启动从库后,自动连接上主库。

4 故障切换

进行故障切换前,首先需要修改数据库的wal_log_hints参数或打开checksum参数。之后才能使用pg_rewind命令进行恢复。

wal_log_hints参数full_page_writes参数一样,目的是为了防止块折断

数据库和操作系统的块大小不一致。PG的一个块大小是8KB,而Linux文件块大小为4KB。当数据库脏块刷盘时,底层由两个OS IO组成,第一次IO刷盘,而第二次发生故障,导致磁盘中数据块不完整。

参数设置为ON后,Checkpoint后一个块的第一次变脏后就要整块写入WAL日志,此后继续修改该块则只用记录修改的信息。如果发生块折断,以全页写入的块为基础恢复磁盘上的折断块。

MySQL使用double_write解决。可以从磁盘共享表空间恢复数据页。

  • buffer pool脏页刷盘时先写入内存中的doublewrite buffer。

  • 从doublewrite buffer写入磁盘共享表空间,连续存储,顺序写。

  • 再从doublewrite buffer写入实际表空间文件。

4.1 故障切换流程

  • 停主库(模拟故障)。

  • 停其他从库。

  • 将一个从库升级为主库:

    $ pg_ctl promote -D backupdata01/
  • 原主库和其他从库上执行pg_rewind

    $ pg_rewind -D data/ --source-server='host=127.0.0.1 port=5433 user=postgres'
  • 为原主库创建standby.signal文件,并启动原主库和其他从库。

4.2 pg_rewind原理

异步主从发生角色切换后,原主库的WAL目录中可能还有未同步到从库的内容,因此原主库无法直接切换为新主库的从库。使用pg_rewind可以修复原主库,不需要重建整个从库。

pg_rewind对比两个实例的差异点并找到差异点之前的最后一次Checkpoint,通过Checkpoint之后的WAL日志将备库推到和主库一致的状态,修复过程中会涉及到时间线修复。

4.3 时间线修复

先恢复到周三,运行一段时间后又需要恢复到周四。若没有时间线,数据库运行时会产生与旧WAL日志同名文件并覆盖旧日志,导致无法恢复到周四。

引入时间线,每次归档文件恢复完成后,创建一个新的时间线来区别新生成的WAL日志。时间线ID号是WAL文件名组成部分,不会覆盖旧时间线的日志。

0条评论
0 / 1000
benzecat
5文章数
0粉丝数
benzecat
5 文章 | 0 粉丝
原创

PostgreSQL的备份恢复和主从复制

2023-08-02 10:01:47
100
0

PostgreSQL的数据备份

首先,备份的目的是为了防止数据丢失。

1 逻辑备份

创建一个由SQL命令组成的文件,服务器利用SQL命令重建与转储时状态一样的数据库。通过pg_dump工具实现:

$ pg_dump testdb01 > db01.sql

$ pg_restore testdb02 < db01.sql

2 物理备份

PG数据库建立在文件系统之上,物理备份即是文件系统级别的备份。

2.1 冷备份

最简单直接的方法,即数据库停下来时完成文件备份,拷贝数据库的PGDATA目录即可。

$ tar -cf backup.tar /usr/local/pgsql/data

冷备份的缺点也就是备份时必须停止数据库。

2.2 热备份

在不停止数据库的情况下完成备份。有两种方式:

  1. 通过文件系统或块设备级别的一致性快照实现。但如果数据库跨越多个文件系统,无法对所有卷获得完全同步的快照。
  2. 基于时间点的备份(PITR)

这里重点介绍PITR。

2.2.1 PITR

数据库通过WAL日志保证数据不丢失,日志中记录数据文件的每一次改变。数据库异常崩溃后,通过重放最后一次Checkpoint点之后的日志,可以还原数据库状态,这就是PITR的原理。

Checkpoint是WAL日志中的位点,保证该位点之前所有shared buffer中的脏页均被刷盘

Checkpoint操作会向WAL日志写位点,其步骤如下:

  • 首先记录下Checkpoint开始的位置,记录为redo point。
  • 将shared buffer中的数据刷盘。
  • 此时数据库接收一条SQL INSERT。
  • Checkpoint刷脏结束,redo point之前的数据均已被刷盘,在WAL日志中记录Checkpoint位点。
  • 将最新的Checkpoint位点记录在pg_control文件中。

进行数据库恢复时,从pg_control文件中找到最新的Checkpoint位置,再从Checkpoint找到redo point位置,开始重放日志。数据1和2已经刷盘,只有INSERT 3需要重放。

基于WAL日志机制,可以先把数据库以文件系统的方式备份出来,同时把相应的WAL日志也备份出来。虽然直接复制数据文件会导致文件不一致(如复制多个文件不是同一时间),且一个数据块也可能不一致(刚复制完前4KB部分,数据块又写了整个8KB的块,此时复制的前4KB和后4KB不是一个完整的数据块),但通过重放WAL日志,依然可以把数据推到一致状态。

 

PostgreSQL的主从复制

基于上述的PG备份恢复原理,可以将基础备份恢复到一台新机器作为从库,并不停从原始数据库机器上接收WAL日志,在新机器上持续重放WAL,追上主库。

这里把WAL日志传送到另一台机器上的方法有两种。

1 WAL日志归档

日志归档会把在线的已写完的WAL日志移动到指定的归档目录。

postgresql.conf文件中做如下配置即可:

archive_mode = on
archive_command = 'cp %p /backup/pgarch/%f'

其中%p表示WAL日志文件的全路径名,%f表示不包括路径的WAL日志文件名。

也可以通过如scp命令把WAL日志复制到其他机器上:

archive_mode = on
archive_command = 'scp %p postgres@192.168.1.100:/backup/pgarch/%f'

但是由于已写完的日志文件才会被归档,因此使用这种方法会导致备库落后主库一个WAL日志文件

2 流复制

主库的WAL日志一产生则马上传递到从库,有异步/同步两种方式。

从库一直等待新的WAL日志,有新的日志则自动重放,直到主库宕机。类似MySQL的主从binlog复制。

3 主从部署实例:异步流复制Hot Standby数据库部署

Hot Standby数据库即可以提供只读服务的从库。

主从部署步骤如下:

3.1 主库准备工作

创建用户并授权,用于复制数据:

CREATE ROLE replica LOGIN;
ALTER ROLE replica REPLICATION;

同时还需要在pg_hba.conf中修改访问控制参数。

3.2 从库生成基础备份

使用pg_basebackup工具把整个数据库实例的数据物理地复制出来。

$ pg_basebackup -h 127.0.0.1 -p 5432 -U replica -F p -P -X stream -R -D /usr/local/pgsql/backupdata -l pgbackup202307241034

其中的参数含义:

  1. -h host:指定连接的数据库的IP地址。
  2. -p port:指定连接的端口。
  3. -U username:指定连接的用户名。
  4. -F p:指定输出格式为plain。
  5. -P:在备份过程中实时显示进度。
  6. -X stream:表示备份开始后启动一个流复制连接从主库接受WAL日志。
  7. -R:是否生成recovery.conf文件。
  8. -D directory:指定备份的目标目录。
  9. -l label:指定备份标识。

3.3 启动从库

设置从库hot_standby参数为on,让备库作为Hot Standby,可以对外提供只读服务。

通过pg_ctl启动从库后,自动连接上主库。

4 故障切换

进行故障切换前,首先需要修改数据库的wal_log_hints参数或打开checksum参数。之后才能使用pg_rewind命令进行恢复。

wal_log_hints参数full_page_writes参数一样,目的是为了防止块折断

数据库和操作系统的块大小不一致。PG的一个块大小是8KB,而Linux文件块大小为4KB。当数据库脏块刷盘时,底层由两个OS IO组成,第一次IO刷盘,而第二次发生故障,导致磁盘中数据块不完整。

参数设置为ON后,Checkpoint后一个块的第一次变脏后就要整块写入WAL日志,此后继续修改该块则只用记录修改的信息。如果发生块折断,以全页写入的块为基础恢复磁盘上的折断块。

MySQL使用double_write解决。可以从磁盘共享表空间恢复数据页。

  • buffer pool脏页刷盘时先写入内存中的doublewrite buffer。

  • 从doublewrite buffer写入磁盘共享表空间,连续存储,顺序写。

  • 再从doublewrite buffer写入实际表空间文件。

4.1 故障切换流程

  • 停主库(模拟故障)。

  • 停其他从库。

  • 将一个从库升级为主库:

    $ pg_ctl promote -D backupdata01/
  • 原主库和其他从库上执行pg_rewind

    $ pg_rewind -D data/ --source-server='host=127.0.0.1 port=5433 user=postgres'
  • 为原主库创建standby.signal文件,并启动原主库和其他从库。

4.2 pg_rewind原理

异步主从发生角色切换后,原主库的WAL目录中可能还有未同步到从库的内容,因此原主库无法直接切换为新主库的从库。使用pg_rewind可以修复原主库,不需要重建整个从库。

pg_rewind对比两个实例的差异点并找到差异点之前的最后一次Checkpoint,通过Checkpoint之后的WAL日志将备库推到和主库一致的状态,修复过程中会涉及到时间线修复。

4.3 时间线修复

先恢复到周三,运行一段时间后又需要恢复到周四。若没有时间线,数据库运行时会产生与旧WAL日志同名文件并覆盖旧日志,导致无法恢复到周四。

引入时间线,每次归档文件恢复完成后,创建一个新的时间线来区别新生成的WAL日志。时间线ID号是WAL文件名组成部分,不会覆盖旧时间线的日志。

文章来自个人专栏
PostgreSQL
5 文章 | 1 订阅
0条评论
0 / 1000
请输入你的评论
0
1