Утилита резервирования pgBackRest перестала поддерживаться, стало актуальным найти ей замену. Главными альтернативами называют WAL-G и Barman. Можно использовать pg_basebackup+pg_receivewal. Преимущество WAL-G в том, что резервирование возможно по протоколу S3, WAL-G обеспечивает более высокую скорость резервирования и сжатия, имеет неплохие перспективы развития. Кроме протокола S3, WAL-G может резервировать и восстанавливать из директории в файловой системе, работает с Patroni. Директория не обязательно находится на локальном диске, можно смонтировать любую файловую систему, например, NFS. Утилита свободно распространяемая.

В статье рассматриваются примеры команд, которыми можно резервировать и восстанавливать PostgreSQL утилитой WAL-G с защитой от потери транзакций (zero data loss).

WAL-G можно собрать из исходников или из установить из пакета. Инсталляционный пакет содержит единственный файл wal-g, который будет распакован в директорию. Чтобы не писать каждый раз путь к утилите, можно создать символическую ссылку в директории, которая есть в переменной окружения $PATH:

root@host:~$ dpkg -i wal-g-*.deb
root@host:~$ ln -s /opt/tantor/usr/bin/wal-g /usr/local/bin/wal-g

Настройки утилиты хранятся в одном файле. По умолчанию, местоположение файла параметров $HOME/.walg.json Можно иметь несколько файлов с разными настройками и указывать нужный файл параметром wal-g --config.

Для бэкапа в директорию файловой системы достаточно создать файл:

root@host:~$ su - postgres
postgres@host:~$ cat > $HOME/.walg.json << EOF
{
    "WALG_FILE_PREFIX": "/var/lib/postgresql/backup",
    "WALG_COMPRESSION_METHOD": "brotli",
    "WALG_DELTA_MAX_STEPS": "5",
    "PGHOST": "/var/run/postgresql",
    "PGDATA": "/var/lib/postgresql/tantor-se-server-18/data"
}
EOF

Резервирование будет выполняться в директорию, на которую указывает WALG_FILE_PREFIX.

Скрытый текст

Пример файла конфигурации для протокола S3:

postgres@host:~$ cat > .walg.json << EOF
{
   "AWS_ENDPOINT": "http://127.0.0.1:9000",
   "WALG_S3_PREFIX": "s3://bucket1",
   "AWS_ACCESS_KEY_ID": "rustfsadmin",
   "AWS_SECRET_ACCESS_KEY": "rustfsadmin",
   "AWS_S3_FORCE_PATH_STYLE": "true",
   "WALG_COMPRESSION_METHOD": "brotli",
   "WALG_DELTA_MAX_STEPS": "5",
   "PGDATA": "/var/lib/postgresql/tantor-se-18/data",
   "PGHOST": "/var/run/postgresql"
}
EOF

Пример установки S3-сервера, чтобы попробовать работу WAL-G по протоколу S3:

root@host:~$ curl -O https://rustfs.com/install_rustfs.sh && bash install_rustfs.sh
Service port: 9000,  Console port: 9001,  Data directory: /data/rustfs0
root@host:~$ mkdir /data/rustfs0/bucket1

У S3-сервера есть веб-консоль управления http://localhost:9001 (rustfsadmin/rustfsadmin)

Приведённые в статье примеры можно попробовать на виртуальной машине Tantor DBA1-18.ova

Алгоритм brotli обеспечивает лучшее и быстрое сжатие (лучше чем LZ4, быстрее чем LZMA). Благодаря нему и многопоточности, WAL-G чрезвычайно быстро резервирует.

Для работы не с директорией, а по протоколу S3 достаточно поменять параметры в файле $HOME/.walg.json, команды резервирования и восстановления остаются теми же самыми. Или создать ещё один файл и добавить параметр --config к параметрам утилиты WAL-G.

Для проверки того, что wal-g может работать с настройками в файле, можно дать команду:

postgres@host:~$ wal-g backup-list
INFO: 2026/04/28 10:33:54.281318 List backups from storages: [default]
INFO: 2026/04/28 10:33:54.281702 No backups found

Команда не выдала ошибки, значит, файл параметров корректный. Бэкапов нет, так как мы их ещё не делали.

Конфигурирование PostgreSQL для архивирования WAL

Чтобы с бэкапа можно было полностью восстановиться, нужно сохранять все WAL-файлы с начала бэкапа до самого последнего. WAL файлы можно вытягивать по протоколу репликации или передавать командой, указанной в параметре конфигурации archive_command (текущий WAL-файл команда не может передать). Для передачи WAL-файлов утилитой WAL-G в архив достаточно установить параметры:

postgres=# 
alter system set archive_command = 'wal-g wal-push "%p" >> $PGDATA/log/archive_command.log 2>&1';
alter system set restore_command = 'wal-g wal-fetch "%f" "%p" >> $PGDATA/log/restore_command.log 2>&1';
alter system set archive_mode=on;

Параметр archive_command задаёт команду, которая будет выполняться после переключения на следующий WAL-файл («сегмент»). %p - переменная, которая инициализируется названием и путём к WAL-файлу, в который завершена запись и который должен быть передан в архив.

Параметр restore_command указывает, какая команда будет выполнена процессом startup, который восстанавливает кластер после запуска экземпляра и определяет по файлу backup_label или pg_control, какой WAL-сегмент нужен для продолжения восстановления (будет накатываться следующим). Эта команда должна создать WAL-файл в директории $PGDATA/pg_wal.

Параметр archive_mode включает действие параметра archive_command.

WAL-G и pg_receivewal

WAL-G можно совместить с pg_receivewal, получив преимущества высокоскоростного создания сжатых бэкапов, которые делает WAL-G и отсутствие потерь транзакций (zero data loss), которое обеспечивает pg_receivewal. При использовании pg_receivewal нужно задать в параметре restore_command команду копирования из директории, куда утилита pg_receivewal вытягивала журналы. Пример команды запуска pg_receivewal:

postgres@host:~$ rm -rf $HOME/archivelog
mkdir $HOME/archivelog
psql -c "alter system set max_slot_wal_keep_size = '1TB';"
psql -c "select pg_reload_conf();"
pg_receivewal --drop-slot --slot=arch
pg_receivewal --create-slot --slot=arch
pg_receivewal -D $HOME/archivelog --slot=arch --synchronous

Утилиту pg_receivewal можно запускать как службу через systemd (так же как и экземпляр PostgreSQL). Если нужна гарантия отсутствия потерь транзакций, то нужно задать параметр конфигурации synchronous_standby_names=pg_receivewal, тогда транзакции будут подтверждаться только после того, как pg_receivewal получит запись о фиксации транзакции (и все предыдущие журнальные записи) и сохранит её в файле .partial. Однако, команды фиксации транзакций могут выполняться с большей задержкой.

Малоизвестно, но это важно: чтобы файл *.partial применялся при запуске экземпляра, нужно использовать следующее значение для параметра конфигурации restore_command:

alter system set restore_command = 'wal-g wal-fetch "%f" "%p"  >> $PGDATA/log/restore_command.log 2>&1 || cp $HOME/archivelog/%f %p || cp $HOME/archivelog/%f.partial %p';

Файлы с расширением  .partial не применяются при восстановлении. Без применения этого файла последние транзакции будут потеряны. Чтобы файл .partial применился, важно убрать расширение у файла, что учтено в вышеприведённой команде. Первая часть команды восстанавливает журнал, заархивированный WAL-G. Если в архиве его нет, то журнал копируется из архива pg_receivewal. Если такого файла нет, то копируется файл .partial (в котором и находятся самые последние изменения) и убирается расширение у файла.

Стоит протестировать, применяется ли (накатывается) в ваших скриптах и утилитах восстановления файл .partial. В документации к Barman о файле .partial, хоть и излишне сложно, но написано. Более просто про файл .partial написал Лоренц Альбе. В Barman предлагается вручную копировать и переименовывать файл, но это плохо тем, что при сбоях лучше минимизировать ручное вмешательство, так как от волнения вероятность ошибиться возрастает. При использовании WAL-G копирование и переименование файла .partial заранее автоматизируется в restore_command.

Скрытый текст

На языке Go написан аналог pg_receivewal, который называется pgrwl. Он работает с S3 и файловой системой, но с файлом .partial работает точно так же, как pg_receivewal. Так как pg_receivewal входит в стандартную поставку и поддерживается сообществом, то имеет смысл использовать pg_receivewal.

Push или Pull

Альтернатива архивированию с помощью параметров archive_* ("push") - запустить wal-g как службу, чтобы она получала ("pull") файлы журналов:

postgres@host:~$ wal-g wal-receive
INFO: 2026/04/28 21:44:41.565679 FILE PATH: 00000002.history.

При использовании этого способа архивирования WAL, нужно установить только параметр restore_command, параметр archive_mode нужно вернуть к значению по умолчанию (off). Поскольку, даже в этом режиме, WAL-G принимает только сформированные WAL-файлы, то с WAL-G проще использовать archive_command, а не режим “pull”. Единственно, надо проследить за тем, чтобы с резервируемого хоста нельзя было стирать или менять файлы в директории, куда резервируются файлы, иначе злоумышленник, завладевший резервируемым хостом, сможет стереть или испортить бэкапы.

WAL-G может не только вытягивать журналы, но и резервировать кластер PostgreSQL (PGDATA) в режиме “pull”, используя репликационный протокол. Эта возможность уже готова и будет включена в следующую версию WAL-G. При использовании репликационного протокола пока нет многопоточной передачи и дельта-бэкапов и бэкап кластера будет создаваться дольше. Это касается только создания бэкапов в режие «pull», вытягивание WAL не имеет таких ограничений. Также, ни в режиме «push», ни в режиме «pull» WAL-G не принимает текущий файл WAL и при полной потере директории PGDATA/pg_wal нельзя будет восстановить транзакции из текущего файла WAL. Это не является проблемой, так как WAL-G может архивировать и восстанавливать журналы совместно с утилитой pg_receivewal.

Отсутствие потерь (zero data loss, RPO=0) способны обеспечить: утилита pg_receivewal, процесс walreceiver (на физических репликах), Polar DataMax (в Tantor XData).

Создание бэкапа утилитой WAL-G

Чтобы изменения подействовали, нужно остановить и запустить (перезапустить недостаточно) экземпляр.

Переключимся на новый WAL-сегмент, так как archive_command выполняется только после завершения записи в WAL-файл процессами экземпляра и переключения на следующий:

postgres@host:~$ psql -c "select pg_switch_wal();"
 pg_switch_wal 
---------------
 0/30002BC
(1 row)
postgres@host:~$ cat $PGDATA/log/archive_command.log 
INFO: 2026/04/28 11:31:34.145668 Files will be uploaded to storage: default
INFO: 2026/04/28 11:31:34.192862 FILE PATH: 000000010000000000000003.br

Появился файл archive_command.log, путь к которому был указан в параметре archive_command.

Зарезервируем директорию кластера. Первый бэкап всегда полный, от него отсчитываются «дельты» (дифференциальные инкрементальные бэкапы). В команде создания бэкапа нужно передать название директории кластера:

postgres@host:~$ wal-g backup-push $PGDATA
INFO: 2026/04/28 11:40:37.903727 Backup will be pushed to storage: default
INFO: 2026/04/28 11:40:37.912409 Couldn't find previous backup. Doing full backup.
...
INFO: 2026/04/28 11:40:38.357616 Wrote backup with name base_000000010000000000000005 to storage default

Проверка, что созданный бэкап есть в списке:

postgres@host:~$ wal-g backup-list
INFO: 2026/04/28 11:47:02.111831 List backups from storages: [default]
backup_name                   modified                  wal_file_name            storage_name
base_000000010000000000000005 2026-04-28T11:40:38+03:00 000000010000000000000005 default

В директории для бэкапов /var/lib/postgresql/backup появятся файлы, которые и являются бэкапом кластера баз данных:

postgres@host:~$ ls -al $HOME/backup/basebackups_005/*/tar_partitions
total 2760
-rw-r--r-- 1 postgres postgres     269 Apr 28 11:40 backup_label.tar.br
-rw-r--r-- 1 postgres postgres 2806055 Apr 28 11:40 part_001.tar.br
-rw-r--r-- 1 postgres postgres     300 Apr 28 11:40 pg_control.tar.br

Следующие пять (WALG_DELTA_MAX_STEPS) бэкапов будут сделаны в режиме DELTA:

postgres@host:~$ wal-g backup-push $PGDATA
INFO: 2026/04/28 11:59:41.614186 Backup will be pushed to storage: default
INFO: 2026/04/28 11:59:41.628244 LATEST backup is: 'base_000000010000000000000005'
INFO: 2026/04/28 11:59:41.629001 Delta backup from base_000000010000000000000005 with LSN 0/5000028.
...
INFO: 2026/04/28 11:59:41.833147 Wrote backup with name base_000000010000000000000007_D_000000010000000000000005 to storage default

Полезна команда удаления мусора в архиве - неудачные бэкапы, ненужные журнальные файлы:

postgres@host:~$ wal-g delete garbage --confirm
INFO: 2026/04/28 20:49:20.660407 Backup to delete will be searched in storages: [default]
INFO: 2026/04/28 20:49:20.660540 retrieving permanent objects
INFO: 2026/04/28 20:49:20.661749 Running in default mode. Will remove outdated WAL files and leftover backup files.
INFO: 2026/04/28 20:49:20.662257 Start delete
INFO: 2026/04/28 20:49:20.663400 Objects in folder:
INFO: 2026/04/28 20:49:20.663440        will be deleted: wal_005/00000002000000000000002A.br, from storage: default

Если WAL-файлы вытягиваются утилитой pg_receivewal, то после создания бэкапа изменится файл $PGDATA/pg_wal/*.backup. После архивирования командой в параметре archive_command создаются файлы $PGDATA/pg_wal/archive_status/*000000??.done. Имена этих файлов можно использовать для удаления WAL-файлов, которые вытягивает pg_receivewal. Пример команды удаления файлов, созданных pg_receivewal, если они уже заархивированы:

pg_archivecleanup $HOME/archivelog $(basename $(ls $PGDATA/pg_wal/archive_status/*000000??.done  | sort -r | head -n 1) .done)
Скрытый текст

Для примера, команда для удаления файлов, которые не нужны последнему бэкапу:

pg_archivecleanup $HOME/archivelog $(basename $(ls $PGDATA/pg_wal/*.backup))

Команду pg_archivecleanup можно запускать по расписанию с желаемой частотой, которую выбрать исходя из объема генерируемых WAL и свободного места в директории (в примере $HOME/archivelog).

Восстановление из бэкапа, созданного WAL-G

Остановим экземпляр и удалим директорию PGDATA:

postgres@host:~$ pg_ctl stop
waiting for server to shut down.... done
server stopped
postgres@host:~$ rm -rf $PGDATA/*

Команда симулирует полную потерю кластера баз данных («disaster»). Команда удаляет, в том числе и текущий WAL-сегмент, который не был записан в архив утилитой WAL-G, но если работала утилита pg_receivewal, то она сохранила записи текущего сегмента в файле .partial. Директория, в которую будет выполняться восстановление из бэкапа должна быть пустой.

Команда восстановления директории кластера из бэкапа:

postgres@host:~$ wal-g backup-fetch $PGDATA LATEST
INFO: 2026/04/28 12:56:37.402035 Selecting the latest backup...
INFO: 2026/04/28 12:56:37.402219 Backup to fetch will be searched in storages: [default]
INFO: 2026/04/28 12:56:37.402360 LATEST backup is: 'base_000000010000000000000007_D_000000010000000000000005'
INFO: 2026/04/28 12:56:37.406190 Delta from base_000000010000000000000005 at LSN 0/5000028 
...
INFO: 2026/04/28 12:56:38.500783 base_000000010000000000000005 fetched. Upgrading from LSN 0/5000028 to LSN 0/7000028 
...
Backup extraction complete.

Директория PGDATA восстановлена. Проверим содержимое директории журналов:

postgres@host:~$ ls $PGDATA/pg_wal

Директория пуста, как и директория с диагностическими файлами PGDATA/log, что нормально, файлы WAL восстанавливаются отдельно командой, указанной в параметре конфигурации restore_command.

Вместо управляющего файла будет использоваться файл backup_label:

postgres@host:~$ cat $PGDATA/backup_label 
START WAL LOCATION: 0/7000028 (file 000000010000000000000007)
CHECKPOINT LOCATION: 0/7000098
BACKUP METHOD: streamed
BACKUP FROM: primary
START TIME: 2026-04-28 11:59:41 MSK
LABEL: 2026-04-28 11:59:41.640728 +0300 MSK m=+0.075156967
START TIMELINE: 1

Нужно создать файл recovery.signal, который укажет, что выполняется восстановление из бэкапа и запустить экземпляр:

postgres@host:~$ touch $PGDATA/recovery.signal
postgres@host:~$ pg_ctl start
 done
server started

Процесс startup будет выполнять команду, указанную в параметре конфигурации restore_command и применять WAL-файлы, которые эта команда скопирует в директорию PGDATA/pg_wal. Экземпляр будет переведён в состяние, в соответствии со значениями параметров (recovery_target_*), которыми можно указать, до какого момента выполнять восстановление и что делать после достижения этого момента.

Первая часть restore_command (wal-g wal-fetch “%f” “%p”) вынет из архива WAL-G и накатит журналы вплоть до текущего WAL-сегмента. Если запускался pg_receivewal, то последняя часть restore_command скопирует и накатит файлы, которые не смог скопировать WAL-G (например, из-за временной недоступности S3 хранилища) и файл .partial, который содержит журнальные записи из текущего WAL-сегмента. Журнальные файлы, которые не попали в архивы wal-g и pg_receivewal, не применятся, и транзакции, которые могли бы в них быть, потеряются. Вероятность того, что две утилиты не смогут или не успеют заархивировать WAL файлы мала. Для полной защиты от такой ситуации используется параметр synchronous_standby_names.

После восстановления слоты репликации удалены и, если они используются, то их надо снова создать. Если использовалась утилита pg_receivewal (которую мы не останавливали и она продолжит вытягивать WAL уже с восстановленного кластера), то после восстановления для неё нужно снова создать слот репликации:

postgres@host:~$ pg_receivewal --create-slot --slot=arch

Сравнение WAL-G с Barman есть в комментариях к статье и самой статье.

Заключение

После прекращения развития утилиты pgBackRest, стал актуальным выбор перспективных утилит резервирования. Там, где нужна простота, высокая скорость резервирования и сжатия, WAL‑G неплохой выбор. WAL‑G имеет большое число разработчиков из разных стран и активно развивается. В статье даны примеры, как установить и сконфигурировать WAL-G и команды, которыми можно зарезервировать и восстановить PostgreSQL с гарантией отсутствия потерь транзакций (zero data loss).

Комментарии (2)


  1. bigtrot
    30.04.2026 05:41

    В программном средстве barman есть возможность настройки различных политик связанных с ротацией архивов, а также автоматизации самого процесса регулярного архивирования.
    Вопрос есть ли такие же возможности в WAL-G. Или это надо еще оборачивать в свой скрипт?


    1. OlegIct Автор
      30.04.2026 05:41

      различных политик связанных с ротацией архивов

      Политики удаления (бэкапов и ненужных оставшимся бэкапам архивов журналов) есть: retain (аналог redundancy), before (аналог recovery window), everything, target. Пример удаления всех бэкапов, кроме двух последних. Команда wal-g delete retain 2 --confirm

      postgres@host:~$ wal-g backup-list
      INFO: 2026/04/30 13:43:36.327222 List backups from storages: [default]
      backup_name                   modified                  wal_file_name            storage_name
      base_00000003000000000000004E 2026-04-30T13:42:17+03:00 00000003000000000000004E default
      base_00000003000000000000004F 2026-04-30T13:42:19+03:00 00000003000000000000004F default
      base_000000030000000000000051 2026-04-30T13:43:32+03:00 000000030000000000000051 default
      base_000000030000000000000052 2026-04-30T13:43:34+03:00 000000030000000000000052 default
      
      postgres@host:~$ wal-g delete retain 2 --confirm
      INFO: 2026/04/30 13:43:51.504303 Backup to delete will be searched in storages: [default]
      INFO: 2026/04/30 13:43:51.504656 retrieving permanent objects
      INFO: 2026/04/30 13:43:51.507417 Start delete
      ...
      postgres@host:~$ wal-g backup-list
      INFO: 2026/04/30 13:43:55.072866 List backups from storages: [default]
      backup_name                   modified                  wal_file_name            storage_name
      base_000000030000000000000051 2026-04-30T13:43:32+03:00 000000030000000000000051 default
      base_000000030000000000000052 2026-04-30T13:43:34+03:00 000000030000000000000052 default

      автоматизации самого процесса регулярного архивирования

      планировщик есть в Платформе Тантор, можно использовать cron.

      Можно написать скрипт, можно отдельными командами:

      wal-g backup-push $PGDATA -f

      wal-g delete retain 2 --confirm