首页 > 数据库 > 数据库开发技术 > pgBackRest你必须知道的坑
PostgreSQL的备份工具很多,目前比较流行的是pg_probackup,pgBackRest等,awesome中也提到了很多优秀的备份工具
• Barman - Backup and Recovery Manager for PostgreSQL by 2ndQuadrant.
• OmniPITR - Advanced WAL File Management Tools for PostgreSQL.
• pg_probackup – A fork of pg_arman, improved by @PostgresPro, supports incremental backups, backups from replica, multithreaded backup and restore, and anonymous backup without archive command.
• pgBackRest - Reliable PostgreSQL Backup & Restore.
• pg_back - pg_back is a simple backup script
• pghoard - Backup and restore tool for cloud object stores (AWS S3, Azure, Google Cloud, OpenStack Swift).
• wal-e - Simple Continuous Archiving for PostgreSQL to S3, Azure, or Swift by Heroku.
• wal-g - The successor of WAL-E rewritten in Go. Currently supports cloud object storage services by AWS (S3), Google Cloud (GCS), Azure, as well as OpenStack Swift, MinIO, and file system storages. Supports block-level incremental backups, offloading backup tasks to a standby server, provides parallelization and throttling options. In addition to Postgres, WAL-G can be used for MySQL and MongoDB databases.
• pitrery - pitrery is a set of Bash scripts to manage Point In Time Recovery (PITR) backups for PostgreSQL.
今天我们要聊的是pgBackRest。
pgBackRest是个不错的备份软件,支持的特性许多,尤其是瞩目的S3兼容
• 支持并行备份和恢复
• 支持本地或远程操作,需配置TLS/SSH 在本地或远程备份、恢复和存档
• 支持完整、增量和差异备份,增量恢复
• 支持断点备份
• S3、Azure和GCS兼容的对象存储支持
特性就不一一列举了,感兴趣的可以参照官网 https://pgBackRest.org/。
这里我们关注实际场景中可能遇到的问题:在实际生产中,往往PostgreSQL都是主从的架构,并且由于备份的过程中会消耗主库的IO、CPU等资源,所以我们一般会选择在备库上进行备份。但是,这里有个坑:pgBackRest的remote backup是依赖ssh的!
比如我这个示例,主从是位于同一台主机的,pgdata是主库的数据目录,standby_data是备库的数据目录。假如要模拟实际生产环境的一主一从的话,需要使用NAS,让主备都能访问到仓库。
可以看到,在备库备份会备份常规的数据文件,比如base目录下的数据文件,而不会通过流复制复制的文件比如日志文件、控制文件、配置文件等,则需要从主库上备份,而这实现的原理则是通过ssh连接到主库进行备份
在官网上也有这一块的说明,通过在主库上执行pg_start_backup和pg_stop_backup,在备库上拷贝通过流复制复制过来的文件,而一些日志文件和统计信息等,从主库拷贝。
pgBackRest can perform backups on a standby instead of the primary.
Both the primary and standby databases are required to perform the backup, though the vast majority of the files will be copied from the standby to reduce load on the primary.
This incremental backup shows that most of the files are copied from the pg-standby host and only a few are copied from the pg-primary host.
pgBackRest creates a standby backup that is identical to a backup performed on the primary. It does this by starting/stopping the backup on the pg-primary host, copying only files that are replicated from the pg-standby host, then copying the remaining few files from the pg-primary host. This means that logs and statistics from the primary database will be included in the backup.
因此,可能的问题也就不难猜到了,比如我们生产环境,都是通过堡垒机来进行访问的(相信绝大多数人也是如此),各个主机之前是无权进行ssh的。我本地将.ssh/authorized_keys移除之后,便会报错
那么假如无法配置ssh,又想同城备份怎么办?不好意思,无解。
https://github.com/pgBackRest/pgBackRest/issues/1219
Is there a way to avoid passwordless ssh between standby and primary for backups from standby ?
是否有方法避免主备之间免密进行ssh备份?
这里提到了类似的问题,备份到S3,但是由于安全原因,也无法使用免密ssh。
目前,pgBackRest只能通过SSH操作。它不需要一个没有密码的SSH用户,但建议使用SSH密钥(没有口令)。也许ssh-agent可以帮助解决口令问题,但你必须在系统中找到解决方案。
遗憾的是,我个人认为目前没有任何其他解决方案。
比如这个例子 https://www.enterprisedb.com/docs/supported-open-source/pgBackRest/07-use_case_2/
https://docs.percona.com/postgresql/11/solutions/dr-pgBackRest-setup.html
https://www.cybertec-postgresql.com/en/remote-backup-and-restore-with-pgBackRest/
https://pgday.ru/presentation/297/60f04de178eaa.pdf
https://www.postgresql.org/message-id/e0746162-fa29-19af-c735-1ac23007f87b%40pgmasters.net
https://blog.dbi-services.com/pgBackRest-dedicated-backup-host/
https://dbsguru.com/configure-pgBackRest-backup-host-remote-postgresql/
https://blog.crunchydata.com/blog/pgBackRest-performing-backups-on-a-standby-cluster
都要求ssh免密。
那么不妨思考一下,为什么pgBackRest会这样设计?即通过ssh连到主库上去拷贝一些额外的文件,其中日志和配置文件这个不难理解,主从的配置文件可能不一致,那么/home/postgres/pgdata/pg_logical/replorigin_checkpoint是什么东西?
/*
* Recover replication replay status from checkpoint data saved earlier by
* CheckPointReplicationOrigin.
*
* This only needs to be called at startup and *not* during every checkpoint
* read during recovery (e.g. in HS or PITR from a base backup) afterwards. All
* state thereafter can be recovered by looking at commit records.
*/
void
StartupReplicationOrigin(void)
{
const char *path = "pg_logical/replorigin_checkpoint";
int fd;
int readBytes;
uint32 magic = REPLICATION_STATE_MAGIC;
int last_state = 0;
pg_crc32c file_crc;
pg_crc32c crc;
/* ---------------------------------------------------------------------------
* Perform a checkpoint of each replication origin's progress with respect to
* the replayed remote_lsn. Make sure that all transactions we refer to in the
* checkpoint (local_lsn) are actually on-disk. This might not yet be the case
* if the transactions were originally committed asynchronously.
*
* We store checkpoints in the following format:
* +-------+------------------------+------------------+-----+--------+
* | MAGIC | ReplicationStateOnDisk | struct Replic... | ... | CRC32C | EOF
* +-------+------------------------+------------------+-----+--------+
*
* So its just the magic, followed by the statically sized
* ReplicationStateOnDisk structs. Note that the maximum number of
* ReplicationState is determined by max_replication_slots.
* ---------------------------------------------------------------------------
*/
void
CheckPointReplicationOrigin(void)
{
const char *tmppath = "pg_logical/replorigin_checkpoint.tmp";
const char *path = "pg_logical/replorigin_checkpoint";
int tmpfd;
int i;
uint32 magic = REPLICATION_STATE_MAGIC;
pg_crc32c crc;
代码有点晦涩,我们可以参照pg_replication_origin_status和pg_replication_origin这两个视图,这个文件是关于复制源的,因为逻辑复制和物理复制有一个很大的区别,逻辑复制可以有多个来源,可以实现双向或者多向复制,因此发布端在订阅端有一个唯一的ID,用于标识数据来源,防止死循环,逻辑复制源用于安全的跟踪复制进度,在创建订阅的时候,会通过replorigin_create()自动创建一个复制源。
比如如下的订阅端,存在remote_lsn和local_lsn两个字段
/*
* Replay progress of a single remote node.
*/
typedef struct ReplicationState
{
/*
* Local identifier for the remote node.
*/
RepOriginId roident;
/*
* Location of the latest commit from the remote side.
*/
XLogRecPtr remote_lsn;
/*
* Remember the local lsn of the commit record so we can XLogFlush() to it
* during a checkpoint so we know the commit record actually is safe on
* disk.
*/
XLogRecPtr local_lsn;
/*
* PID of backend that's acquired slot, or 0 if none.
*/
int acquired_by;
/*
* Lock protecting remote_lsn and local_lsn.
*/
LWLock lock;
} ReplicationState;
• remote_lsn指已复制到订阅者的发布者的LSN。
• local_lsn指本地已持久化REDO的LSN,只有在这个LSN之前的DIRTY PAGE才能flush到磁盘。
postgres=# select * from pg_replication_origin;
roident | roname
---------+----------
1 | pg_24582
(1 row)
postgres=# select oid from pg_subscription;
oid
-------
24582
(1 row)
postgres=# select * from pg_replication_origin_status;
local_id | external_id | remote_lsn | local_lsn
----------+-------------+------------+------------
1 | pg_24582 | 0/0 | 0/DD587A90
(1 row)
当发布端修改了表之后,会更新复制源pg_replication_origin_status中的remote_lsn和local_lsn,该位点对应于每个订阅表最后一次事务提交的位置。当然,PG也提供了一系列函数让我们自己去使用。
pg_replication_origin_create
pg_replication_origin_drop
pg_replication_origin_progress
...
原来是复制源相关的,pgBackRest也将这个考虑了进去,因为主库可能也是一个订阅端。
瑕不掩瑜,pgBackRest确实很先进,包括我个人很喜欢的S3兼容,但必须依赖SSH,相信很多场景会受限,各位要注意这个坑。
这里打个小广告,4月9号,成都meetup欢迎各位的到来 ~ 我会作为门童
原文作者:PostgreSQL学徒;如有侵权,请联系管理员删除。