Перейти к содержимому

02 Занятие 02: Резервное копирование / Базовая резервная копия

Исходная страница в нативном Markdown: Резервное копирование / Базовая резервная копия
Примечание

Эта страница извлечена из официального PDF в нативный Markdown. Текст слайдов, код и комментарии сохранены в порядке чтения; исходные PDF и HTML остаются эталоном макета. HTML source: dba3_02_backup_base.html Archive: DBA3-handouts-16.zip Страниц PDF: 26

Page 1: Резервное копирование / Базовая резервная копия

Авторские права

© Postgres Professional, 2017–2025 Авторы: Егор Рогов, Павел Лузанов, Илья Баштанов, Алексей Береснев Фото: Олег Бартунов (монастырь Пху и пик Бхрикути, Непал)

Использование материалов курса

Некоммерческое использование материалов курса (презентации, демонстрации) разрешается без ограничений. Коммерческое использование возможно только с письменного разрешения компании Postgres Professional. Запрещается внесение изменений в материалы курса.

Обратная связь

Отзывы, замечания и предложения направляйте по адресу: edu@postgrespro.ru

Отказ от ответственности

Компания Postgres Professional не несет никакой ответственности за любые повреждения и убытки, включая потерю дохода, нанесенные прямым или непрямым, специальным или случайным использованием материалов курса. Компания Postgres Professional не предоставляет каких-либо гарантий на материалы курса. Материалы курса предоставляются на основе принципа «как есть» и компания Postgres Professional не обязана предоставлять сопровождение, поддержку, обновления, расширения и изменения.

Page 2: Темы

  • Понятие физической резервной копии
  • Холодное и горячее резервирование
  • Протокол репликации и слот
  • Клонирование кластера и архивная копия
  • Проверка целостности
  • API резервирования

Page 3: Физическая копия

Базовая физическая копия — копия всех файлов кластера

    • быстрее, чем логическое резервирование
    • восстанавливается статистика
  • − можно восстановиться только на совместимой системе
  • − и на той же самой основной версии PostgreSQL
  • − выборочная копия невозможна, копируется весь кластер

Комментарии преподавателя

Физическое резервирование подразумевает копирование всех файлов, относящихся к кластеру БД (как файлов данных, так и служебных файлов), то есть создание полной двоичной копии.

Копирование файлов работает быстрее, чем выгрузка SQL-команд при логическом резервировании; запустить сервер из созданной физической копии — дело нескольких минут, в отличие от восстановления из логической копии. Кроме того, нет необходимости заново собирать статистику — она также восстанавливается из копии.

Но есть и минусы. Из физической резервной копии можно восстановить систему только на совместимой платформе (та же ОС, та же разрядность, тот же порядок байтов в представлении чисел и т. п.) и только на той же основной версии PostgreSQL. Кроме того, невозможно сделать физическую копию отдельных баз данных кластера, возможно копирование только всего кластера целиком.

Page 4: Холодное резервирование

Выключенный сервер

  • если выполнена контрольная точка, то достаточно скопировать файлы
  • копию можно развернуть на другом сервере, независимо от PGDATA
    • простота
  • − требуется прерывание обслуживания
  • Снимок файловой системы
    • как при неаккуратном выключении: при старте потребуется
    • восстановление, но в копию войдут все нужные файлы журнала
    • данные, в т. ч. табличные пространства, должны войти в один снимок
      • не надо останавливать сервер
    • − файловые системы, поддерживающие снимки, работают медленней

Комментарии преподавателя

Смысл холодного резервирования состоит в том, чтобы сделать копию файлов кластера в тот момент, когда данные на диске согласованы, то есть на диск сброшено актуальное состояние всех страниц. Восстановление из такой копии происходит просто: файлы разворачиваются, запускается сервер — и он сразу же готов к работе.

Сделать такую копию можно лишь корректно остановив сервер с выполнением контрольной точки. Минус понятен: необходима остановка сервера (надолго при большом объеме данных).

Время простоя можно сократить за счет предварительного выполнения rsync (или аналогичного инструмента) при работающем сервере. Тогда после останова сервера rsync докопирует только изменения (которых, предположительно, будет немного). Но простоя все равно не избежать.

Другой вариант — сделать несогласованную копию, в которую попадут страницы, сохраненные в разное время. Такая рассогласованность неизбежна при некорректном отключении сервера или при создании снимка файловой системы. В последнем случае все файлы кластера должны попасть в один снимок. Это может оказаться невозможным, если файлы расположены в разных файловых системах.

При восстановлении из несогласованных данных серверу при старте потребуется согласовать страницы. Это обычная автоматическая процедура восстановления после сбоя. Она не представляет проблемы, так как необходимые файлы журнала гарантированно попадут в копию, но потребует некоторого времени.

https://postgrespro.ru/docs/postgresql/16/backup-file

Page 5: Холодная файловая копия

Файлы остановленного кластера можно скопировать и запустить с ними второй сервер. При этом не важно, был ли сервер остановлен корректно. Создадим базу данных и таблицу.

student$ psql
α=> CREATE DATABASE backup_base;
CREATE DATABASE
α=> \c backup_base
You are now connected to database "backup_base" as user "student".
α=> CREATE TABLE t(s text);
CREATE TABLE
α=> INSERT INTO t VALUES ('Эта строка вставлена на α...');
INSERT 0 1

Аварийно останавливаем сервер alpha и копируем файлы на сервер beta:

student$ sudo kill -QUIT $(sudo head -n 1 /var/lib/postgresql/16/alpha/postmaster.pid)
student$ sudo pg_ctlcluster 16 beta stop
Cluster is not running.
student$ sudo rm -rf /var/lib/postgresql/16/beta
student$ sudo cp -a /var/lib/postgresql/16/alpha /var/lib/postgresql/16/beta

Сервер beta запускается, восстанавливая согласованность:

student$ sudo pg_ctlcluster 16 beta start
student$ sudo tail -n 7 /var/log/postgresql/postgresql-16-beta.log
2026-04-10 18:00:49.842 MSK [66007] LOG:  database system was not properly shut down;
automatic recovery in progress
2026-04-10 18:00:49.858 MSK [66007] LOG:  redo starts at 0/1B83330
2026-04-10 18:00:49.932 MSK [66007] LOG:  invalid record length at 0/1FB5708: expected at
least 24, got 0
2026-04-10 18:00:49.932 MSK [66007] LOG:  redo done at 0/1FB56E0 system usage: CPU: user:
0.00 s, system: 0.01 s, elapsed: 0.07 s
2026-04-10 18:00:50.063 MSK [66005] LOG:  checkpoint starting: end-of-recovery immediate
wait
2026-04-10 18:00:53.423 MSK [66005] LOG:  checkpoint complete: wrote 932 buffers (5.7%);
0 WAL file(s) added, 0 removed, 0 recycled; write=0.046 s, sync=3.242 s, total=3.375 s;
sync files=308, longest=0.026 s, average=0.011 s; distance=4297 kB, estimate=4297 kB;
lsn=0/1FB5708, redo lsn=0/1FB5708
2026-04-10 18:00:53.448 MSK [66004] LOG:  database system is ready to accept connections
student$ psql -p 5433 -d backup_base
β=> SELECT * FROM t;
              s
------------------------------
 Эта строка вставлена на α...
(1 row)

Page 6: Горячее резервирование

Работающий сервер

  • страницы не согласованы между собой, как при неаккуратном
  • выключении
  • страница может меняться во время ее копирования
  • (проблема неатомарного чтения и записи)
  • для восстановления согласованности необходимы журнальные записи
  • от последней контрольной точки за все время копирования
  • (в процессе копирования сервер может удалить часть файлов)
    • не требуется прерывание обслуживания
  • − нужны специальные инструменты

Комментарии преподавателя

Горячее резервирование выполняется на работающем сервере, поэтому в копию наверняка попадут несогласованные между собой страницы.

Более того. При резервном копировании данные читаются не через буферный кеш, а напрямую из файлов. Содержимое файлов на диске, очевидно, изменяется во время копирования, а гарантии атомарности чтения/записи страниц PostgreSQL может и не быть (это зависит от файловой системы и оборудования и обсуждается в теме «Настройка журнала» курса DBA2). Поэтому в резервную копию могут попадать «безнадежные» страницы, к которым даже нельзя применить журнальные записи. Это первая сложность.

Вторая сложность состоит в том, что копирование файлов данных может занимать достаточно много времени. Но сервер, после выполнения очередной контрольной точки, может удалить часть файлов журнала, которые уже не нужны ему для восстановления после сбоя, но нужны для резервной копии.

Если не принять специальных мер, сделанная резервная копия будет непригодна для восстановления. Поэтому для горячего резервирования требуются специальные инструменты. PostgreSQL предоставляет низкоуровневый интерфейс, используя который можно реализовать надежное копирование. Этот интерфейс использует и штатная утилита pg_basebackup, и другие сторонние средства резервного копирования.

https://postgrespro.ru/docs/postgresql/16/continuous-archiving#BACKUP-BA SE-BACKUP

Page 7: Протокол репликации

Задачи

  • управление резервным копированием и репликацией
  • в частности, получение потока журнальных записей
  • Обслуживается процессом wal sender
    • max_wal_senders = 10
    • wal_level = replica или logical, но не minimal
  • Подключение
    • роль с атрибутом REPLICATION или SUPERUSER
    • разрешение на подключение в pg_hba.conf

Комментарии преподавателя

Для упрощения задачи сервер PostgreSQL предоставляет протокол репликации — специальный протокол для управления как собственно репликацией (рассматривается в одноименном модуле), так и резервным копированием. В частности, он позволяет получать поток журнальных записей, которые генерирует сервер.

На сервере подключение по протоколу репликации обслуживается процессом wal sender. Он похож на обычный обслуживающий процесс, который запускается при обычном подключении клиента, но понимает не SQL, а специальные команды. Число одновременно работающих процессов wal_sender ограничено параметром max_wal_senders (значение по умолчанию — 10).

Уровень журнала должен быть не ниже, чем replica. Дело в том, что на уровне minimal такие команды, как CREATE TABLE AS SELECT, CREATE INDEX или COPY FROM не попадают в журнал: долговечность обеспечивается тем, что данные не остаются в оперативной памяти, а сразу записываются на диск. Этого достаточно для восстановления после сбоя и из холодной копии, но недостаточно для восстановления из горячей копии.

Чтобы использовать протокол репликации, клиент должен подключаться к серверу под ролью, имеющей атрибут REPLICATION (либо под суперпользователем). В pg_hba.conf надо разрешить подключение этой роли к базе данных replication (это не название БД, а ключевое слово). Причем разрешения для all недостаточно, подключение к replication должно быть разрешено отдельно.

https://postgrespro.ru/docs/postgresql/16/protocol-replication

Page 8: Слот репликации

Серверный объект для гарантии получения журнальных записей

  • помнит, какая запись была передана клиенту последней
  • число слотов ограничено max_replication_slots = 10
  • Не позволяет удалить сегмент WAL, пока все его записи не переданы клиенту
    • клиент может получать данные в удобном режиме,
    • в том числе отключаться на время
    • при отключении клиента журнальные файлы накапливаются на сервере
    • мониторинг состояния: pg_replication_slots

Комментарии преподавателя

Чтобы при выполнении контрольной точки сервер не удалил файлы WAL преждевременно, можно применять слот репликации. Если поток журнальных записей идет через слот, то слот помнит, какие записи уже были переданы клиенту, и не позволяет серверу удалять файл WAL до тех пор, пока клиент не получит все записи из этого файла.

Использование слота позволяет клиенту не беспокоиться о том, что сервер сотрет файл журнала раньше времени. Клиент даже может отключиться и затем через какое-то время подключиться вновь и продолжить получать журнальные записи с того момента, на котором остановился.

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

Общее количество слотов, которые могут быть созданы, ограничено конфигурационным параметром max_replication_slots (значение по умолчанию — 10).

Подробнее применение слотов обсуждается в модуле «Репликация».

https://postgrespro.ru/docs/postgresql/16/warm-standby#STREAMING-REP LICATION-SLOTS

Page 9: Клонирование кластера

Source slide page 9: Клонирование кластера{#source-figure-009 caption=“Source slide page 9: Клонирование кластера”}

для физического копирования используется утилита pg_basebackup после копирования новый сервер готов к запуску

Комментарии преподавателя

Для немедленного развертывания нового сервера из копии вызывают pg_basebackup в обычном формате (–format=plain — по умолчанию), запуская утилиту на целевом сервере. Она подключается к серверу-источнику и копирует с него файлы в локальный каталог, указанный параметром –pgdata.

Дополнительные табличные пространства копируются по тем же абсолютным путям, что и на сервере-источнике. Пути можно переназначить, указав соответствия в параметрах –tablespace-mapping утилиты. Это необходимо, если pg_basebackup запускается на самом сервере-источнике.

При потоковой доставке (–wal-method=stream — по умолчанию) утилита устанавливает второе соединение для передачи потока журнальных записей, которые генерирует работающий сервер, в локальный каталог, указанный параметром –waldir.

По умолчанию второе соединение использует временный слот репликации, который создается при подключении и удаляется при завершении работы pg_basebackup. Однако можно указать и имя постоянного слота, который должен существовать на момент запуска утилиты или создаваться ей.

В формате plain можно сжимать данные на сервере, уменьшая нагрузку на сеть. Переданные данные затем распаковываются утилитой. Но журнальные записи в потоковом режиме не сжимаются.

https://postgrespro.ru/docs/postgresql/16/app-pgbasebackup

Page 10: Клонирование кластера

Сделаем базовую копию работающего сервера alpha и восстановим с помощью этой копии сервер beta.

student$ sudo pg_ctlcluster 16 alpha start
student$ psql backup_base

Разрешение на локальное подключение по протоколу репликации в pg_hba.conf уже имеется:

student$ psql -U postgres << EOF
SELECT type, database, user_name, address, auth_method
FROM pg_hba_file_rules() WHERE 'replication' = ANY(database);
EOF
 type  |   database    | user_name |  address  |  auth_method
-------+---------------+-----------+-----------+---------------
 local | {replication} | {all}     |           | trust
 host  | {replication} | {all}     | 127.0.0.1 | scram-sha-256
 host  | {replication} | {all}     | ::1       | scram-sha-256
(3 rows)

Чтобы утилита pg_basebackup могла подключиться к серверу под ролью student, эта роль должна иметь атрибут REPLICATION:

α=> \du student
                  List of roles
 Role name |             Attributes
-----------+-------------------------------------
 student   | Create role, Create DB, Replication

Остановим сервер beta и удалим каталог данных этого сервера.

student$ sudo pg_ctlcluster 16 beta stop
student$ sudo rm -rf /var/lib/postgresql/16/beta

Скопируем, выполнив быструю контрольную точку. Данные будут сжаты на стороне сервера и затем распакованы утилитой — это ускоряет передачу по сети, но при локальном подключении не даст эффекта. Параметр –pgdata указывает целевой каталог для записи копии. Каталог создается автоматически, но если он уже существует, то должен быть пуст.

postgres$ pg_basebackup \
  --checkpoint=fast \
  --compress=server-zstd \
  --pgdata=/var/lib/postgresql/16/beta

Эта команда использовала значения по умолчанию: –format=plain –wal-method=stream В подкаталог pg_wal скопированы файлы журнала:

postgres$ ls -l /var/lib/postgresql/16/beta/pg_wal
total 16388
-rw------- 1 postgres postgres 16777216 апр 10 18:01 000000010000000000000002
drwx------ 2 postgres postgres     4096 апр 10 18:01 archive_status

Page 11: Проверка целостности

Проверка файлов данных

  • задача: гарантировать, что в копию попадут целостные данные
  • утилиты pg_basebackup и pg_checksums
  • проверяют контрольные суммы страниц файлов отношений
  • Проверка резервной копии
    • задача: проверить, что целостность данных в копии
    • не нарушилась со временем
    • файл манифеста backup_manifest
    • утилита pg_verifybackup проверяет файлы по списку из манифеста

Комментарии преподавателя

Данные могут повреждаться как при записи на носитель, так и в процессе хранения. Важно убедиться в том, что в копию попали целостные данные и в дальнейшем эта целостность не нарушилась.

Расчет контрольных сумм файлов отношений включается при инициализации кластера (или в процессе работы утилитой pg_checksums). Контрольная сумма сохраняется при каждом изменении страницы в ее заголовке. Вычисленная и сохраненная контрольная сумма сравниваются:

● при каждом чтении страницы в буферный кеш;

● утилитой pg_basebackup при формировании резервной копии;

● утилитой pg_checksums в режиме проверки.

Утилита pg_basebackup включает в копию файл backup_manifest с информацией о файлах (имена, размеры, вычисленные контрольные суммы) и журнальных записях (начальная и конечная позиции WAL, линия времени), а также контрольную сумму самого манифеста.

https://postgrespro.ru/docs/postgresql/16/backup-manifest-format

Утилита pg_verifybackup проверяет соответствие резервной копии манифесту: наличие файлов, корректность контрольных сумм, возможность чтения и разбора записей WAL, необходимых для восстановления.

https://postgrespro.ru/docs/postgresql/16/app-pgverifybackup

Для полной уверенности все же следует развернуть резервную копию и проверить работоспособность сервера, ведь совпадение контрольных сумм не дает гарантии, что данные не были повреждены.

Page 12: Проверка целостности

Резервная копия содержит файл манифеста, вот его начало и конец:

postgres$ head -5 /var/lib/postgresql/16/beta/backup_manifest
{ "PostgreSQL-Backup-Manifest-Version": 1,
"Files": [
{ "Path": "backup_label", "Size": 225, "Last-Modified": "2026-04-10 15:01:36 GMT",
"Checksum-Algorithm": "CRC32C", "Checksum": "45a3d732" },
{ "Path": "postgresql.auto.conf", "Size": 88, "Last-Modified": "2025-11-25 15:23:08 GMT",
"Checksum-Algorithm": "CRC32C", "Checksum": "536f950b" },
{ "Path": "pg_logical/replorigin_checkpoint", "Size": 8, "Last-Modified": "2026-04-10
15:01:36 GMT", "Checksum-Algorithm": "CRC32C", "Checksum": "c74b6748" },
postgres$ tail -6 /var/lib/postgresql/16/beta/backup_manifest
{ "Path": "global/pg_control", "Size": 8192, "Last-Modified": "2026-04-10 15:01:36 GMT",
"Checksum-Algorithm": "CRC32C", "Checksum": "43872087" }
],
"WAL-Ranges": [
{ "Timeline": 1, "Start-LSN": "0/2000028", "End-LSN": "0/2000100" }
],
"Manifest-Checksum": "1717a28bdccedfcd93e1fdf00f9fdb7284dbdaaeeb1bc3e677de7cf5e384ec8a"}

Проверим целостность копии утилитой pg_verifybackup:

postgres$ /usr/lib/postgresql/16/bin/pg_verifybackup /var/lib/postgresql/16/beta
backup successfully verified

Утилита проверяет по манифесту наличие файлов, их контрольные суммы, а также наличие и возможность чтения всех записей WAL, необходимых для восстановления. Запускаем второй сервер.

student$ sudo pg_ctlcluster 16 beta start

Теперь оба сервера работают одновременно и независимо. Проверим:

student$ psql -p 5433 -d backup_base
β=> INSERT INTO t VALUES ('...а эта — на β.');
INSERT 0 1
β=> SELECT * FROM t;
              s
------------------------------
 Эта строка вставлена на α...
 ...а эта — на β.
(2 rows)

Page 13: Потоковая доставка WAL

Source slide page 13: Потоковая доставка WAL{#source-figure-013 caption=“Source slide page 13: Потоковая доставка WAL”}

создание копии для будущего использования

Комментарии преподавателя

Для создания архивных копий используется формат tar. По умолчанию используется потоковая доставка журнальных записей (параметр –wal-method=stream).

Файлы кластера будут сохранены в файле base.tar. Каждое дополнительное табличное пространство копируется в отдельный tar-файл, имя которого совпадает с OID табличного пространства. Сегменты WAL помещаются в отдельный файл pg_wal.tar.

Утилита может выполнять сжатие как на стороне клиента, так и на стороне сервера (в последнем случае pg_wal.tar не сжимается). К именам сжатых tar-архивов добавится суффикс, соответствующий методу сжатия. Например, при сжатии методом gzip основной файл будет называться base.tar.gz.

Для восстановления из такой копии сначала потребуется развернуть tar-файлы по правильным путям. При этом пути табличных пространств можно изменить: для этого нужно перед запуском сервера отредактировать файл tablespace_map или использовать параметр командной строки –tablespace-mapping.

Page 14: Файловая доставка клиенту

Source slide page 14: Файловая доставка клиенту{#source-figure-014 caption=“Source slide page 14: Файловая доставка клиенту”}

создание копии для будущего использования

Комментарии преподавателя

При создании архивной копии можно использовать другой режим — файловую доставку журнальных записей (–wal-method=fetch).

В этом случае отдельное соединение не создается, а сегменты журнала копируются и передаются по основному соединению. Это происходит после того, как скопированы все файлы кластера. Необходимо учитывать, что во время контрольной точки сервер может удалить сегменты журнала, уже не нужные для восстановления, поэтому стоит позаботиться об их сохранности, установив достаточно большое значение параметру wal_keep_size.

Журнальные сегменты записываются в файл base.tar вместе с остальными файлами кластера.

В большинстве случаев возможность использовать режим fetch при создании копии на клиенте не нужна. Она осталась с прежних версий и в настоящее время может иметь смысл только для того, чтобы передавать журнальные записи сжатыми — режим stream не дает такой возможности.

Page 15: Архивная копия на стороне клиента

Создадим архивную копию на клиенте. Сжатие будем выполнять также на стороне клиента.

student$ pg_basebackup \
  --checkpoint=fast \
  --compress=client-gzip:level=9 \
  --format=tar \
  --pgdata=/home/student/tmp/alpha-stream.backup

В этой команде по умолчанию была использована потоковая доставка WAL (–wal-method=stream). Посмотрим на получившуюся копию:

student$ ls -lh /home/student/tmp/alpha-stream.backup
total 5,2M
-rw------- 1 student student 220K апр 10 18:02 backup_manifest
-rw------- 1 student student 5,0M апр 10 18:02 base.tar.gz
-rw------- 1 student student  17K апр 10 18:02 pg_wal.tar.gz

При потоковой доставке записей WAL в формате tar для них создается отдельный файл:

student$ tar tf /home/student/tmp/alpha-stream.backup/pg_wal.tar.gz
000000010000000000000004

Теперь создадим еще одну архивную копию на клиенте, но используем режим доставки fetch. В этом случае сегменты WAL будут передаваться по тому же соединению, что и данные. Сжатие поручим серверу.

student$ pg_basebackup \
  --checkpoint=fast \
  --wal-method=fetch \
  --compress=server-gzip:level=9 \
  --format=tar \
  --pgdata=/home/student/tmp/alpha-fetch.backup

В получившейся копии сегменты WAL помещены в файл base.tar.gz.

student$ ls -lh /home/student/tmp/alpha-fetch.backup
total 5,2M
-rw------- 1 student student 220K апр 10 18:02 backup_manifest
-rw------- 1 student student 5,0M апр 10 18:02 base.tar.gz
student$ tar tf /home/student/tmp/alpha-fetch.backup/base.tar.gz pg_wal
pg_wal/
pg_wal/000000010000000000000005
pg_wal/archive_status/000000010000000000000005.done

Page 16: Файловая доставка серверу

Source slide page 16: Файловая доставка серверу{#source-figure-016 caption=“Source slide page 16: Файловая доставка серверу”}

создание копии для будущего использования копия создается на сервере без передачи данных по сети

Комментарии преподавателя

Архивную копию можно создать на сервере, запуская pg_basebackup на клиенте. Данные при этом не передаются по сети.

Создание копии на сервере задается параметром командной строки pg_basebackup –target=server:path, где path — путь к каталогу в файловой системе сервера (по умолчанию подразумевается –target=client).

В этом режиме также можно использовать сжатие, но, конечно, только на стороне сервера.

При создании копии на сервере невозможно использовать потоковый режим доставки WAL (stream), поскольку журнальные записи вообще не передаются клиенту. Необходимо указать режим доставки fetch, при котором накопившиеся журнальные сегменты копируются и помещаются в файл base.tar вместе с остальными файлами кластера.

Page 17: Архивная копия на сервере

Запустим pg_basebackup на клиенте и при этом сохраним архивную копию на сервере. В этом случае мы обязаны использовать режим доставки fetch, поэтому установим параметр wal_keep_size (будем надеяться, что этого значения хватит):

α=> ALTER SYSTEM SET wal_keep_size = '32MB';
ALTER SYSTEM
student$ sudo pg_ctlcluster 16 alpha reload

Запустим pg_basebackup, указав каталог на сервере для сохранения архивной копии и режим сжатия zstd.

student$ pg_basebackup \
  --checkpoint=fast \
  --wal-method=fetch \
  --target=server:/var/lib/postgresql/alpha.backup \
  --compress=server-zstd:level=12

Получили сжатую архивную копию в формате tar (он подразумевается).

postgres$ ls -lh /var/lib/postgresql/alpha.backup
total 4,2M
-rw------- 1 postgres postgres 220K апр 10 18:02 backup_manifest
-rw------- 1 postgres postgres 4,0M апр 10 18:02 base.tar.zst

При режиме доставки fetch утилита сохраняет сегменты WAL в общем архиве:

postgres$ tar tf /var/lib/postgresql/alpha.backup/base.tar.zst pg_wal
pg_wal/
pg_wal/000000010000000000000007
pg_wal/archive_status/000000010000000000000007.done

Удалим архивную копию.

postgres$ rm -rf /var/lib/postgresql/alpha.backup

Page 18: Низкоуровневый взгляд

Source slide page 18: Низкоуровневый взгляд{#source-figure-018 caption=“Source slide page 18: Низкоуровневый взгляд”}

на время копирования устанавливается full_page_writes = on в самом начале выполняется контрольная точка (быстро или обычно)

Комментарии преподавателя

Общий алгоритм изготовления резервной копии на низком уровне одинаков как для pg_basebackup, так и для любых сторонних средств (которые могут потребоваться, поскольку pg_basebackup предоставляет только самую базовую функциональность).

  1. Надо сообщить серверу о том, что начинается резервное копирование.

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

Во-вторых, выполняется контрольная точка. Предусмотрено два режима: быстрое выполнение (что может привести к пиковой нагрузке на дисковую подсистему) и протяженное (которое определяется обычным параметром checkpoint_completion_target).

  1. После прохождения контрольной точки можно копировать файлы данных любым удобным способом.

  2. После того, как все скопировано, надо сообщить серверу, что резервное копирование завершено.

  3. Кроме того, так или иначе надо обеспечить попадание в резервную копию всех журнальных записей, сгенерированных с начала копирования и до его окончания.

Page 19: API резервирования

Начало копирования: pg\_backup\_start

  • выполняет контрольную точку, устанавливает full_page_writes
  • возвращает начальную позицию в журнале
  • Конец копирования: pg_backup_stop
    • возвращает конечную позицию в журнале
  • Копирование файлов
    • либо протокол репликации, либо любые средства ОС
  • Копирование журнала от начальной до конечной позиции
    • протокол репликации + слот либо средства ОС + wal_keep_size

Комментарии преподавателя

Описанный алгоритм резервного копирования можно использовать, чтобы реализовать свою собственную утилиту копирования.

Резервное копирование начинается вызовом функции pg_backup_start. Она устанавливает параметр full_page_writes и выполняет контрольную точку, как рассматривалось выше. Возвращаемое этой функцией значение — позиция в журнале, начиная с которой в копию должны попасть журнальные записи.

В конце копирования вызывается функция pg_backup_stop. Она возвращает конечную позицию в журнале.

Все журнальные записи между начальной и конечной позициями надо поместить в резервную копию. Поскольку при своей работе сервер может удалять журнальные файлы, которые не требуются для восстановления, надо либо пользоваться протоколом репликации и слотом, получая записи во время копирования (как pg_basebackup в режиме доставки –wal-method=stream), либо — что менее удобно — копировать файлы средствами ОС, установив параметр wal_keep_size. Можно копировать файлы в несколько потоков, использовать rsync и т. п.

https://postgrespro.ru/docs/postgresql/16/continuous-archiving#BACKUP-LO WLEVEL-BASE-BACKUP

Page 20: Итоги

Базовая резервная копия — полная копия кластера, включая табличные пространства, плюс журнал для восстановления согласованности

  • Горячее резервирование позволяет не останавливать сервер
  • Инструменты
    • протокол репликации
    • слот репликации
    • низкоуровневый API резервирования

Page 21: Практика

  1. В первом кластере создайте табличное пространство и базу данных с таблицей в этом пространстве. 2. Сделайте базовую резервную копию кластера с помощью pg_basebackup в формате tar со сжатием. 3. Разверните второй кластер из этой резервной копии. Табличное пространство разместите в другом каталоге, изменив файл tablespace_map. 4. Запустите второй сервер и проверьте его работоспособность.

Комментарии преподавателя

После выполнения практики удалите базу данных и табличное пространство в обоих кластерах.

Page 22: 1. Табличное пространство и база данных

student$ sudo mkdir /var/lib/postgresql/ts_dir
student$ sudo chown postgres /var/lib/postgresql/ts_dir

Табличные пространства может создавать только суперпользователь:

α=> \c - postgres
You are now connected to database "student" as user "postgres".
α=> CREATE TABLESPACE ts OWNER student LOCATION '/var/lib/postgresql/ts_dir';
CREATE TABLESPACE
α=> \c - student
You are now connected to database "student" as user "student".
α=> CREATE DATABASE backup_base;
CREATE DATABASE
α=> \c backup_base
You are now connected to database "backup_base" as user "student".
α=> CREATE TABLE t(s text) TABLESPACE ts;
CREATE TABLE
α=> INSERT INTO t VALUES ('Привет, мир!');
INSERT 0 1

2. Базовая резервная копия

Запускаем pg_basebackup от имени роли student, указывая формат tar со сжатием:

student$ pg_basebackup \
  --checkpoint=fast \
  --format=tar \
  --compress=client-gzip \
  --pgdata /home/student/tmp/backup
student$ ls -l /home/student/tmp/backup
total 5348
-rw------- 1 student student     342 апр 10 18:13 16409.tar.gz
-rw------- 1 student student  224520 апр 10 18:13 backup_manifest
-rw------- 1 student student 5224279 апр 10 18:13 base.tar.gz
-rw------- 1 student student   17097 апр 10 18:13 pg_wal.tar.gz

3. Восстановление из базовой резервной копии

student$ sudo pg_ctlcluster 16 beta stop
Cluster is not running.

Очистим основной каталог данных кластера beta. Права на каталог должны быть лишь у владельца.

student$ sudo rm -rf /var/lib/postgresql/16/beta
student$ sudo mkdir /var/lib/postgresql/16/beta
student$ sudo chown postgres /var/lib/postgresql/16/beta
student$ sudo chmod 700 /var/lib/postgresql/16/beta

Каталог для табличного пространства ts на сервере, который будет развернут из резервной копии:

student$ sudo mkdir /var/lib/postgresql/ts_beta_dir
student$ sudo chown postgres /var/lib/postgresql/ts_beta_dir

Разворачиваем резервную копию:

student$ sudo tar xf /home/student/tmp/backup/base.tar.gz -C /var/lib/postgresql/16/beta

Page 23: Page 23

student$ sudo tar xf /home/student/tmp/backup/16409.tar.gz -C /var/lib/postgresql/ts_beta_dir
student$ sudo tar xf /home/student/tmp/backup/pg_wal.tar.gz -C /var/lib/postgresql/16/beta/pg_wal

В каталоге pg_tblspc сейчас пусто:

student$ sudo ls /var/lib/postgresql/16/beta/pg_tblspc/

Символическая ссылка появится при старте сервера в соответствии с файлом tablespace_map (который находился внутри base.tar):

student$ sudo cat /var/lib/postgresql/16/beta/tablespace_map
16409 /var/lib/postgresql/ts_dir

Изменяем в этом файле путь для табличного пространства:

student$ sudo sed -i 's/ts_dir/ts_beta_dir/' /var/lib/postgresql/16/beta/tablespace_map

4. Запуск и проверка

Запускаем сервер.

student$ sudo pg_ctlcluster 16 beta start
student$ sudo ls -l /var/lib/postgresql/16/beta/pg_tblspc/
total 0
lrwxrwxrwx 1 postgres root 31 апр 10 18:13 16409 -> /var/lib/postgresql/ts_beta_dir
student$ psql -p 5433 -d backup_base
β=> \c backup_base
You are now connected to database "backup_base" as user "student".
β=> SELECT * FROM t;
      s
--------------
 Привет, мир!
(1 row)

Уборка

Удалим резервную копию.

student$ rm -rf /home/student/tmp/backup

Чтобы удалить базу данных, надо от нее отключиться.

α=> \c student
You are now connected to database "student" as user "student".
α=> DROP DATABASE backup_base;
DROP DATABASE
α=> DROP TABLESPACE ts;
DROP TABLESPACE
student$ sudo rm -rf /var/lib/postgresql/ts_dir

И для второго сервера:

β=> \c student
You are now connected to database "student" as user "student".
β=> DROP DATABASE backup_base;
DROP DATABASE
β=> DROP TABLESPACE ts;
DROP TABLESPACE
student$ sudo rm -rf /var/lib/postgresql/ts_beta_dir

Page 24: Практика+

  1. Подключите модуль basebackup_to_shell для создания базовой резервной копии на сервере с помощью определяемой пользователем команды. Эта команда должна сжимать tar-архив копии утилитой bzip2. 2. Выполните резервное копирование на сервере в формате tar. Убедитесь, что полученный архив сжат bzip2. 3. Восстановите кластер beta из полученного сжатого архива и проверьте его работоспособность.

Комментарии преподавателя

  1. Для подключения модуля укажите одноименную библиотеку в параметре shared_preload_libraries. Параметром basebackup_to_shell.command задайте команду, выполняемую при резервном копировании: bzip2 -c > архив.tar.bz2

https://postgrespro.ru/docs/postgresql/16/basebackup-to-shell

  1. Чтобы задействовать модуль при резервном копировании, укажите pg_basebackup –target=shell

  2. Для извлечения файлов из сжатого утилитой bzip2 архива tar воспользуйтесь командой: tar xjf архив.tar.bz2 -C каталог-назначения

После выполнения практики удалите созданные базы данных и резервную копию.

Page 25: 1. Подключение модуля

Запишем настройки для подключения и конфигурации модуля basebackup_to_shell в подключаемый файл конфигурации.

postgres$ cat << EOF > /etc/postgresql/16/alpha/conf.d/basebackup_to_shell.conf
shared_preload_libraries = basebackup_to_shell
basebackup_to_shell.command = 'bzip2 -c > /var/lib/postgresql/archive.backup/%f.bz2'
EOF

Перезапустим сервер.

student$ sudo pg_ctlcluster 16 alpha restart

Проверим установки.

student$ psql
α=> SHOW shared_preload_libraries;
 shared_preload_libraries
--------------------------
 basebackup_to_shell
(1 row)
α=> SHOW basebackup_to_shell.command;
             basebackup_to_shell.command
------------------------------------------------------
 bzip2 -c > /var/lib/postgresql/archive.backup/%f.bz2
(1 row)

Создадим базу данных и таблицу в ней.

α=> CREATE DATABASE backup_base;
CREATE DATABASE
α=> \c backup_base
You are now connected to database "backup_base" as user "student".
α=> CREATE TABLE t AS SELECT now() AS creatime;
SELECT 1

2. Резервное копирование

Создадим каталог для резервной копии.

postgres$ mkdir /var/lib/postgresql/archive.backup

Выполним резервное копирование. Использование потокового режима невозможно, поэтому воспользуемся режимом доставки WAL fetch.

student$ pg_basebackup \
  --checkpoint=fast \
  --wal-method=fetch \
  --target=shell
postgres$ ls -l /var/lib/postgresql/archive.backup
total 4464
-rw------- 1 postgres postgres   10072 апр 10 18:13 backup_manifest.bz2
-rw------- 1 postgres postgres 4558543 апр 10 18:13 base.tar.bz2

3. Восстановление из резервной копии

Удалим файлы кластера beta.

student$ sudo pg_ctlcluster 16 beta stop
Cluster is not running.
postgres$ rm -rf /var/lib/postgresql/16/beta

Page 26: Page 26

Source slide page 26: Page 26{#source-figure-026 caption=“Source slide page 26: Page 26”}

postgres$ mkdir /var/lib/postgresql/16/beta
postgres$ chmod 700 /var/lib/postgresql/16/beta

Извлечем файлы из архива.

postgres$ tar xjf /var/lib/postgresql/archive.backup/base.tar.bz2 -C /var/lib/postgresql/16/beta

Проверим, восстановлены ли данные.

student$ sudo pg_ctlcluster 16 beta start
student$ psql -p 5433 -d backup_base
β=> SELECT * FROM t;
           creatime
-------------------------------
 2026-04-10 18:13:49.437998+03
(1 row)

Уборка

α=> \c student
You are now connected to database "student" as user "student".
α=> DROP DATABASE backup_base;
DROP DATABASE
β=> \c student
You are now connected to database "student" as user "student".
β=> DROP DATABASE backup_base;
DROP DATABASE
student$ sudo pg_ctlcluster 16 beta stop
postgres$ rm -rf /var/lib/postgresql/archive.backup