A key feature of the v2.33 pgBackrest release is support for multiple repositories. This lets you define different behavior for different backup repositories. As an example, you could have a local repository for fast restore that had short retention period (to save space) paired with a remote repository which is larger for cold storage.
This feature introduces a new --repo option which can be used to set the repository the command should apply to. All repo*- options are indexed to enable configuring multiple repositories.
In this section, we will set up a demo cluster (using EDB Postgres Advanced Server version 13 on CentOS 7) to demonstrate how this new feature impacts each pgBackRest command.
Configuration
It must be noted that in this demo, we will set up two local repositories on our database host. For production purposes, it is recommended to store each repository on separate storage, and configure at least one remote repository.
For safety reasons, the --repo option can't be defined in the configuration file or a warning will be triggered: WARN: configuration file contains command-line only option 'repo'. If there is more than one repository configured and the --repo option is not specified for a command, the repository with the highest priority order (e.g. repo1 then repo2) will be chosen by default.
The --repo option is not required when only repo1 is configured to maintain backward compatibility. However, when a single repository is configured, it is recommended to use repo1 in the configuration.
Initialization
Stanza Create Command
The stanza-create command will automatically operate on all configured repositories:
Check Command
The check command will trigger a new WAL segment to be archived and try to push it to all defined repositories:
Archive Push Command
The archive-push command will always archive WALs in all configured repositories. Backups will need to be scheduled individually for each repository. In most cases, this is desirable since backup types and retention could vary per repository.
The archive_command can still be defined as usual:
Here is a DEBUG extract of the PostgreSQL logs showing the archive-push activity:
The archive-push command will try to push the WAL archive to all reachable repositories. The idea is to archive to as many repositories as possible even if we still need to throw an error to PostgreSQL to prevent it from removing the WAL file.
The PostgreSQL archiver process should then report an error:
The next WAL segments should not then be archived:
This becomes very handy by adding archive-async=y to the configuration in order to use asynchronous archiving processes within pgBackRest itself. Even if PostgreSQL archiver process is still stuck, the archives will reach the working repositories:
Let us unblock the archiver process (and remove asynchronous archiving) before going further:
Backups
Backup Command
Let us take a few backups:
Here, we alternated full and incr backups in each repository.
Info Command
The default order will sort backups by dates mixing the repositories. It might be confusing to find the backups depending on each other.
We can then split this view per repository:
The 'wal archive min/max' shows the minimum and maximum WAL currently stored in the archive and, in the case of multiple repositories, will be reported across all repositories unless the --repo option is set. There may be gaps due to archive retention policies or other reasons.
Let us break the first repository by removing its content:
If multiple repositories are configured, then a status of mixed indicates that the stanza is not in a healthy state for one or more of the repositories. In this case, the state of the stanza will be detailed in additional lines per repository.
This state can be resolved by taking a new backup:
Restore
Let us initiate a situation with some data, backups and restore point:
As you can see in the example above, the backup command automatically triggered the expire command on the repository when we created a backup. Since this command is operating on one repository only, it would not expire anything in the other repositories until the backup or expire command is run for that repository.
Since the default retention policy is based on a number of backups, it is expected that only new backups are affecting the backups and archives to expire.
Restore Command
The restore command automatically defaults to selecting the latest backup from the first repository where backups exist. The order in which the repositories are checked is dictated by order of the repositories as configured in the pgbackrest.conf (e.g. repo1 will be checked before repo2). To restore from from a specific repository, the --repo option can be used.
PITR can be performed by specifying --type=time and specifying the target time with --target. If a backup is not specified via the --set option, then the configured repositories will be checked for a backup that contains the requested time. If no backup can be found, the latest backup from the first repository containing backups will be used.
Even if the backup in repo2 is newer, the first found match is preserved. Let's take a new backup in repo1 to check if pgBackRest will auto-select the backup in repo2:
The recovery process may be complex and tricky depending on the target, and therefore, the info command can really be helpful to determine the repository to restore from.
Archive Get Command
When multiple repositories are configured, WAL will be fetched from the repositories in priority order (e.g. repo1, repo2, etc.). In general it is better if faster storage has higher priority. The command can operate on a single repository by specifying it with the --repo option.
PostgreSQL found the WALs needed for recovery in our repo2, picked a new timeline and pushed the history file to the repositories.
Whenever a new timeline is created, PostgreSQL creates a timeline history file that shows which timeline it branched off from and when. These history files are necessary to allow the system to pick the right WAL segment files when recovering from a backup that contains multiple timelines.
As shown above, since the history file is stored within the same repository as the restored backup set, PostgreSQL is able to pick a new and accurate timeline.
Let us now retry after moving the history file to repo1.
As we can see, both 00000002.history and 00000003.history have been found in repo1 so PostgreSQL could pick the next timeline correctly, even if the restored backup set came from repo2.
When using multiple repositories, the archive-get command will tolerate gaps in one repository (due to lack of disk space e.g.) mainly because it will still be able to find the missing files in the other repository.