# Занятие 14: Резервное копирование / Обзор

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

---

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

---

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

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

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

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

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

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

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

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

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

- Логическое резервное копирование
- Физическое резервное копирование

## Page 3: Логическое копирование {#source-page-003}

**Что такое логическое резервное копирование**
- Копия таблицы
- Копия базы данных
- Копия кластера

## Page 4: Логическая копия {#source-page-004}

**Команды SQL для восстановления данных с нуля**
  - + можно сделать копию отдельного объекта или базы
  - + можно восстановиться на кластере другой основной версии
  - + можно восстановиться на другой архитектуре
  - − невысокая скорость
  - восстановление только на момент копирования

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

Существует два вида резервирования: логическое и физическое.

Логическая резервная копия — это набор команд SQL, восстанавливающий кластер (или базу данных, или отдельный объект) с нуля.

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

Кроме того, команды SQL можно выполнить на другой версии СУБД или на другой архитектуре. Для этого требуется только совместимость на уровне команд; двоичная совместимость не нужна.

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

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

## Page 5: COPY: копия таблицы {#source-page-005}

**Резервное копирование**
  - вывод содержимого таблицы или результатов запроса в файл, в поток
  - или в программу
- Восстановление
  - добавление строк из файла или из потока ввода к существующей
  - таблице
- Серверный вариант Клиентский вариант
  - команда SQL COPY
  - команда psql \\copy
  - файл должен быть доступен
  - файл должен быть доступен
  - пользователю postgres
  - запустившему psql
  - на сервере
  - на клиенте

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

Если требуется сохранить только содержимое одной таблицы, можно воспользоваться командой COPY.

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

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

Команда COPY работает существенно быстрее, чем аналогичные команды INSERT — клиенту не нужно много раз обращаться к серверу, а серверу не нужно много раз анализировать команды.

<https://postgrespro.ru/docs/postgresql/16/sql-copy>

В psql существует клиентский вариант команды COPY с аналогичным синтаксисом. В отличие от серверного варианта COPY, который является командой SQL, клиентский вариант — это команда psql.

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

<https://postgrespro.ru/docs/postgresql/16/app-psql>

## Page 6: COPY {#source-page-006}

Создадим базу данных и таблицу в ней.
```sql
=> CREATE DATABASE backup_overview;
```
```sql
CREATE DATABASE
```
```sql
=> \c backup_overview
```
```text
You are now connected to database "backup_overview" as user "student".
```
```sql
=> CREATE TABLE t(id numeric, s text);
```
```sql
CREATE TABLE
```
```sql
=> INSERT INTO t VALUES (1, 'Привет!'), (2, ''), (3, NULL);
```
```sql
INSERT 0 3
```
```sql
=> SELECT * FROM t;
```
```text
 id |    s
----+---------
  1 | Привет!
  2 |
  3 |
(3 rows)
```
Вот как выглядит таблица в выводе команды COPY:
```text
=> COPY t TO STDOUT;
```
```text
1
Привет!
2
3
\N
```
Обратите внимание на то, что пустая строка и NULL — разные значения, хотя, выполняя запрос, этого и не заметно.
Аналогично можно вводить данные:
```text
=> TRUNCATE TABLE t;
```
```text
TRUNCATE TABLE
```
```sql
=> COPY t FROM STDIN;
1
Hi there!
2
3
\N
\.
```
```text
COPY 3
```
Проверим:
```text
=> \pset null '<null>'
```
```text
Null display is "<null>".
```
```sql
=> SELECT * FROM t;
```
```text
 id |     s
----+-----------
  1 | Hi there!
  2 |
  3 | <null>
(3 rows)
```

## Page 7: pg_dump: копия базы {#source-page-007}

**Резервное копирование**
  - выводит в поток или в файл SQL-скрипт,
  - либо архив в специальном формате с оглавлением
  - поддерживает параллельное выполнение
  - позволяет ограничить набор выгружаемых объектов
  - (таблицы, схемы, только DML или только DDL и т. п.)
- Восстановление
  - SQL-скрипт — psql
  - формат с оглавлением — pg\_restore
  - (позволяет ограничить набор объектов при восстановлении
  - и поддерживает параллельное выполнение)
  - новая база должна быть создана из шаблона template0
  - заранее должны быть созданы роли и табличные пространства

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

Для создания полноценной резервной копии базы данных используется утилита pg\_dump. В зависимости от указанных параметров, результатом работы является либо SQL-скрипт, содержащий команды, создающие выбранные объекты, либо файл в специальном формате с оглавлением.

Чтобы восстановить объекты из SQL-скрипта, достаточно выполнить его в psql.

<https://postgrespro.ru/docs/postgresql/16/app-pgdump>

Для восстановления из резервной копии в специальном формате требуется другая утилита — pg\_restore. Она читает файл и преобразует его в обычные команды psql. Преимущество в том, что набор объектов можно ограничить не при создании резервной копии, а уже при восстановлении. Кроме того, создание резервной копии в специальном формате и восстановление из нее может выполняться параллельно.

<https://postgrespro.ru/docs/postgresql/16/app-pgrestore>

Базу данных для восстановления надо создавать из шаблона template0, так как все изменения, сделанные в template1, также попадут в резервную копию. Кроме того, заранее должны быть созданы необходимые роли и табличные пространства, поскольку эти объекты относятся ко всему кластеру. После восстановления базы имеет смысл выполнить команду ANALYZE, которая соберет статистику.

## Page 8: pg_dumpall: копия кластера {#source-page-008}

**Резервирование**
  - сохраняет весь кластер, включая роли и табличные пространства
  - выдает на консоль или в файл SQL-скрипт
  - параллельное выполнение не поддерживается, но можно выгрузить
  - только глобальные объекты и воспользоваться pg\_dump
- Восстановление
  - с помощью psql

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

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

Поскольку pg\_dumpall требуется доступ ко всем объектам всех БД, имеет смысл запускать ее от имени суперпользователя. Утилита по очереди подключается к каждой БД кластера и выгружает информацию с помощью pg\_dump. Кроме того, она сохраняет и данные, относящиеся к кластеру в целом.

Результатом работы pg\_dumpall является скрипт для psql. Другие форматы не поддерживаются. Это означает, что pg\_dumpall не поддерживает параллельную выгрузку данных, что может оказаться проблемой при больших объемах данных. В таком случае можно воспользоваться ключом --globals-only, чтобы выгрузить только роли и табличные пространства, а сами базы данных выгрузить с помощью утилиты pg\_dump.

<https://postgrespro.ru/docs/postgresql/16/app-pg-dumpall>

## Page 9: Утилита pg_dump {#source-page-009}

Посмотрим на результат работы утилиты pg\_dump в простом формате (plain). Обратите внимание на то, в каком виде сохранены данные из таблицы.
Если в шаблон template1 вносились какие-либо изменения, они также попадут в резервную копию. Поэтому при восстановлении базы данных имеет смысл предварительно создать ее из шаблона template0 (указанный ключ --create добавляет нужные команды автоматически).
```sh
student$ pg_dump -d backup_overview --create
```
```text
--
-- PostgreSQL database dump
--
```
```text
\restrict wPK5P49kGYb4h6NSsdYtzdxEIF9AmoXjciCHI1S7SgzMVyh5Yq1EmJAYld7c243
```
```sql
-- Dumped from database version 16.11 (Ubuntu 16.11-1.pgdg24.04+1)
-- Dumped by pg_dump version 16.11 (Ubuntu 16.11-1.pgdg24.04+1)
```
```sql
SET statement_timeout = 0;
SET lock_timeout = 0;
SET idle_in_transaction_session_timeout = 0;
SET client_encoding = 'UTF8';
SET standard_conforming_strings = on;
SELECT pg_catalog.set_config('search_path', '', false);
SET check_function_bodies = false;
SET xmloption = content;
SET client_min_messages = warning;
SET row_security = off;
```
```text
--
-- Name: backup_overview; Type: DATABASE; Schema: -; Owner: student
--
```
```sql
CREATE DATABASE backup_overview WITH TEMPLATE = template0 ENCODING = 'UTF8'
LOCALE_PROVIDER = libc LOCALE = 'en_US.UTF-8';
```
```sql
ALTER DATABASE backup_overview OWNER TO student;
```
```sql
\unrestrict wPK5P49kGYb4h6NSsdYtzdxEIF9AmoXjciCHI1S7SgzMVyh5Yq1EmJAYld7c243
\connect backup_overview
\restrict wPK5P49kGYb4h6NSsdYtzdxEIF9AmoXjciCHI1S7SgzMVyh5Yq1EmJAYld7c243
```
```sql
SET statement_timeout = 0;
SET lock_timeout = 0;
SET idle_in_transaction_session_timeout = 0;
SET client_encoding = 'UTF8';
SET standard_conforming_strings = on;
SELECT pg_catalog.set_config('search_path', '', false);
SET check_function_bodies = false;
SET xmloption = content;
SET client_min_messages = warning;
SET row_security = off;
```
```text
SET default_tablespace = '';
```
```text
SET default_table_access_method = heap;
```
```text
--
-- Name: t; Type: TABLE; Schema: public; Owner: student
--
```
```sql
CREATE TABLE public.t (
    id numeric,
    s text
);
```
```sql
ALTER TABLE public.t OWNER TO student;
```
```text
--
-- Data for Name: t; Type: TABLE DATA; Schema: public; Owner: student
--
```

## Page 10: Page 10 {#source-page-010}

```sql
COPY public.t (id, s) FROM stdin;
1
Hi there!
2
3
\N
\.
```
```text
--
-- PostgreSQL database dump complete
--
```
```text
\unrestrict wPK5P49kGYb4h6NSsdYtzdxEIF9AmoXjciCHI1S7SgzMVyh5Yq1EmJAYld7c243
```
При выполнении скриптов psql трактует символ \\ как начало метакоманды. Чтобы обратная косая черта в данных не привела (случайно или преднамеренно) к нежелательным последствиям, строка \\restrict в резервной копии включает безопасный режим, который запрещает выполнение любых метакоманд psql.
В качестве примера использования скопируем таблицу в другую базу.
```sql
=> CREATE DATABASE backup_overview2;
```
```sql
CREATE DATABASE
```
```sh
student$ pg_dump -d backup_overview --table=t | psql -d backup_overview2
```
```text
SET
SET
SET
SET
SET
 set_config
------------
(1 row)
```
```sql
SET
SET
SET
SET
SET
SET
CREATE TABLE
ALTER TABLE
COPY 3
```
```sh
student$ psql -d backup_overview2
```
```sql
=> SELECT * FROM t;
```
```text
 id |     s
----+-----------
  1 | Hi there!
  2 |
  3 |
(3 rows)
```

## Page 11: Физическое копирование {#source-page-011}

**Что такое физическое резервное копирование**
- Холодное и горячее резервное копирование
- Протокол репликации
- Автономные резервные копии
- Непрерывная архивация журналов предзаписи

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

**Используется механизм восстановления после сбоя: копия данных и журналы предзаписи**
  - + скорость восстановления
  - + можно восстановить кластер на определенный момент времени
  - − нельзя восстановить отдельную базу данных, только весь кластер
  - − восстановление только на той же основной версии и архитектуре

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

Физическое резервирование использует механизм восстановления после сбоев. Для этого требуются:

● базовая резервная копия — копия файлов кластера (файлов данных и служебных файлов);

● набор журналов предзаписи, необходимых для восстановления согласованности.

Если файловая система уже согласована (копия снималась при корректно остановленном сервере), то журналы не требуются.

Однако наличие архива журналов позволяет получить из базовой резервной копии состояние кластера на любой момент времени. Таким образом можно восстановить резервную копию практически на момент сбоя (либо сознательно восстановить систему на некоторый момент в прошлом).

Высокая скорость восстановления и возможность создавать копию «на лету», не выключая сервер, делает физическое резервирование основным инструментом периодического резервного копирования.

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

<https://postgrespro.ru/docs/postgresql/16/continuous-archiving>

## Page 13: Горячо или холодно? {#source-page-013}

  - Холодное резервирование
  - Горячее
  - резервирование
  - выключенном
  - неаккуратно
  - выключенном
  - работающем
- Файлы кластера копируются при...
  - сервере
  - сервере
  - сервере
  - нужны
  - специальные
  - средства
  - не нужны
  - нужны с последней
  - нужны за время
- Журналы предварительной записи...
  - контрольной точки
  - копирования
  - находятся
  - в файловой
  - сервер
  - не должен удалить WAL
  - системе
  - раньше времени

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

Физическое резервирование так или иначе предполагает создание копии файлов кластера баз данных.

Если копия создается при выключенном сервере, она называется «холодной». Такая копия либо содержит согласованные данные (если сервер был выключен аккуратно), либо содержит все необходимые для восстановления журналы (например, если используется снимок данных средствами операционной системы). Это упрощает восстановление, но требует останова сервера.

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

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

## Page 14: Автономная копия {#source-page-014}

**Базовая копия + WAL**
- Резервное копирование — pg\_basebackup
  - подключается к серверу по протоколу репликации
  - выполняет контрольную точку
  - копирует файлы кластера баз данных в указанный каталог
  - сохраняет все сегменты WAL, сгенерированные за время копирования
- Восстановление
  - разворачиваем созданную автономную копию
  - запускаем сервер

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

Для создания горячей резервной копии используется утилита pg\_basebackup.

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

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

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

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

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

**Протокол**
  - получение потока журнальных записей
  - команды управления резервным копированием и репликацией
- Обслуживается процессом wal\_sender
- Параметр wal\_level = replica
- Слот репликации
  - серверный объект для получения журнальных записей
  - помнит, какая запись была считана последней
  - сегмент WAL не удаляется, пока он полностью не прочитан через слот

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

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

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

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

Во-первых, роль должна обладать атрибутом REPLICATION (или быть суперпользователем) и иметь разрешение на подключение по протоколу репликации в конфигурационном файле pg\_hba.conf.

Во-вторых, параметр max\_wal\_senders должен быть установлен в достаточно большое значение. Этот параметр ограничивает число одновременно работающих процессов wal\_sender, обслуживающих подключения по протоколу репликации.

В-третьих, параметр wal\_level, определяющий количество информации в журнале, должен быть установлен в значение replica.

Настройки по умолчанию включают все эти требования (при локальном подключении).

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

## Page 16: Автономная копия {#source-page-016}

![Source slide page 16: Автономная копия](images/page-016.png){#source-figure-016 caption="Source slide page 16: Автономная копия"}


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

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

Внизу рисунка (а в реальной жизни — обычно на другом сервере) изображена созданная резервная копия — базовая копия данных и набор файлов WAL.

## Page 17: Автономная резервная копия {#source-page-017}

Значения параметров по умолчанию позволяют использовать протокол репликации:
```sql
=> SELECT name, setting
FROM pg_settings
WHERE name IN ('wal_level','max_wal_senders');
```
```text
      name       | setting
-----------------+---------
 max_wal_senders | 10
 wal_level       | replica
(2 rows)
```
Разрешение на локальное подключение по протоколу репликации в pg\_hba.conf также прописано по умолчанию (хотя это и зависит от конкретной пакетной сборки):
```sql
=> SELECT type, database, user_name, address, auth_method
FROM pg_hba_file_rules()
WHERE 'replication' = ANY(database);
```
```text
 type  |   database    | user_name |  address  |  auth_method
-------+---------------+-----------+-----------+---------------
 local | {replication} | {all}     | <null>    | trust
 host  | {replication} | {all}     | 127.0.0.1 | scram-sha-256
 host  | {replication} | {all}     | ::1       | scram-sha-256
(3 rows)
```
Еще один кластер баз данных replica был предварительно инициализирован на порту 5433. Убедимся, что кластер остановлен, с помощью утилиты пакета для Ubuntu:
```sh
student$ pg_lsclusters
```
```text
Ver Cluster Port Status Owner    Data directory                 Log file
16  main    5432 online postgres /var/lib/postgresql/16/main
/var/log/postgresql/postgresql-16-main.log
16  replica 5433 down   postgres /var/lib/postgresql/16/replica
/var/log/postgresql/postgresql-16-replica.log
```
Создадим резервную копию. Используем формат по умолчанию (plain):
```sh
student$ rm -rf /home/student/tmp/basebackup
```
```sh
student$ pg_basebackup --pgdata=/home/student/tmp/basebackup --checkpoint=fast
```
Утилита pg\_basebackup сразу после подключения к серверу выполняет контрольную точку. По умолчанию грязные буферы записываются постепенно, чтобы не создавать пиковую нагрузку (запись длится до 4,5 минут). Если указать -- checkpoint=fast, буферы записываются без пауз.

## Page 18: Восстановление {#source-page-018}

![Source slide page 18: Восстановление](images/page-018.png){#source-figure-018 caption="Source slide page 18: Восстановление"}


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

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

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

## Page 19: Восстановление {#source-page-019}

Заменим каталог кластера replica созданной копией, предварительно убедившись, что кластер остановлен:
```sh
student$ sudo pg_ctlcluster 16 replica status
```
```text
pg_ctl: no server running
```
```sh
student$ sudo rm -rf /var/lib/postgresql/16/replica
```
```sh
student$ sudo mv /home/student/tmp/basebackup/ /var/lib/postgresql/16/replica
```
Файлы кластера должны принадлежать пользователю postgres.
```sh
student$ sudo chown -R postgres:postgres /var/lib/postgresql/16/replica
```
Проверим содержимое каталога:
```sh
student$ sudo ls -l /var/lib/postgresql/16/replica
```
```text
total 344
-rw------- 1 postgres postgres    225 апр 10 17:06 backup_label
-rw------- 1 postgres postgres 268206 апр 10 17:06 backup_manifest
drwx------ 8 postgres postgres   4096 апр 10 17:06 base
drwx------ 2 postgres postgres   4096 апр 10 17:06 global
drwx------ 2 postgres postgres   4096 апр 10 17:06 pg_commit_ts
drwx------ 2 postgres postgres   4096 апр 10 17:06 pg_dynshmem
drwx------ 4 postgres postgres   4096 апр 10 17:06 pg_logical
drwx------ 4 postgres postgres   4096 апр 10 17:06 pg_multixact
drwx------ 2 postgres postgres   4096 апр 10 17:06 pg_notify
drwx------ 2 postgres postgres   4096 апр 10 17:06 pg_replslot
drwx------ 2 postgres postgres   4096 апр 10 17:06 pg_serial
drwx------ 2 postgres postgres   4096 апр 10 17:06 pg_snapshots
drwx------ 2 postgres postgres   4096 апр 10 17:06 pg_stat
drwx------ 2 postgres postgres   4096 апр 10 17:06 pg_stat_tmp
drwx------ 2 postgres postgres   4096 апр 10 17:06 pg_subtrans
drwx------ 2 postgres postgres   4096 апр 10 17:06 pg_tblspc
drwx------ 2 postgres postgres   4096 апр 10 17:06 pg_twophase
-rw------- 1 postgres postgres      3 апр 10 17:06 PG_VERSION
drwx------ 3 postgres postgres   4096 апр 10 17:06 pg_wal
drwx------ 2 postgres postgres   4096 апр 10 17:06 pg_xact
-rw------- 1 postgres postgres     88 апр 10 17:06 postgresql.auto.conf
```
В процессе запуска произойдет восстановление из резервной копии.
```sh
student$ sudo pg_ctlcluster 16 replica start
```
Теперь оба сервера работают одновременно и независимо.
Основной сервер:
```sql
=> INSERT INTO t VALUES (4, 'Основной сервер');
```
```sql
INSERT 0 1
```
```sql
=> SELECT * FROM t;
```
```text
 id |        s
----+-----------------
  1 | Hi there!
  2 |
  3 | <null>
  4 | Основной сервер
(4 rows)
```
Сервер, восстановленный из резервной копии:
```sh
student$ psql -p 5433 -d backup_overview
```
```sql
=> INSERT INTO t VALUES (4, 'Резервная копия');
```
```sql
INSERT 0 1
```
```sql
=> SELECT * FROM t;
```

## Page 20: Page 20 {#source-page-020}

```text
 id |        s
----+-----------------
  1 | Hi there!
  2 |
  3 |
  4 | Резервная копия
(4 rows)
```

## Page 21: Архив журналов {#source-page-021}

**Файловый архив**
  - сегменты WAL копируются в архив по мере переключения
  - механизм работает под управлением сервера
  - неизбежны задержки попадания данных в архив
- Потоковый архив
  - в архив постоянно записывается поток журнальных записей
  - требуются внешние средства
  - задержки минимальны

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

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

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

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

## Page 22: Файловый архив журналов {#source-page-022}

**Процесс archiver Параметры**
- archive\_mode = on archive\_command команда shell для копирования сегмента WAL в отдельное хранилище Алгоритм
  - при переключении сегмента WAL вызывается команда archive\_command
  - если команда завершается со статусом 0, сегмент удаляется
  - если команда возвращает не 0 (или если команда не задана), сегмент
  - остается до тех пор, пока попытка не будет успешной

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

Файловый архив реализуется фоновым процессом archiver.

PostgreSQL позволяет определить для копирования произвольную команду shell в параметре archive\_command. Сам механизм включается параметром archive\_mode = on.

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

<https://postgrespro.ru/docs/postgresql/16/continuous-archiving>

## Page 23: Файловый архив журналов {#source-page-023}

![Source slide page 23: Файловый архив журналов](images/page-023.png){#source-figure-023 caption="Source slide page 23: Файловый архив журналов"}


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

На этом рисунке изображен основной сервер с настроенным непрерывным архивированием: заполненные сегменты WAL копируются в отдельный архив с помощью команды в параметре archive\_command. Обычно такой архив расположен на другом сервере.

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

## Page 24: Потоковый архив журналов {#source-page-024}

**Утилита pg\\\_receivewal**
  - подключается по протоколу репликации (можно использовать слот)
  - и направляет поток записей WAL в файлы-сегменты
  - стартовая позиция — начало сегмента, следующего за последним
  - заполненным сегментом в каталоге,
  - или начало текущего сегмента сервера, если каталог пустой
  - в отличие от файлового архива, записи пишутся постоянно
  - при переходе на новый сервер надо перенастраивать параметры

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

Другое решение — использовать утилиту pg\_receivewal, которая получает записи WAL по протоколу репликации и записывает сегменты в архив.

Обычно утилита запускается на отдельном «архивном» сервере и подключается к серверу с параметрами, указанными в ключах. Утилита может (и должна) использовать слот репликации, чтобы гарантированно не потерять записи.

Утилита формирует файлы аналогично тому, как это делает сервер, и записывает их в указанный каталог. Еще не заполненные сегменты записываются с суффиксом .partial.

При запуске утилита начинает архивирование с начала сегмента, следующего за последним заполненным сегментом архива. Если архив пуст (первый запуск), утилита запрашивает записи с начала текущего сегмента.

При переходе на новый сервер утилиту придется остановить и запустить заново с новыми параметрами.

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

<https://postgrespro.ru/docs/postgresql/16/app-pgreceivewal>

## Page 25: Потоковый архив журналов {#source-page-025}

![Source slide page 25: Потоковый архив журналов](images/page-025.png){#source-figure-025 caption="Source slide page 25: Потоковый архив журналов"}


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

Утилита pg\_receivewal подключается к серверу по протоколу репликации. Подключение обслуживается отдельным процессом wal sender (это необходимо учесть при установке параметра max\_wal\_senders).

Утилита записывает данные, не дожидаясь получения всего сегмента.

## Page 26: Базовая копия + архив {#source-page-026}

**Настроенное непрерывное архивирование журналов**
- Резервное копирование — pg\_basebackup
  - подключается к серверу по протоколу репликации
  - выполняет контрольную точку
  - копирует файлы кластера в указанный каталог
  - сегменты WAL
  - в копии не нужны
- Восстановление
  - разворачиваем резервную копию
  - задаем конфигурационные параметры
  - (команда чтения WAL из архива, целевая точка восстановления)
  - создаем сигнальный файл recovery.signal
  - запускаем сервер

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

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

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

● команду restore\_command (обратную archive\_command — она копирует нужные файлы из архива в каталог сервера);

● целевую точку восстановления.

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

## Page 27: Восстановление {#source-page-027}

![Source slide page 27: Восстановление](images/page-027.png){#source-figure-027 caption="Source slide page 27: Восстановление"}


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

Процедура восстановления (например, при выходе из строя основного сервера), выполняется следующим образом. На другом (или на том же) сервере разворачивается базовая резервная копия и создается файл recovery.signal. Сервер запускается, начинает копировать сегменты WAL из архива, используя restore\_command, и применять их.

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

## Page 28: Восстановление {#source-page-028}

![Source slide page 28: Восстановление](images/page-028.png){#source-figure-028 caption="Source slide page 28: Восстановление"}


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

Резервный сервер применяет все доступные записи WAL, читая сегменты из каталога pg\_wal (при отсутствии сегмента делается попытка скопировать его из архива), тем самым доводя состояние баз данных до актуального. Максимально возможная потеря — незаполненный сегмент WAL, не попавший в архив, если его по каким-то причинам невозможно скопировать.

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

## Page 29: Восстановление {#source-page-029}

![Source slide page 29: Восстановление](images/page-029.png){#source-figure-029 caption="Source slide page 29: Восстановление"}


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

После завершения восстановления резервный сервер переходит в обычный режим работы: принимает запросы, записывает сегменты WAL в архив и так далее, выступая в качестве нового полноценного основного сервера.

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

## Page 30: Итоги {#source-page-030}

**Логическая резервная копия — команды SQL для восстановления состояния объектов**
  - команда copy, утилиты pg\_dump и pg\_dumpall
- Физическая резервная копия — копия файлов кластера + набор файлов WAL
  - утилита pg\_basebackup
- Архив WAL
  - файловый или потоковый
  - позволяет восстановить систему на произвольный момент времени

## Page 31: Практика {#source-page-031}

1. Создайте базу данных и таблицу в ней с несколькими строками. 2. Сделайте логическую копию базы данных с помощью утилиты pg\_dump.
- Удалите базу данных и восстановите ее из сделанной копии. 3. Сделайте автономную физическую резервную копию кластера с помощью утилиты pg\_basebackup.
  - Измените таблицу.
  - Восстановите новый кластер из сделанной резервной копии
  - и проверьте, что база данных не содержит более поздних
  - изменений.

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

3. В виртуальной машине курса уже создан кластер replica на порту 5433. Используйте этот кластер, для того чтобы восстановить данные из резервной копии.

Каталог данных кластера – /var/lib/postgresql/16/replica.

Для подключения укажите номер порта: psql -p 5433

## Page 32: 1. База данных и таблица {#source-page-032}

```sql
=> CREATE DATABASE backup_overview;
```
```sql
CREATE DATABASE
```
```sql
=> \c backup_overview
```
```text
You are now connected to database "backup_overview" as user "student".
```
```sql
=> CREATE TABLE t(n integer);
```
```sql
CREATE TABLE
```
```sql
=> INSERT INTO t VALUES (1), (2), (3);
```
```sql
INSERT 0 3
```
### 2. Логическая резервная копия
Создаем резервную копию:
```sh
student$ pg_dump -f /home/student/tmp/backup_overview.dump -d backup_overview --create
```
Удаляем базу данных и восстанавливаем ее из копии:
```sql
=> \c postgres
```
```text
You are now connected to database "postgres" as user "student".
```
```sql
=> DROP DATABASE backup_overview;
```
```sql
DROP DATABASE
```
```sh
student$ psql -f /home/student/tmp/backup_overview.dump
```
```text
SET
SET
SET
SET
SET
 set_config
------------
(1 row)
```
```sql
SET
SET
SET
SET
CREATE DATABASE
ALTER DATABASE
You are now connected to database "backup_overview" as user "student".
SET
SET
SET
SET
SET
 set_config
------------
(1 row)
```
```sql
SET
SET
SET
SET
SET
SET
CREATE TABLE
ALTER TABLE
COPY 3
```
```sql
=> \c backup_overview
```
```text
You are now connected to database "backup_overview" as user "student".
```
```sql
=> SELECT * FROM t;
```

## Page 33: 3. Физическая автономная резервная копия {#source-page-033}

```text
 n
---
 1
 2
 3
(3 rows)
```
Создаем резервную копию, выполняя «быструю» контрольную точку:
```sh
student$ rm -rf /home/student/tmp/backup
```
```sh
student$ pg_basebackup --pgdata=/home/student/tmp/backup --checkpoint=fast
```
Убеждаемся, что второй сервер остановлен, и выкладываем резервную копию:
```sh
student$ sudo pg_ctlcluster 16 replica status
```
```text
pg_ctl: no server running
```
```sh
student$ sudo rm -rf /var/lib/postgresql/16/replica
```
```sh
student$ sudo mv /home/student/tmp/backup /var/lib/postgresql/16/replica
```
```sh
student$ sudo chown -R postgres:postgres /var/lib/postgresql/16/replica
```
Изменяем таблицу:
```sql
=> DELETE FROM t;
```
```sql
DELETE 3
```
Запускаем сервер из резервной копии:
```sh
student$ sudo pg_ctlcluster 16 replica start
```
```sh
student$ psql -p 5433 -d backup_overview
```
```sql
=> SELECT * FROM t;
```
```text
 n
---
 1
 2
 3
(3 rows)
```
### Уборка
```sql
=> \c student
```
```text
You are now connected to database "student" as user "student".
```
```sql
=> DROP DATABASE backup_overview;
```
```sql
DROP DATABASE
```
```sql
=> \q
```
```sql
=> \c student
```
```text
You are now connected to database "student" as user "student".
```
```sql
=> DROP DATABASE backup_overview;
```
```sql
DROP DATABASE
```
```sql
=> \q
```

## Page 34: Практика+ {#source-page-034}

1. Организуйте потоковую архивацию кластера main с помощью утилиты pg\_receivewal.
- 2. Сделайте автономную резервную копию кластера main (без WAL) с помощью утилиты pg\_basebackup. 3. В кластере main создайте базу данных и таблицу в ней. 4. Выполните восстановление кластера replica из базовой копии с использованием архива. Убедитесь, что база и таблица тоже восстановились.

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

Кластер replica находится в /var/lib/postgresql/16/replica.

Текущий файл, записываемый утилитой pg\_receivewal, имеет суффикс .partial, по окончании записи файл переименовывается. При восстановлении наряду с обычными сегментами нужно использовать и последний недозаписанный файл.

Для подключения к кластеру replica укажите номер порта: psql -p 5433.

## Page 35: 1. Потоковый архив {#source-page-035}

Обратите внимание, что часть команд выполняется от имени пользователя postgres, а часть — от имени student.
Создаем каталог для архива WAL:
```sh
postgres$ mkdir /var/lib/postgresql/archive
```
Создаем слот, чтобы в архиве не было пропусков:
```sh
postgres$ pg_receivewal --create-slot --slot=archive
```
Запускаем утилиту pg\_receivewal в фоновом режиме. Для этого следующую команду нужно выполнить в отдельном окне терминала или добавить в конце командной строки символ &.
```sh
postgres$ pg_receivewal -D /var/lib/postgresql/archive --slot=archive &
```
```sh
student$ sudo ls -l /var/lib/postgresql/archive
```
```text
total 16384
-rw------- 1 postgres postgres 16777216 апр 10 17:11 000000010000000000000001.partial
```
### 2. Базовая физическая копия без журнала
```sh
student$ pg_basebackup --wal-method=none --pgdata=/home/student/tmp/backup --checkpoint=fast
```
```text
NOTICE:  WAL archiving is not enabled; you must ensure that all required WAL segments are
copied through other means to complete the backup
```
```sh
student$ ls -l /home/student/tmp/backup
```
```text
total 260
-rw------- 1 student student    225 апр 10 17:11 backup_label
-rw------- 1 student student 180378 апр 10 17:11 backup_manifest
drwx------ 6 student student   4096 апр 10 17:11 base
drwx------ 2 student student   4096 апр 10 17:11 global
drwx------ 2 student student   4096 апр 10 17:11 pg_commit_ts
drwx------ 2 student student   4096 апр 10 17:11 pg_dynshmem
drwx------ 4 student student   4096 апр 10 17:11 pg_logical
drwx------ 4 student student   4096 апр 10 17:11 pg_multixact
drwx------ 2 student student   4096 апр 10 17:11 pg_notify
drwx------ 2 student student   4096 апр 10 17:11 pg_replslot
drwx------ 2 student student   4096 апр 10 17:11 pg_serial
drwx------ 2 student student   4096 апр 10 17:11 pg_snapshots
drwx------ 2 student student   4096 апр 10 17:11 pg_stat
drwx------ 2 student student   4096 апр 10 17:11 pg_stat_tmp
drwx------ 2 student student   4096 апр 10 17:11 pg_subtrans
drwx------ 2 student student   4096 апр 10 17:11 pg_tblspc
drwx------ 2 student student   4096 апр 10 17:11 pg_twophase
-rw------- 1 student student      3 апр 10 17:11 PG_VERSION
drwx------ 3 student student   4096 апр 10 17:11 pg_wal
drwx------ 2 student student   4096 апр 10 17:11 pg_xact
-rw------- 1 student student     88 апр 10 17:11 postgresql.auto.conf
```
### 3. Новые база данных и таблица
```sql
=> CREATE DATABASE backup_overview;
```
```sql
CREATE DATABASE
```
```sql
=> \c backup_overview
```
```text
You are now connected to database "backup_overview" as user "student".
```
```sql
=> CREATE TABLE t(n integer);
```
```sql
CREATE TABLE
```
```sql
=> INSERT INTO t VALUES (1), (2), (3);
```
```sql
INSERT 0 3
```
### 4. Настройка восстановления
Убеждаемся, что второй сервер остановлен, и выкладываем резервную копию:
```sh
student$ sudo pg_ctlcluster 16 replica status
```

## Page 36: Page 36 {#source-page-036}

```text
pg_ctl: no server running
```
```sh
student$ sudo rm -rf /var/lib/postgresql/16/replica
```
```sh
student$ sudo mv /home/student/tmp/backup /var/lib/postgresql/16/replica
```
При восстановлении также используем частично записанный сегмент:
```sh
student$ echo "restore_command = 'cp /var/lib/postgresql/archive/%f %p || cp
/var/lib/postgresql/archive/%f.partial %p'" | sudo tee
/var/lib/postgresql/16/replica/postgresql.auto.conf
```
```text
restore_command = 'cp /var/lib/postgresql/archive/%f %p || cp
/var/lib/postgresql/archive/%f.partial %p'
```
```sh
student$ touch /var/lib/postgresql/16/replica/recovery.signal
```
```sh
student$ sudo chown -R postgres:postgres /var/lib/postgresql/16/replica
```
Запустим сервер и проверим результат:
```sh
student$ sudo pg_ctlcluster 16 replica start
```
```sh
student$ psql -p 5433 -d backup_overview
```
```sql
=> SELECT * FROM t;
```
```text
 n
---
 1
 2
 3
(3 rows)
```
### Уборка
Архивация больше не нужна. Остановим утилиту и удалим слот, чтобы он не мешал очистке WAL.
```sh
student$ sudo pkill pg_receivewal
```
```sh
postgres$ pg_receivewal --drop-slot --slot=archive
```
```sql
=> \q
```
```sh
student$ sudo pg_ctlcluster 16 replica stop
```
```sql
=> \c student
```
```text
You are now connected to database "student" as user "student".
```
```sql
=> DROP DATABASE backup_overview;
```
```sql
DROP DATABASE
```
```sql
=> \q
```
```sh
postgres$ rm -rf /var/lib/postgresql/archive
```
```sh
student$ rm -rf /home/student/tmp/backup
```
