Утилита резервирования 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 и устанавливается аккуратно - не копирует себя в стандартные директории linux. Чтобы не писать каждый раз путь к утилите, можно её скопировать или создать символическую ссылку в какой-нибудь директории, которая есть в переменной окружения $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 Можно иметь несколько файлов с разными настройками и указывать нужный файл параметром --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. Алгоритм brotli обеспечивает лучшее и быстрое сжатие (лучше чем LZ4, быстрее чем LZMA). Благодаря brotli и многопоточности, WAL-G чрезвычайно быстро резервирует.
Скрытый текст
Для работы не с директорией, а по протоколу S3 достаточно поменять параметры в файле $HOME/.walg.json, команды резервирования и восстановления остаются теми же самыми. Или создать ещё один файл и добавить параметр --config к параметрам утилиты WAL-G.
Пример файла конфигурации для протокола 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-сервера RUSTFS есть веб-консоль управления http://localhost:9001 (rustfsadmin/rustfsadmin)
Приведённые в статье примеры можно попробовать на виртуальной машине Tantor DBA1-18.ova

Пример для Yandex Cloud и Patroni описаны в базе знаний.
Для проверки того, что 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).
Скрытый текст
Файл службы не поставляется. Пример команд, которые автоматизируют запуск pg_receivewal как службы:
postgres@host:~$ mkdir $HOME/archivelog touch $HOME/archivelog/pg_receivewal.log sudo chown postgres:postgres /var/lib/postgresql/archivelog/pg_receivewal.log sudo chmod 660 /var/lib/postgresql/archivelog/pg_receivewal.log cat > $HOME/pg_receivewal.service << EOF [Unit] # имя для systemctl service status Description=postgres pg_receivewal # запустится после того, как поднимется сеть After=network.target [Service] # работает в foreground Type=simple # переменная окружения Environment=PGDATA=/var/lib/postgresql/tantor-se-18/data # директория запуска WorkingDirectory=/var/lib/postgresql/archivelog # до запуска выполнить команду ExecStartPre=/opt/tantor/db/18/bin/pg_receivewal --create-slot --if-not-exists --slot=arch # команда запуска ExecStart=/opt/tantor/db/18/bin/pg_receivewal -D /var/lib/postgresql/archivelog --slot=arch --synchronous -w -v Restart=on-failure RestartSec=10s User=postgres Group=postgres # для создаваемых процессом файлов, umask это инвертированный chmod UMask=047 #вывод stdout в файл StandardOutput=append:/var/lib/postgresql/archivelog/pg_receivewal.log #вывод stderr в файл StandardError=inherit [Install] # чтобы не запускалось в single mode WantedBy=multi-user.target EOF sudo cp $HOME/pg_receivewal.service /usr/lib/systemd/system/pg_receivewal.service sudo chmod 644 /usr/lib/systemd/system/pg_receivewal.service sudo systemctl daemon-reload sudo systemctl enable pg_receivewal sudo systemctl start pg_receivewal sudo systemctl status pg_receivewal
Если нужна гарантия отсутствия потерь транзакций, то нужно задать параметр конфигурации 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 написал Лоренц Альбе. При использовании утилиты WAL-G, копирование и переименование файла .partial можно установить в restore_command заранее, что минимизирует ошибки во время восстановления.
Скрытый текст
На языке Go написан аналог pg_receivewal, который называется pgrwl. Он работает с S3 и файловой системой, но с файлом .partial работает точно так же, как pg_receivewal. Так как pg_receivewal входит в стандартную поставку и поддерживается сообществом, то имеет смысл использовать pg_receivewal.
То, что в документации к Barman файл .partial описан, это плюс Barman. В pgBackRest пишут: "Насколько мне известно, в документации PostgreSQL нет информации о файлах с расширением .partial. ... хотя могут быть случаи, когда он вам понадобится. Впрочем, если вы ищете данные, лучше использовать исходный WAL-файл с мастера, если он доступен. Это не значит, что файл .partial бесполезен, просто в тех немногих случаях, когда он появляется, по нашему опыту, есть более удачное решение, чем его использование." Nuff said.
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 может не только вытягивать журналы, но и вытягивать файлы PGDATA (бэкапить кластер PostgreSQL в режиме “pull”) по репликационному протоколу. Эта возможность уже готова и будет включена в следующую версию WAL-G. При использовании репликационного протокола пока нет многопоточной передачи и дельта-бэкапов и бэкап кластера будет создаваться дольше. Это касается только создания бэкапов в режие «pull», вытягивание WAL не имеет таких ограничений. Также, ни в режиме «push», ни в режиме «pull» WAL-G не принимает текущий WAL-файл и при полной потере директории PGDATA/pg_wal нельзя будет восстановить транзакции из текущего WAL-файла. Это не является проблемой, так как WAL-G может архивировать и восстанавливать журналы совместно с утилитой pg_receivewal, которая способна вытягивать журнальные записи из текущего WAL-файла и сохранять их в файл .partial.
Отсутствие потерь (zero data loss, RPO=0) способны обеспечить: утилита pg_receivewal, pgrwl, процесс walreceiver (на физических репликах), Polar DataMax (в Tantor XData).
Создание бэкапа утилитой WAL-G
Чтобы изменения подействовали, нужно остановить и запустить (перезапустить недостаточно) экземпляр.
Для проверки того, что мы правильно настроили архивирование журналов, переключимся на новый WAL-файл и убедимся, что archive_command выполнена:
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, сохраняются сообщения утилиты WAL-G.
Зарезервируем директорию кластера. Первый бэкап всегда полный, от него отсчитываются «дельты» (дифференциальные инкрементальные и кумулятивные инкрементальные бэкапы, и те и те WAL-G делает) В команде создания бэкапа нужно передать название директории кластера $PGDATA:
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
В директории для бэкапов (WALG_FILE_PREFIX) появятся файлы, которые и являются бэкапом кластера баз данных:
postgres@host:~$ ls -al /var/lib/postgresql/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, то она сохранила записи текущего WAL-файла в файле .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
В файле указан WAL-файл, с которого должен начаться накат журналов и адрес журнальной записи о завершении контрольной точки (CHECKPOINT LOCATION), после наката этой журнальной записи, восстанавливаемая директория PGDATA станет согласованной и может открываться экземпляром.
Для копирования из архива журналов и их наката нужно создать файл recovery.signal, который укажет, что нужно выполнять команды из параметра конфигурации restore_command и накатывать полученные журнальные файлы. После создания файла запустить экземпляр:
postgres@host:~$ touch $PGDATA/recovery.signal postgres@host:~$ pg_ctl start done server started
Процесс экземпляра startup будет выполнять команду, указанную в параметре конфигурации restore_command и применять WAL-файлы, которые эта команда скопирует в директорию PGDATA/pg_wal. Экземпляр будет переведён в состяние, в соответствии со значениями параметров конфигурации (recovery_target_*), которыми можно указать, до какого момента выполнять восстановление и что делать после достижения этого момента. Мы не устанавливаем параметры recovery_target_*, так как, по умолчанию, накатываются все WAL-файлы, которые сможет найти команда в restore_command, после чего кластер открывается в режиме чтения-записи.
Первая часть 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 для резервирования и восстанновления кластера PostgreSQL, а также на что обратить внимание, чтобы не было потерь транзакций при восстановлении (zero data loss).