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

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

---

Индекс LLMS: [llms.txt](/ru/llms.txt)

---

<!-- Generated by scripts/generate_skeleton.py. -->

> [!NOTE]
> Эта страница извлечена из официального PDF в нативный Markdown. Текст слайдов, код и комментарии сохранены в порядке чтения; исходные PDF и HTML остаются эталоном макета.
> **HTML source:** [dba3_02_backup_base.html](https://edu.postgrespro.ru/16/dba3-16/dba3_02_backup_base.html)
> **Archive:** [DBA3-handouts-16.zip](https://edu.postgrespro.ru/16/DBA3-handouts-16.zip)
> **Страниц PDF:** 26

## Page 1: Резервное копирование / Базовая резервная копия {#source-page-001}

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

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

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

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

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

## Page 2: Темы {#source-page-002}

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

## Page 3: Физическая копия {#source-page-003}

**Базовая физическая копия — копия всех файлов кластера**
  - + быстрее, чем логическое резервирование
  - + восстанавливается статистика
  - − можно восстановиться только на совместимой системе
  - − и на той же самой основной версии PostgreSQL
  - − выборочная копия невозможна, копируется весь кластер

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

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

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

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

## Page 4: Холодное резервирование {#source-page-004}

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

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

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

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

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

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

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

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

## Page 5: Холодная файловая копия {#source-page-005}

Файлы остановленного кластера можно скопировать и запустить с ними второй сервер. При этом не важно, был ли сервер остановлен корректно.
Создадим базу данных и таблицу.
```sh
student$ psql
```
```sql
α=> CREATE DATABASE backup_base;
```
```sql
CREATE DATABASE
```
```sql
α=> \c backup_base
```
```text
You are now connected to database "backup_base" as user "student".
```
```sql
α=> CREATE TABLE t(s text);
```
```sql
CREATE TABLE
```
```sql
α=> INSERT INTO t VALUES ('Эта строка вставлена на α...');
```
```sql
INSERT 0 1
```
Аварийно останавливаем сервер alpha и копируем файлы на сервер beta:
```sh
student$ sudo kill -QUIT $(sudo head -n 1 /var/lib/postgresql/16/alpha/postmaster.pid)
```
```sh
student$ sudo pg_ctlcluster 16 beta stop
```
```text
Cluster is not running.
```
```sh
student$ sudo rm -rf /var/lib/postgresql/16/beta
```
```sh
student$ sudo cp -a /var/lib/postgresql/16/alpha /var/lib/postgresql/16/beta
```
Сервер beta запускается, восстанавливая согласованность:
```sh
student$ sudo pg_ctlcluster 16 beta start
```
```sh
student$ sudo tail -n 7 /var/log/postgresql/postgresql-16-beta.log
```
```text
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
```
```sh
student$ psql -p 5433 -d backup_base
```
```sql
β=> SELECT * FROM t;
```
```text
              s
------------------------------
 Эта строка вставлена на α...
(1 row)
```

## Page 6: Горячее резервирование {#source-page-006}

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

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

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

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

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

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

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

## Page 7: Протокол репликации {#source-page-007}

**Задачи**
  - управление резервным копированием и репликацией
  - в частности, получение потока журнальных записей
- Обслуживается процессом 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: Слот репликации {#source-page-008}

**Серверный объект для гарантии получения журнальных записей**
  - помнит, какая запись была передана клиенту последней
  - число слотов ограничено 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-page-009}

![Source slide page 9: Клонирование кластера](images/page-009.png){#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: Клонирование кластера {#source-page-010}

Сделаем базовую копию работающего сервера alpha и восстановим с помощью этой копии сервер beta.
```sh
student$ sudo pg_ctlcluster 16 alpha start
```
```sh
student$ psql backup_base
```
Разрешение на локальное подключение по протоколу репликации в pg\_hba.conf уже имеется:
```sh
student$ psql -U postgres << EOF
SELECT type, database, user_name, address, auth_method
FROM pg_hba_file_rules() WHERE 'replication' = ANY(database);
EOF
```
```text
 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:
```text
α=> \du student
```
```sql
                  List of roles
 Role name |             Attributes
-----------+-------------------------------------
 student   | Create role, Create DB, Replication
```
Остановим сервер beta и удалим каталог данных этого сервера.
```sh
student$ sudo pg_ctlcluster 16 beta stop
```
```sh
student$ sudo rm -rf /var/lib/postgresql/16/beta
```
Скопируем, выполнив быструю контрольную точку. Данные будут сжаты на стороне сервера и затем распакованы утилитой — это ускоряет передачу по сети, но при локальном подключении не даст эффекта. Параметр --pgdata указывает целевой каталог для записи копии. Каталог создается автоматически, но если он уже существует, то должен быть пуст.
```sh
postgres$ pg_basebackup \
  --checkpoint=fast \
  --compress=server-zstd \
  --pgdata=/var/lib/postgresql/16/beta
```
Эта команда использовала значения по умолчанию:
--format=plain --wal-method=stream
В подкаталог pg\_wal скопированы файлы журнала:
```sh
postgres$ ls -l /var/lib/postgresql/16/beta/pg_wal
```
```text
total 16388
-rw------- 1 postgres postgres 16777216 апр 10 18:01 000000010000000000000002
drwx------ 2 postgres postgres     4096 апр 10 18:01 archive_status
```

## Page 11: Проверка целостности {#source-page-011}

**Проверка файлов данных**
  - задача: гарантировать, что в копию попадут целостные данные
  - утилиты 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: Проверка целостности {#source-page-012}

Резервная копия содержит файл манифеста, вот его начало и конец:
```sh
postgres$ head -5 /var/lib/postgresql/16/beta/backup_manifest
```
```text
{ "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" },
```
```sh
postgres$ tail -6 /var/lib/postgresql/16/beta/backup_manifest
```
```text
{ "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:
```sh
postgres$ /usr/lib/postgresql/16/bin/pg_verifybackup /var/lib/postgresql/16/beta
```
```text
backup successfully verified
```
Утилита проверяет по манифесту наличие файлов, их контрольные суммы, а также наличие и возможность чтения всех записей WAL, необходимых для восстановления.
Запускаем второй сервер.
```sh
student$ sudo pg_ctlcluster 16 beta start
```
Теперь оба сервера работают одновременно и независимо. Проверим:
```sh
student$ psql -p 5433 -d backup_base
```
```sql
β=> INSERT INTO t VALUES ('...а эта — на β.');
```
```sql
INSERT 0 1
```
```sql
β=> SELECT * FROM t;
```
```text
              s
------------------------------
 Эта строка вставлена на α...
 ...а эта — на β.
(2 rows)
```

## Page 13: Потоковая доставка WAL {#source-page-013}

![Source slide page 13: Потоковая доставка WAL](images/page-013.png){#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-page-014}

![Source slide page 14: Файловая доставка клиенту](images/page-014.png){#source-figure-014 caption="Source slide page 14: Файловая доставка клиенту"}

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

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

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

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

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

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

## Page 15: Архивная копия на стороне клиента {#source-page-015}

Создадим архивную копию на клиенте. Сжатие будем выполнять также на стороне клиента.
```sh
student$ pg_basebackup \
  --checkpoint=fast \
  --compress=client-gzip:level=9 \
  --format=tar \
  --pgdata=/home/student/tmp/alpha-stream.backup
```
В этой команде по умолчанию была использована потоковая доставка WAL (--wal-method=stream).
Посмотрим на получившуюся копию:
```sh
student$ ls -lh /home/student/tmp/alpha-stream.backup
```
```text
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 для них создается отдельный файл:
```sh
student$ tar tf /home/student/tmp/alpha-stream.backup/pg_wal.tar.gz
```
```text
000000010000000000000004
```
Теперь создадим еще одну архивную копию на клиенте, но используем режим доставки fetch. В этом случае сегменты WAL будут передаваться по тому же соединению, что и данные. Сжатие поручим серверу.
```sh
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.
```sh
student$ ls -lh /home/student/tmp/alpha-fetch.backup
```
```text
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
```
```sh
student$ tar tf /home/student/tmp/alpha-fetch.backup/base.tar.gz pg_wal
```
```text
pg_wal/
pg_wal/000000010000000000000005
pg_wal/archive_status/000000010000000000000005.done
```

## Page 16: Файловая доставка серверу {#source-page-016}

![Source slide page 16: Файловая доставка серверу](images/page-016.png){#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: Архивная копия на сервере {#source-page-017}

Запустим pg\_basebackup на клиенте и при этом сохраним архивную копию на сервере. В этом случае мы обязаны использовать режим доставки fetch, поэтому установим параметр wal\_keep\_size (будем надеяться, что этого значения хватит):
```sql
α=> ALTER SYSTEM SET wal_keep_size = '32MB';
```
```sql
ALTER SYSTEM
```
```sh
student$ sudo pg_ctlcluster 16 alpha reload
```
Запустим pg\_basebackup, указав каталог на сервере для сохранения архивной копии и режим сжатия zstd.
```sh
student$ pg_basebackup \
  --checkpoint=fast \
  --wal-method=fetch \
  --target=server:/var/lib/postgresql/alpha.backup \
  --compress=server-zstd:level=12
```
Получили сжатую архивную копию в формате tar (он подразумевается).
```sh
postgres$ ls -lh /var/lib/postgresql/alpha.backup
```
```text
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 в общем архиве:
```sh
postgres$ tar tf /var/lib/postgresql/alpha.backup/base.tar.zst pg_wal
```
```text
pg_wal/
pg_wal/000000010000000000000007
pg_wal/archive_status/000000010000000000000007.done
```
Удалим архивную копию.
```sh
postgres$ rm -rf /var/lib/postgresql/alpha.backup
```

## Page 18: Низкоуровневый взгляд {#source-page-018}

![Source slide page 18: Низкоуровневый взгляд](images/page-018.png){#source-figure-018 caption="Source slide page 18: Низкоуровневый взгляд"}

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

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

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

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

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

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

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

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

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

## Page 19: API резервирования {#source-page-019}

**Начало копирования: 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: Итоги {#source-page-020}

**Базовая резервная копия — полная копия кластера, включая табличные пространства, плюс журнал для восстановления согласованности**
- Горячее резервирование позволяет не останавливать сервер
- Инструменты
  - протокол репликации
  - слот репликации
  - низкоуровневый API резервирования

## Page 21: Практика {#source-page-021}

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

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

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

## Page 22: 1. Табличное пространство и база данных {#source-page-022}

```sh
student$ sudo mkdir /var/lib/postgresql/ts_dir
```
```sh
student$ sudo chown postgres /var/lib/postgresql/ts_dir
```
Табличные пространства может создавать только суперпользователь:
```sql
α=> \c - postgres
```
```text
You are now connected to database "student" as user "postgres".
```
```sql
α=> CREATE TABLESPACE ts OWNER student LOCATION '/var/lib/postgresql/ts_dir';
```
```sql
CREATE TABLESPACE
```
```sql
α=> \c - student
```
```text
You are now connected to database "student" as user "student".
```
```sql
α=> CREATE DATABASE backup_base;
```
```sql
CREATE DATABASE
```
```sql
α=> \c backup_base
```
```text
You are now connected to database "backup_base" as user "student".
```
```sql
α=> CREATE TABLE t(s text) TABLESPACE ts;
```
```sql
CREATE TABLE
```
```sql
α=> INSERT INTO t VALUES ('Привет, мир!');
```
```sql
INSERT 0 1
```
### 2. Базовая резервная копия
Запускаем pg\_basebackup от имени роли student, указывая формат tar со сжатием:
```sh
student$ pg_basebackup \
  --checkpoint=fast \
  --format=tar \
  --compress=client-gzip \
  --pgdata /home/student/tmp/backup
```
```sh
student$ ls -l /home/student/tmp/backup
```
```text
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. Восстановление из базовой резервной копии
```sh
student$ sudo pg_ctlcluster 16 beta stop
```
```text
Cluster is not running.
```
Очистим основной каталог данных кластера beta. Права на каталог должны быть лишь у владельца.
```sh
student$ sudo rm -rf /var/lib/postgresql/16/beta
```
```sh
student$ sudo mkdir /var/lib/postgresql/16/beta
```
```sh
student$ sudo chown postgres /var/lib/postgresql/16/beta
```
```sh
student$ sudo chmod 700 /var/lib/postgresql/16/beta
```
Каталог для табличного пространства ts на сервере, который будет развернут из резервной копии:
```sh
student$ sudo mkdir /var/lib/postgresql/ts_beta_dir
```
```sh
student$ sudo chown postgres /var/lib/postgresql/ts_beta_dir
```
Разворачиваем резервную копию:
```sh
student$ sudo tar xf /home/student/tmp/backup/base.tar.gz -C /var/lib/postgresql/16/beta
```

## Page 23: Page 23 {#source-page-023}

```sh
student$ sudo tar xf /home/student/tmp/backup/16409.tar.gz -C /var/lib/postgresql/ts_beta_dir
```
```sh
student$ sudo tar xf /home/student/tmp/backup/pg_wal.tar.gz -C /var/lib/postgresql/16/beta/pg_wal
```
В каталоге pg\_tblspc сейчас пусто:
```sh
student$ sudo ls /var/lib/postgresql/16/beta/pg_tblspc/
```
Символическая ссылка появится при старте сервера в соответствии с файлом tablespace\_map (который находился внутри base.tar):
```sh
student$ sudo cat /var/lib/postgresql/16/beta/tablespace_map
```
```text
16409 /var/lib/postgresql/ts_dir
```
Изменяем в этом файле путь для табличного пространства:
```sh
student$ sudo sed -i 's/ts_dir/ts_beta_dir/' /var/lib/postgresql/16/beta/tablespace_map
```
### 4. Запуск и проверка
Запускаем сервер.
```sh
student$ sudo pg_ctlcluster 16 beta start
```
```sh
student$ sudo ls -l /var/lib/postgresql/16/beta/pg_tblspc/
```
```text
total 0
lrwxrwxrwx 1 postgres root 31 апр 10 18:13 16409 -> /var/lib/postgresql/ts_beta_dir
```
```sh
student$ psql -p 5433 -d backup_base
```
```sql
β=> \c backup_base
```
```text
You are now connected to database "backup_base" as user "student".
```
```sql
β=> SELECT * FROM t;
```
```text
      s
--------------
 Привет, мир!
(1 row)
```
### Уборка
Удалим резервную копию.
```sh
student$ rm -rf /home/student/tmp/backup
```
Чтобы удалить базу данных, надо от нее отключиться.
```sql
α=> \c student
```
```text
You are now connected to database "student" as user "student".
```
```sql
α=> DROP DATABASE backup_base;
```
```sql
DROP DATABASE
```
```sql
α=> DROP TABLESPACE ts;
```
```sql
DROP TABLESPACE
```
```sh
student$ sudo rm -rf /var/lib/postgresql/ts_dir
```
И для второго сервера:
```sql
β=> \c student
```
```text
You are now connected to database "student" as user "student".
```
```sql
β=> DROP DATABASE backup_base;
```
```sql
DROP DATABASE
```
```sql
β=> DROP TABLESPACE ts;
```
```sql
DROP TABLESPACE
```
```sh
student$ sudo rm -rf /var/lib/postgresql/ts_beta_dir
```

## Page 24: Практика+ {#source-page-024}

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>

2. Чтобы задействовать модуль при резервном копировании, укажите pg\_basebackup --target=shell

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

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

## Page 25: 1. Подключение модуля {#source-page-025}

Запишем настройки для подключения и конфигурации модуля basebackup\_to\_shell в подключаемый файл конфигурации.
```sh
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
```
Перезапустим сервер.
```sh
student$ sudo pg_ctlcluster 16 alpha restart
```
Проверим установки.
```sh
student$ psql
```
```text
α=> SHOW shared_preload_libraries;
```
```text
 shared_preload_libraries
--------------------------
 basebackup_to_shell
(1 row)
```
```text
α=> SHOW basebackup_to_shell.command;
```
```text
             basebackup_to_shell.command
------------------------------------------------------
 bzip2 -c > /var/lib/postgresql/archive.backup/%f.bz2
(1 row)
```
Создадим базу данных и таблицу в ней.
```sql
α=> CREATE DATABASE backup_base;
```
```sql
CREATE DATABASE
```
```sql
α=> \c backup_base
```
```text
You are now connected to database "backup_base" as user "student".
```
```sql
α=> CREATE TABLE t AS SELECT now() AS creatime;
```
```sql
SELECT 1
```
### 2. Резервное копирование
Создадим каталог для резервной копии.
```sh
postgres$ mkdir /var/lib/postgresql/archive.backup
```
Выполним резервное копирование. Использование потокового режима невозможно, поэтому воспользуемся режимом доставки WAL fetch.
```sh
student$ pg_basebackup \
  --checkpoint=fast \
  --wal-method=fetch \
  --target=shell
```
```sh
postgres$ ls -l /var/lib/postgresql/archive.backup
```
```text
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.
```sh
student$ sudo pg_ctlcluster 16 beta stop
```
```text
Cluster is not running.
```
```sh
postgres$ rm -rf /var/lib/postgresql/16/beta
```

## Page 26: Page 26 {#source-page-026}

![Source slide page 26: Page 26](images/page-026.png){#source-figure-026 caption="Source slide page 26: Page 26"}

```sh
postgres$ mkdir /var/lib/postgresql/16/beta
```
```sh
postgres$ chmod 700 /var/lib/postgresql/16/beta
```
Извлечем файлы из архива.
```sh
postgres$ tar xjf /var/lib/postgresql/archive.backup/base.tar.bz2 -C /var/lib/postgresql/16/beta
```
Проверим, восстановлены ли данные.
```sh
student$ sudo pg_ctlcluster 16 beta start
```
```sh
student$ psql -p 5433 -d backup_base
```
```sql
β=> SELECT * FROM t;
```
```text
           creatime
-------------------------------
 2026-04-10 18:13:49.437998+03
(1 row)
```
### Уборка
```sql
α=> \c student
```
```text
You are now connected to database "student" as user "student".
```
```sql
α=> DROP DATABASE backup_base;
```
```sql
DROP DATABASE
```
```sql
β=> \c student
```
```text
You are now connected to database "student" as user "student".
```
```sql
β=> DROP DATABASE backup_base;
```
```sql
DROP DATABASE
```
```sh
student$ sudo pg_ctlcluster 16 beta stop
```
```sh
postgres$ rm -rf /var/lib/postgresql/archive.backup
```
