1. Featrue

pgBackRest是一款C语言编写的功能强大的postgres WAL/备份(Backup)管理工具。

当前pgBackRest项目的主要维护者是Crunchydata公司,Crunchydata在的postgres-operator工具pgo中深度绑定了pgbackrest工具。

pgbackrest的官方文档主要介绍了以下特性:

  • Parallel Backup & Restore
  • 多存储库(Repo)支持
  • 存储库(Repo)支持对接S3
  • 存储库(Repo)基于Local、TLS、SSH方式操作
  • 存储库(Repo)加密
  • 支持全量、差分、增量Backup
  • Backup/WAL自动Rotation/Expiration维护:支持在存储库上创建Backup的保留策略
  • Backup Resume:将创建Backup的操作可以”断点重建“
  • Delta Restore:基于Backup中每个文件的校验和进行增量恢复
  • Backup 完整性检查
  • Page Checksums:创建Backup时,检查内存Page和数据库文件一致性,并进行告警(PS:不会中断Backup)
  • Streaming Compression & Checksums:pgBackRest对存储库交互的数据流进行压缩和校验
  • Parallel, Asynchronous WAL Push & Get
  • Tablespace & Link Support

pgbackrest的功能多余同类型竞品WAL-E/G,并且笔者在学习中发现pgbackuprest官方提供的用户手册非常详细,远胜WAL-E/G

2.安装/编译

1.二进制安装

crunchydata提供了基于RPM等格式pgBackRest,可以从crunchydata的官网或者Postgres官方仓库获取相应操作系统的安装包。

1
2
3
yum install -y https://download.postgresql.org/pub/repos/yum/reporpms/EL-7-x86_64/pgdg-redhat-repo-latest.noarch.rpm
yum --showduplicates list pgbackrest
yum  install  pgbackrest

2.编译

1
2
3
4
5
6
yum -y install make gcc postgresql11-devel openssl-devel libxml2-devel lz4-devel libzstd-devel bzip2-devel libyaml-devel
yum -y install libpq5 libpq5-devel
mkdir -p ./build
wget -q -O - https://github.com/pgbackrest/pgbackrest/archive/release/2.37.tar.gz | tar zx -C ./build
cd ./build/pgbackrest-release-2.37/src && ./configure && make
cp pgbackrest /usr/local/bin/

上述编译过程结束后,在编译目录下会生成pgbackrest文件,只需要将上述文件copy到生产环境即可使用pgbackrest。 在生产环境上,还需要安装libpq5和libzstd作为pgbackrest的运行时依赖!

手工安装时可以创建pgbackrest的配置目录和日志目录:

1
2
3
4
5
6
7
sudo mkdir -p -m 770 /var/log/pgbackrest
sudo chown postgres:postgres /var/log/pgbackrest
sudo mkdir -p /etc/pgbackrest
sudo mkdir -p /etc/pgbackrest/conf.d
sudo touch /etc/pgbackrest/pgbackrest.conf
sudo chmod 640 /etc/pgbackrest/pgbackrest.conf
sudo chown postgres:postgres /etc/pgbackrest/pgbackrest.conf

3.特殊概念

在体验pgbackrest前先简单介绍以下概念。

1. Backup

Backup指的是数据库目录下所有文件的副本,通过Backup用户可以创建副本或者在新的环境中重建数据库。

pgBackRest的设计将Backup划分成以下三种类型:

  • Full:全量Backup
  • Differential:仅包含自上次Full Backup中发生更改的文件,Differential Backup依赖Full Backup才能restore数据库 。
  • Incremental:仅包含自上次Backup中发生更改的文件,上次Backup可以是任意类型的Backup

用户可以pgbackrest backup命令创建以上类型的backup,并在需要是通过pgbackrest restore从backup还原数据库。

2. Repositories

Repositories是用来保存backupwal的服务,pgbackrest在工作过程中可以通过SSH、HTTPS、Local的方式和Repositories交互。

当pgbackrest是基于SSH或者Local方式和Repositories交互时,Repositories本质上只是一个目录,没有实际运行进程。pgbackrest会直接读写本地目录中的文件或者通过免密SSH操作远程主机上的文件。

当pgbackrest通过HTTPS和Repositories交互时,远程主机上需要通过pgbackrest server命令启动Repositories服务。

用户可以同时定义多个Repositories,当需要执行backup/restore的时候通过–repo参数指定使用的Repositories。

以下配置中定义了repo1、repo2、repo3 三种不同类型的Repositories。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
[global]
# repo1 本地仓库
repo1-path=/var/lib/pgbackrest

# repo2 远程仓库,基于SSH访问,执行SSH的用户是postgres,用户需要手工在这两个机器之间打通免密
repo2-host=harbor-repo-host
repo2-host-user=postgres
repo2-path=/pgbackrest/repo

# repo3 远程仓库,基于HTTPS访问
repo3-host-ca-file=/etc/pgbackrest/cert/ca.crt
repo3-host-cert-file=/etc/pgbackrest/cert/client.crt
repo3-host-key-file=/etc/pgbackrest/cert/client.key
repo3-host-type=tls

3. Stanza

Stanza 是 pgbackrest 配置文件中的概念,它表示postgres集群中每个postgres实例的连接信息,可以简单理解为postgres的集群名称。pgbackrest管理backup和wal以Stanza为单位,数据合并存储。

以下配置中,db是Stanza名称,包含pg1、pg2、pg3 三个postgres实例:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
[db]
pg1-host=postgres1.svc.cluster.local.
pg1-path=/pgdata/pg13
pg1-port=5432
pg1-socket-path=/tmp/postgres

pg2-host=postgres2.svc.cluster.local.
pg2-path=/pgdata/pg13
pg2-port=5432
pg2-socket-path=/tmp/postgres

pg3-host=postgres3.svc.cluster.local.
pg3-path=/pgdata/pg13
pg3-port=5432
pg3-socket-path=/tmp/postgres

上述配置中每个postgres实例包含以下配置:

  • host:数据库地址
  • path:数据目录
  • port:数据库端口
  • socket-path:unix sock 目录(这个地址是相对于postgres运行的服务器的)

4. Quick Start

官方文档详细介绍了如何使用pgbackrest在虚拟机上使用pgbackup,这里不再复述。

以下是简化的脚本命令:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
# 初始化postgres数据库
sudo -u postgres /usr/pgsql-11/bin/initdb  -D /var/lib/pgsql/11/data -k -A peer
mv /var/lib/pgsql/11/data/postgresql.conf  /var/lib/pgsql/11/data/postgresql.base.conf

# 生成pgbackrest的配置目录
sudo mkdir -p -m 770 /var/log/pgbackrest
sudo chown postgres:postgres /var/log/pgbackrest
sudo mkdir -p /etc/pgbackrest
sudo mkdir -p /etc/pgbackrest/conf.d

# 创建一个本地目录作为备份仓库
sudo mkdir -p /var/lib/pgbackrest
sudo chmod 750 /var/lib/pgbackrest
sudo chown postgres:postgres /var/lib/pgbackrest

# 创建配置文件,配置文件中stanza名称为demo,并且省缺配置了一个本地的pg实例,数据目录为/var/lib/pgsql/11/data
# 同时配置了本地仓库repo1
cat >> /etc/pgbackrest/pgbackrest.conf << EOF
[demo]
pg1-path=/var/lib/pgsql/11/data

[global]
repo1-path=/var/lib/pgbackrest
repo1-retention-full=2
start-fast=y
repo1-cipher-pass=zWaf6XtpjIVZC5444yXB+cgFDFl7MxGlgkZSaoPvTGirhPygu4jOKOXf9LO4vjfO
repo1-cipher-type=aes-256-cbc

[global:archive-push]
compress-level=3

EOF
sudo chown postgres:postgres /etc/pgbackrest/pgbackrest.conf


# 创建postgresql.conf的配置文件,PS:这里的配置都不是必须的,只用于演示
cat >> /var/lib/pgsql/11/data/postgresql.conf << EOF
include 'postgresql.base.conf'

listen_addresses = '*'
log_line_prefix = ''
log_filename = 'postgresql.log'
archive_command = '/usr/bin/pgbackrest --stanza=demo archive-push %p'
archive_mode = on
max_wal_senders = 3
wal_level = replica
EOF
chown postgres:postgres /var/lib/pgsql/11/data/postgresql.conf

# 启动数据库
mkdir /home/postgres
chown postgres:postgres /home/postgres
cd /home/postgres
sudo -u postgres /usr/pgsql-11/bin/pg_ctl -D /var/lib/pgsql/11/data -l logfile start

# 初始化/运行stanza
sudo -u postgres /usr/bin/pgbackrest --stanza=demo --log-level-console=info stanza-create

# 检查指定stanza的配置
sudo -u postgres /usr/bin/pgbackrest --stanza=demo --log-level-console=info check

# 强制运行backup,由于设置了start-fast=y参数,此时会强制触发postgres的checkpoint操作,PS:如果没有该配置创建backup的动作会被延后,直到有一个checkpoint完成
sudo -u postgres /usr/bin/pgbackrest --stanza=demo --log-level-console=info backup

# 查看demo集群信息,以下命令会展示指定demo集群的所有备份信息,并且支持--output=json参数将结果格式化为json
sudo -u postgres /usr/bin/pgbackrest --stanza=demo info

# 恢复数据库
sudo -u postgres /usr/bin/pgbackrest --stanza=demo restore

5.Crunchydata架构

Crunchydata 公司开源的pgo中,使用pgbackrest和patroni搭建了一个Postgres HA方案,相比于Zalando开源的postgres-operator有以下不同:

  • pgo中完全关闭了postgres的Replication Slot功能,Standby启动时先从Repo中获取wal,replay完成后通过Replication Stream从Master同步。Zalando的方案主要基于Replication Slot。pgo将wal数据的存储和Postgres分离,但是同时引入了repo目录的高可用问题。
  • Standby启动时,pgo通过Repo的backup创建/restore数据目录。由于pgbackrest支持差分restore,因此对于长时间下线的Standby可能可以更快将数据目录的恢复到backup的状态(PS:这里更快的前提是用户定时生成backup,否则pgo依然会回退到pg_basebackup的方式全量同步数据)。Zalando默认使用pg_basebackup,用户也可以配置使用WAL-G。

PS:pgbackrest通过计算文件的SHA-1实现差分restore

pgo默认配置下,部署一个2副本的postgres集群会生成3个Pod,如下图:

  • postgres instance:PG Master/Standby,运行patroni和postgres

  • pgbackrest server(Repo):pgbackrest仓库通过SSH和postgres pod交互,用来保存WAL和backup

image-20220106162304396

pgo默认情况下Patroni的配置文件:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
bootstrap:
  dcs:
    postgresql:
	  use_pg_rewind: true
	  # 关闭Replication Slot
      use_slots: false
      parameters:
        # Master 调用 pgbackrest archive-push 备份 wal
        archive_command: pgbackrest --stanza=db archive-push "%p"
        archive_mode: 'on'
        jit: 'off'
        # Standby 调用 pgbackrest archive-get 获取 wal
        restore_command: pgbackrest --stanza=db archive-get %f "%p"
        wal_level: logical
postgresql:
  # 定义以下两种方式创建replicas,优先级pgbackrest
  create_replica_methods:
  - pgbackrest
  - basebackup
  pgbackrest:
    # 调用pgbackrest restore
    command: 'bash -ceu -- install --directory --mode=0700 "${PGDATA?}" && exec "$@" - pgbackrest restore --delta --stanza=db --repo=1 --link-map=pg_wal=/pgdata/pg13_wal'
    # 执行command时,patroni不会清楚pg的数据目录
    keep_data: true
    # no_master参数表示即使当前patroni集群不存在leader也依然创建replica
    no_master: true
    # 调用command时,patroni不会额外注入参数
    no_params: true
  basebackup:
  - waldir=/pgdata/pg13_wal

上述配置中,create_replica_methods 中定义了pgbackrest用于差分创建副本。关于patroni的配置说明参考博客

参考