Настройка и восстановление PostgreSQL с WAL: подробное руководство
Введение в WAL
В самом начале стоит понять, что такое Write-Ahead Logging (WAL), и почему он так важен для PostgreSQL. Когда мы говорим о целостности базы данных, мы подразумеваем, что при различных сбоях – будь то отключение электричества, сбой в работе диска или сбой в сети – данные остаются максимально доступными и непротиворечивыми. Для обеспечения такой надёжности PostgreSQL использует механизм WAL.
Что такое Write-Ahead Logging (WAL)
WAL (Write-Ahead Logging) — это журнал, в котором фиксируются все изменения данных перед тем, как они окончательно применяются к самим файлам базы. То есть, прежде чем обновление или вставка «попадут» на диск, PostgreSQL записывает «описание» этого изменения в лог-файл WAL. Это можно сравнить с черновиком или заметками, которые мы делаем перед тем, как внести исправления в финальный документ.
Зачем это нужно?
- Целостность данных. При сбое система может «дочитать» лог, понять, какие данные были изменены, и восстановить их до корректного состояния.
- Непрерывность работы. Благодаря тому, что сам WAL-файл достаточно быстр в записи (он по сути представляет собой последовательный журнал), основная часть нагрузки при записи не ложится на конечные файлы базы, и работа с данными продолжается эффективнее.
Основные виды бэкапов
При администрировании PostgreSQL обычно используют два основных способа резервного копирования (бэкапа):
- Логические дампы (Logical backups):
- Выполняются с помощью утилиты
pg_dump
илиpg_dumpall
. - Сохраняют структуру БД (DDL) и данные (DML) в виде SQL-скриптов или пользовательских двоичных форматов.
- Удобны тем, что позволяют переносить схему и данные на другие версии PostgreSQL, легко восстанавливать отдельные таблицы или схему.
- Основной минус – при большом объёме данных создание дампа может занимать значительное время и потреблять много ресурсов.
- Выполняются с помощью утилиты
- Физические копии (Physical backups):
- Представляют собой копирование файловой структуры самой базы данных (каталог
data
, где хранятся все файлы PostgreSQL, включая WAL-логи). - Чаще всего выполняются с помощью утилит вроде
pg_basebackup
, а в случае резервного копирования через Docker – с помощью настроенных волумов и инструментов архивации. - Физический бэкап точнее передаёт состояние БД, чем логический дамп, но и объём данных может быть намного больше. Кроме того, физическую копию сложнее переносить на иную версию PostgreSQL (например, с 12 на 14), поэтому следует внимательно учитывать совместимость версий.
- Представляют собой копирование файловой структуры самой базы данных (каталог
Оба способа имеют право на жизнь и обычно применяются в зависимости от ситуации. Однако в большинстве случаев рекомендуют сочетать дампы и физические бэкапы.
Зачем сочетать регулярные дампы с WAL
WAL – это «чёрный ящик» или «журнал изменений», который позволяет откатить или доиграть операции, совершённые между резервными копиями. Представим классическую ситуацию: мы делаем бэкап (дамп) раз в день. Но в промежутке между созданием дампа и моментом сбоя в базу вносились изменения (новые заказы, транзакции, записи и т.д.). В итоге, если восстанавливаться только из дампа, мы потеряем все изменения за сутки.
Как тут помогает WAL?
- Пока база работает, PostgreSQL непрерывно записывает все изменения в WAL-файлы.
- Если включена архивация WAL (о ней поговорим в следующих главах), эти файлы сохраняются в отдельном, безопасном месте (например, на удалённом сервере или в облаке).
- После сбоя мы можем сначала развернуть базу из свежего дампа, а потом «доиграть» (replay) WAL-журналы за период после создания этого дампа. Это вернёт базу в состояние вплоть до момента сбоя.
Таким образом, комбинация регулярных дампов (логических или физических) и архивации WAL позволяет добиться:
- Быстрого восстановления «большинства» данных за счёт дампа.
- Восполнения пропущенных изменений за счёт «доигрывания» WAL.
На практике эта схема даёт оптимальный баланс между затратами на хранение бэкапов и гарантированным сохранением данных. Если вдруг ломается хранилище, где крутится PostgreSQL, мы восстанавливаемся из самой свежей копии (дамп или физический бэкап), а затем применяем WAL, которые накопились между моментом создания копии и сбоем.
Подготовка окружения
Во второй главе разберёмся, как настроить Docker Compose для работы с PostgreSQL и подготовить базовую конфигурацию, необходимую для дальнейшей настройки WAL. Особое внимание уделим правильной структуре каталогов (volumes), чтобы в дальнейшем без проблем сохранять файлы WAL и резервные копии.
Создание и настройка docker-compose.yml
с PostgreSQL
Ниже приведён пример базового docker-compose.yml
, который можно использовать в качестве отправной точки. Он поднимает единственный сервис с PostgreSQL и монтирует каталог для хранения данных и логов снаружи контейнера (через volume). Это не только облегчает резервное копирование, но и гарантирует, что данные сохранятся, даже если контейнер будет пересоздан.
services:
postgres:
image: postgres:14
container_name: my_postgres
restart: always
environment:
POSTGRES_USER: myuser
POSTGRES_PASSWORD: mypassword
POSTGRES_DB: mydatabase
volumes:
- postgres_data:/var/lib/postgresql/data
# При необходимости можно добавить другой volume для логов,
# но по умолчанию PostgreSQL пишет логи в stdout
# - postgres_logs:/var/log/postgresql
ports:
- "5432:5432"
volumes:
postgres_data:
# Локальный volume, управляется Docker’ом. Можно настроить
# type, name и другие параметры, если нужно.
Ключевые моменты в примере
- Image: используем официальный образ
postgres:14
. Можно выбрать другую версию, но стоит убедиться, что все параметры, о которых мы будем говорить далее, присутствуют именно в этой версии. - Environment: задаём пользователя, пароль и имя базы по умолчанию. Это удобный минимальный набор параметров.
- Volumes:
postgres_data
указывает, что все файлы БД (включая WAL-файлы) сохраняются не внутри контейнера, а на хостовой машине (в Docker-managed volume).- При пересоздании контейнера данные из
postgres_data
не удалятся, что крайне важно для целостности и постоянного хранения WAL.
- Ports: прокидываем порт 5432 для доступа к СУБД извне.
Такой файл docker-compose.yml
можно поместить в любой каталог на хосте. После этого достаточно запустить:
docker-compose up -d
и контейнер с PostgreSQL будет готов к работе.
Краткий обзор основных параметров PostgreSQL, важных для WAL
Хотя многие параметры PostgreSQL можно настроить через переменные окружения или с помощью дополнительного конфига, есть несколько ключевых опций, связанных с WAL, о которых важно знать заранее:
wal_level
- Определяет уровень детализации записей в WAL.
- По умолчанию для современных версий PostgreSQL (начиная с 10) значение
wal_level
уже установлено вreplica
, что достаточно для большинства кейсов, включая репликацию и архивирование. - Если нужно будет более тонко управлять архивацией или репликацией, возможно понадобится изменить на
logical
или оставить как есть.
archive_mode
- Включает (on) или выключает (off) режим архивации WAL.
- По умолчанию
off
, так что для полноценной системы бэкапов и восстановления нужно будет установитьarchive_mode = on
.
archive_command
- Команда, которая вызывается PostgreSQL для копирования каждого завершённого WAL-файла в архив.
- Например:
archive_command = 'cp %p /path/to/archive/%f'
. - Про неё поговорим подробнее в следующей главе, когда будем настраивать архивацию WAL.
max_wal_size
,min_wal_size
- Параметры, задающие минимально и максимально допустимые размеры WAL в структуре данных PostgreSQL.
- В большинстве случаев можно оставлять значения по умолчанию, но при очень высоконагруженной системе можно увеличить
max_wal_size
для избежания частых чекпоинтов.
wal_compression
- Указывает, сжимать ли WAL-файлы «на лету».
- Это может быть полезно, если размер WAL велик и есть желание экономить место.
Важно понимать, что не все параметры удобно задавать через переменные окружения (например, POSTGRES_INITDB_ARGS
или через дополнительный файл конфигурации). Иногда проще подготовить свой postgresql.conf
, а затем смонтировать его через volume в /var/lib/postgresql/data
или /etc/postgresql/postgresql.conf
внутри контейнера. Но чаще всего базовых параметров, переданных через переменные окружения (или дополнительных SQL-скриптов при инициализации), бывает достаточно.
Структура каталогов в контейнере и снаружи (volumes)
При работе с PostgreSQL через Docker важно понимать, где физически хранятся данные и, в частности, WAL-файлы. По умолчанию в контейнере PostgreSQL использует каталог:
/var/lib/postgresql/data
В нём находится как основная директория базы, так и:
- Папка
pg_wal
(ранееpg_xlog
), где живут файлы WAL. - Конфигурационные файлы (при инициализации).
- Вся структура таблиц и служебные файлы.
Когда мы монтируем postgres_data:/var/lib/postgresql/data
, Docker сохраняет эти данные в специальном месте на хосте (или внешнем драйвере volume). Таким образом, при остановке или удалении контейнера:
- Данные (включая WAL) не удаляются автоматически.
- Вы можете бэкапить их стандартными средствами или копировать целиком папку, если нужно сделать «физическую копию» базы.
Если требуется отдельное место для логов или архива, можно добавить ещё один volume, смонтировав его на хостовом каталоге:
volumes:
postgres_logs:
# ...
services:
postgres:
# ...
volumes:
- postgres_data:/var/lib/postgresql/data
- ./logs:/var/log/postgresql
Тогда логи из PostgreSQL можно будет изучать напрямую на хосте в папке ./logs
. Для WAL-архивов в конфигурации PostgreSQL можно указать каталог (например, /var/lib/postgresql/data/archives
), а затем смонтировать туда отдельный volume. В следующих главах мы разберём детальнее, как с этим работать.
Основные нюансы при подготовке окружения
- Сохраняйте все, что нужно бэкапить, за пределами контейнера.
Использование volume – наиболее правильный способ. Если контейнер удалится, данные останутся на месте, а вы сможете в любой момент пересоздать контейнер, не потеряв при этом базу. - Выбирайте стабильный образ PostgreSQL.
Как правило, лучше использовать обновлённый мажорный релиз (например, 14 или 15), чтобы получить все новые функции и патчи. Но если у вас Production-система, убедитесь, что нужная версия поддерживается, а её поведение вам известно. - Храните конфигурационные файлы вместе с данными или подключайте отдельным volume.
Часто удобнее иметь свойpostgresql.conf
,pg_hba.conf
или папку с SQL-скриптами начальной инициализации. Это позволит быстрее вносить правки в конфигурацию, особенно касающиеся WAL, без необходимости пересобирать образ. - Учитывайте размер диска.
Убедитесь, что на хосте достаточно места для хранения как основных данных, так и потенциала для архивации WAL, особенно если база активно записывает много данных. Слишком маленький диск может привести к переполнению volume и остановке работы контейнера.
На этом этапе мы имеем базовый docker-compose.yml
и общее понимание того, как PostgreSQL хранит данные и WAL. В дальнейших главах настроим параметры для архивации WAL, чтобы иметь полноценную систему восстановления данных, комбинируя бэкапы и «доигрывание» логов.
Настройка PostgreSQL
Итак, мы создали базовое окружение Docker и кратко рассмотрели, какие параметры PostgreSQL влияют на WAL. Теперь настал момент настроить систему так, чтобы она могла архивировать WAL-файлы и использовать их для последующего восстановления.
Основные конфигурационные параметры
Для полноценной работы с WAL нужно включить и правильно настроить несколько ключевых параметров в postgresql.conf
(либо передать их через переменные окружения при запуске контейнера):
wal_level
- Отвечает за уровень детализации записей в WAL.
- Распространённые значения:
replica
(стоит по умолчанию у современных версий PostgreSQL)logical
(если планируете логическую репликацию)
- Для большинства случаев архивации и обычной репликации достаточно
replica
.
archive_mode
- Включает или выключает архивацию WAL-файлов.
- При работе с бэкапами и восстановлением из WAL нужно ставить
on
.
archive_command
- Задаёт команду, с помощью которой PostgreSQL копирует каждый завершённый WAL-файл в место постоянного хранения.
Например:
archive_command = 'cp %p /var/lib/postgresql/data/archives/%f'
где
%p
– путь к WAL-файлу в рабочем каталоге, а%f
– его имя.- Подразумевается, что в директории
/var/lib/postgresql/data/archives
будет достаточно места. - Для удалённой архивации можно использовать
scp
,rsync
и другие инструменты, при условии корректной настройки доступа.
archive_timeout
(необязательно)- Заставляет PostgreSQL «принудительно» завершать WAL-файл через указанный интервал времени (даже если он ещё не достигнут конца).
- Удобно, если нужно более предсказуемое расписание архивации, особенно при низкой нагрузке на базу.
wal_log_hints
(для некоторых вариантов репликации и standby)- Обычно не требуется, но может понадобиться, если планируете использовать реплику в качестве "promote" без полного перебора pages.
max_wal_size
,min_wal_size
- Настройки, регулирующие, сколько WAL-файлов PostgreSQL может хранить до следующего чекпоинта.
- При больших объёмах записи и высоких требованиях к производительности может понадобиться увеличение
max_wal_size
.
Настройка конфигурационных файлов и их размещение в Docker
Способ 1: Настройка через переменные окружения
В Docker-образе PostgreSQL предусмотрен механизм инициализации с помощью переменных окружения и SQL-скриптов. Но в случае с параметрами вроде archive_mode
или archive_command
проще использовать собственный конфигурационный файл.
Способ 2: Использование собственного postgresql.conf
Наиболее распространённая практика — указать в docker-compose.yml
дополнительный volume, который «накрывает» дефолтный postgresql.conf
или монтирует собственный файл в папку с конфигами:
services:
postgres:
image: postgres:14
container_name: my_postgres
environment:
POSTGRES_USER: myuser
POSTGRES_PASSWORD: mypassword
POSTGRES_DB: mydatabase
volumes:
- postgres_data:/var/lib/postgresql/data
- archives:/var/lib/postgresql/data/archives
- ./my_postgresql.conf:/etc/postgresql/postgresql.conf
- ./pg_hba.conf:/etc/postgresql/pg_hba.conf
ports:
- "5432:5432"
command: >
-c 'config_file=/etc/postgresql/postgresql.conf'
-c 'hba_file=/etc/postgresql/pg_hba.conf'
volumes:
postgres_data:
archives:
В таком случае структура папок на хосте может выглядеть так:
my_project/
├─ docker-compose.yml
├─ my_postgresql.conf
└─ pg_hba.conf (опционально)
Сохраним дефолтные настройки postgresql.conf выполнив команду:
docker run --rm postgres:14 cat /usr/share/postgresql/postgresql.conf.sample > my_postgresql.conf
Изменим my_postgresql.conf раскомментировав, к примеру, следующие строки:
# WAL настройки
wal_level = replica # Уровень детализации WAL
archive_mode = on # Включить архивацию
archive_command = 'cp %p /var/lib/postgresql/data/archives/%f' # Команда для архивирования WAL
archive_timeout = 300 # Таймаут архивации WAL (5 минут)
max_wal_size = 2GB # Максимальный размер WAL
min_wal_size = 80MB # Минимальный размер WAL
wal_buffers = 16MB # Буферы для WAL-записей (оптимально для больших нагрузок)
# Настройки автосохранения
checkpoint_timeout = 5min # Частота выполнения checkpoint
checkpoint_completion_target = 0.7 # Целевой процент завершения checkpoint до таймаута
checkpoint_warning = 30s # Предупреждение, если checkpoint выполняется слишком часто
# Оптимизация параллельных операций
effective_cache_size = 512MB # Оценка кэша системы (обычно 50%-75% от RAM)
default_statistics_target = 100 # Статистика для планировщика запросов
В самом контейнере при запуске PostgreSQL прочитает настройки из /etc/postgresql/postgresql.conf
, которые мы смонтировали. Путь к этому файлу указываем через опцию -c 'config_file=...'
в docker-compose.yml
.
Файл pg_hba.conf
отвечает за контроль доступа (авторизация). Он напрямую не влияет на WAL, но при переносе собственной конфигурации стоит убедиться, что в нём сохранены корректные настройки для вашего окружения (например, чтобы пользователь myuser
мог подключаться по нужному IP-адресу).
Пример:
# Разрешить локальное подключение для всех пользователей
local all all trust
# Разрешить подключение по сети с использованием MD5-авторизации
host all all 0.0.0.0/0 md5
host all all ::/0 md5
В случае Docker’а полезно указывать host all all 172.17.0.0/16 md5
(или свой диапазон) — зависит от сетевых настроек Compose.
Проверка корректности настроек и перезапуск контейнера
Шаг 1: Создаём директорию для архивов
Перед тем как запускать контейнер, убедитесь, что есть каталог для архивных WAL-файлов, если не создан volume как в нашем примере.
Шаг 2: Запуск или перезапуск контейнера
Если вы уже запустили контейнер раньше, нужно перезапустить его, чтобы применились новые настройки:
docker-compose down
docker-compose up -d
При этом проверьте логи:
docker-compose logs -f postgres
Ищите строки, указывающие, что archive_mode
включён (archive_mode = on
) и что команда archive_command
установлена.
Шаг 3: Проверка параметров внутри PostgreSQL
Подключитесь к контейнеру PostgreSQL с помощью psql
: Используйте следующую команду для подключения к базе данных mydatabase
:
docker exec -it my_postgres psql -U myuser -d mydatabase
Если хотите подключиться через встроенную базу postgres
, к примеру чтоб создать mydatabase
, используйте:
docker exec -it my_postgres psql -U myuser -d postgres
Затем выполните команду:
\l
Это отобразит список всех доступных баз данных.
Если база данных mydatabase
отсутствует, создайте её:
CREATE DATABASE mydatabase;
Выполните команды для проверки параметров: Внутри интерактивной оболочки psql
выполните следующие SQL-запросы:
SHOW wal_level;
SHOW archive_mode;
SHOW archive_command;
Шаг 4: Проверка архивации WAL
Для теста можно создать или изменить данные в базе, затем дождаться, когда PostgreSQL «свернёт» WAL-файл и запустит archive_command
. В папке archives
(в volume или на хосте) должен появиться файл с именем наподобие 00000001000000000000000A
.
docker exec -it my_postgres ls -l /var/lib/postgresql/data/archives
Если видите, что файлы появляются — настройка архивации WAL работает. Если нет, смотрите логи PostgreSQL: иногда из-за прав на запись или неверного пути PostgreSQL не может выполнить cp %p /.../%f
.
Таким образом, мы включили архивацию WAL, указали, куда копируются файлы, и проверили корректность настроек. На следующем этапе разберём, как организовать хранение этих архивов, эффективно управлять их объёмом и впоследствии использовать их для восстановления данных между моментами создания дампов.
Организация архивации WAL
В этой главе рассмотрим, куда и как можно сохранять WAL-файлы, какие инструменты и команды используются для их архивации, а также познакомимся с механизмами сжатия, ротации и мониторинга. Правильно настроенная архивация позволит нам в дальнейшем «доигрывать» операции при восстановлении из дампа — без потери важных изменений.
Способы хранения WAL-файлов
1. Локальный диск
- Преимущества: простота организации (достаточно указать команду копирования в локальную папку), быстрый доступ к файлам, отсутствие зависимости от сети.
- Недостатки: при выходе из строя локального диска теряется и архив. Также может быстро закончиться место, если объём WAL велик.
2. Сетевое хранилище (NFS, SMB и пр.)
- Преимущества: архив хранится отдельно от основного диска сервера БД, что повышает надёжность. Можно подключать несколько серверов к одному хранилищу.
- Недостатки: нужна стабильная сеть с достаточной пропускной способностью. При сбоях в сети процесс архивации может прерываться.
3. Облачные хранилища (S3, GCS и др.)
- Преимущества: данные «живут» в облаке, обычно есть встроенные механизмы надёжного хранения и репликации.
- Недостатки: возможна сложность интеграции (нужно использовать специальные утилиты типа
s3cmd
,rclone
или писать свой скрипт). Задержки на сеть могут быть выше, чем при локальном или сетевом хранилище.
4. Удалённый сервер (через scp
, rsync
)
- Преимущества: простая реализация, достаточно иметь доступ по SSH; архив лежит отдельно от текущего сервера БД.
- Недостатки: нужно убедиться, что на удалённом сервере настроены права и есть достаточно места для хранения. При проблемах с сетью архивация будет «подвисать» или прерываться.
На практике многие начинают с локального диска (или Docker volume) для отладки и тестирования, а потом переводят архив на более надёжное место: например, сетевую шару или S3.
Настройка archive_command
Чтобы PostgreSQL «отдавал» WAL-файлы в архив, нужно в postgresql.conf
(или через переменные окружения) задать archive_command
. Простейший вариант (локальный архив):
archive_mode = on
archive_command = 'cp %p /var/lib/postgresql/data/archives/%f'
Здесь:
%p
— это путь к исходному WAL-файлу.%f
— имя файла (обычно выглядит как00000001000000000000000A
)./var/lib/postgresql/data/archives/
— каталог, куда мы складываем файлы. Он может быть локальной директорией или смонтированным volume.
Распространённые ошибки и способы их устранения
- Отсутствие каталога для архивов
- Если папка
archives/
не существует или у PostgreSQL нет прав на запись в неё, то при каждом завершении WAL-файла в логах будут появляться ошибки видаcould not create file /... Permission denied
. - Решение: убедиться, что директория создана и права выставлены корректно. В Docker-контейнере папка должна существовать внутри контейнера, если вы не монтируете её снаружи.
- Если папка
- Перезапись уже существующих файлов
- По умолчанию команда
cp %p /archives/%f
перезапишет файл, если он уже там есть. Это может быть проблемой в редких случаях (например, если архивируемся с нескольких нод репликации). Решение: добавить проверку наличия файла, например:
archive_command = 'test ! -f /archives/%f && cp %p /archives/%f'
Так мы не затираем уже существующий WAL-файл.
- По умолчанию команда
- Сеть недоступна (при удалённом хранении)
- Если используем
scp
илиrsync
на удалённый сервер, при отсутствии сети PostgreSQL будет пытаться снова и снова выполнить команду, «зависая» на архивации. - Решение: обеспечивать стабильный доступ к сети, использовать дополнительные ключи
rsync --partial --append
, настраивать SSH-ключи для автоматического подключения. При серьёзных сбоях следить за логами PostgreSQL.
- Если используем
- Недостаточно места
- При избыточной нагрузке и большом количестве WAL-файлов архив может быстро заполняться. Когда директория переполнена, PostgreSQL не сможет завершить запись WAL-файлов, что может привести к критическим ошибкам.
- Решение: регулярно очищать или ротационно перемещать старые файлы, следить за объёмами и расширять хранилище.
Механизмы сжатия, ротации и мониторинга
1. Сжатие (compression)
Чтобы не захламлять хранилище гигабайтами WAL-файлов, можно их сжимать. Например, с помощью gzip:
archive_command = 'cp %p /var/lib/postgresql/data/archives/%f && gzip /var/lib/postgresql/data/archives/%f'
Или комбинированная команда:
archive_command = 'gzip -c %p > /var/lib/postgresql/data/archives/%f.gz'
Главное — помнить, что при восстановлении нужно будет распаковывать эти файлы (PostgreSQL сам не умеет работать с .gz-файлами «напрямую»). В сценариях восстановления нужно прописать путь или использовать скрипты, которые будут «догонять» WAL-файлы в распакованном виде.
Варианты сжатия
- gzip: баланс скорости и сжатия, почти повсеместно доступен.
- bzip2 или xz: более сильное сжатие, но выше нагрузка на процессор.
- zstd: современный алгоритм, даёт хорошее соотношение скорость/сжатие, но требует установки соответствующей утилиты.
2. Ротация архивов
Хранить все WAL-файлы бесконечно невозможно: они могут занять терабайты места. Поэтому необходимо выстроить политику ротации:
- Автоматическая ротация: если у вас настроена логическая репликация или потоковая реплика, возможно, часть WAL уже не нужна. Иногда используют
pg_archivecleanup
, который удаляет WAL-файлы, не нужные для определённой точки восстановления. - Внешние скрипты: можно использовать
cron
-задачи для удаления старых файлов (например, старше N дней), если у вас принято хранить их только за этот период. - Логические дампы: при наличии «золотого» дампа (или физической копии) на определённую дату хранить сверхдревние WAL-файлы нет смысла, т.к. восстанавливаться далее этой даты вы всё равно не будете.
3. Мониторинг состояния архивации
Чтобы не пропустить момент, когда что-то пошло не так, стоит мониторить:
- Логи PostgreSQL: при каждом копировании WAL-файла PostgreSQL пишет запись в лог. Если там появляются повторяющиеся ошибки, нужно реагировать незамедлительно.
- Размер каталога с архивами: если объём внезапно вырос — возможно, из-за пиковых нагрузок или по ошибке не удаляются старые файлы.
- Количество файлов: если раз в день делается дамп, то объём WAL между дампами должен быть понятен и предсказуем. Слишком много новых файлов может говорить о «шторме» транзакций или о циклических ошибках.
Можно подключить системы мониторинга (Prometheus, Zabbix, ELK, Grafana и пр.), следить за состоянием диска, скоростью роста каталога, появлением ошибок в логах.
Таким образом, в правильной схеме архивации мы стремимся хранить WAL на надёжном носителе (локальном, сетевом или облачном), сжимать (при необходимости) файлы ради экономии пространства и регулярно «подчищать» старые логи, без которых уже не будет восстанавливаться база. В следующих главах мы подробно рассмотрим, как непосредственно использовать эти файлы для восстановления между моментами создания дампа и точкой сбоя, то есть как «доигрывать» транзакции из WAL.
Процесс восстановления
В предыдущих главах мы рассмотрели, как настроить PostgreSQL для записи и архивации WAL-файлов. Теперь разберём конкретные шаги, которые позволяют «доиграть» операции (транзакции) между моментом создания дампа и точкой сбоя. Основная идея в том, что дамп восстанавливает базовое состояние, а затем с помощью WAL-файлов мы восстанавливаем все изменения, произошедшие после создания этого дампа.
Шаг 1: Подготовка свежего дампа
Чтобы иметь точку начала для восстановления из WAL, нам нужен актуальный дамп (логический или физический). Предположим, что регулярно (например, раз в сутки или несколько раз в день) мы делаем логический дамп при помощи pg_dump
:
pg_dump -U myuser -d mydatabase > /backup/pg_dumps/mydatabase_20250101.sql
Или делаем физическую копию через pg_basebackup
(которая сохраняет структуру файловой системы БД). В любом случае у нас должен быть «срез» состояния базы на момент создания бэкапа.
Шаг 2: Подготовка каталога для восстановления
Когда случается сбой, нам нужно создать новую чистую среду (новую папку с данными PostgreSQL) и «развернуть» туда наш бэкап. В Docker-контейнере обычно это выглядит так:
- Останавливаем контейнер с PostgreSQL (если он ещё работает).
Очищаем или создаём новую папку (volume) для базы данных:
docker-compose down # Допустим, мы сохраняем данные в volume postgres_data # Если нужно, можно пересоздать volume: docker volume rm my_project_postgres_data docker volume create my_project_postgres_data
Запускаем контейнер с новым (пустым) volume:
docker-compose up -d
Теперь в
/var/lib/postgresql/data
у нас чистая файловая система PostgreSQL.
Шаг 3: Восстановление из дампа
Вариант 1: Логический дамп (.sql
или custom-формат)
Подключаемся к базе (которая сейчас пуста) с помощью
psql
:psql -U myuser -d mydatabase -h 127.0.0.1 -p 5432 < /backup/pg_dumps/mydatabase_20250101.sql
или, если дамп в custom-формате, используем
pg_restore
:pg_restore -U myuser -d mydatabase -h 127.0.0.1 -p 5432 /backup/pg_dumps/mydatabase_20250101.dump
- Дожидаемся окончания восстановления. Теперь в базе данные соответствуют состоянию на момент, когда делался дамп.
Вариант 2: Физическая копия (через pg_basebackup
)
Распаковываем физическую копию в папку
data
(или соответствующую папку volume):pg_basebackup -D /var/lib/postgresql/data_restored -U myuser -Fp -Xs -P
- Запускаем PostgreSQL, указав путь к этой директории в Docker (или копируя файлы в нужную папку volume).
При физическом бэкапе у нас уже есть «живое» состояние всей файловой системы базы, включая pg_wal
, но для полноценного восстановления может понадобиться дополнительная настройка recovery-файлов — об этом в следующих шагах.
Шаг 4: Применение WAL для восстановления данных между моментом создания дампа и точкой сбоя
Теперь самое важное: «доиграть» (replay) все WAL-файлы, которые накопились после создания дампа. Логика следующая:
- PostgreSQL при старте переходит в режим восстановления (recovery) и начинает поочерёдно читать архивные WAL-файлы.
- Все изменения, зафиксированные в WAL, применяются к базе.
- Как только доходят до нужной точки (обычно до последнего доступного WAL-файла перед сбоем), восстанавливаемая база становится актуальной.
Настройка режима восстановления
Исторически в PostgreSQL был файл recovery.conf
, где прописывалось, откуда брать WAL для восстановления. Начиная с 12-й версии, эти параметры переехали в postgresql.conf
или standby.signal
/recovery.signal
. Однако логика осталась примерно той же:
restore_command
— команда, которую PostgreSQL использует, чтобы брать нужный WAL-файл из архива. Аналогичнаarchive_command
, но в обратную сторону.recovery_target_time
илиrecovery_target_xid
(опционально) — если нужно восстановиться к конкретному моменту времени или к конкретной транзакции.recovery_target_action
— что делать после достижения нужной точки (остановить или продолжить работу).
Пример фрагмента в postgresql.conf
, который настраивается для восстановления:
# Включаем режим восстановления (PostgreSQL 12+)
restore_command = 'cp /var/lib/postgresql/data/archives/%f %p'
# Если хотим «поймать» момент времени, до которого делаем recovery:
# recovery_target_time = '2025-01-01 10:30:00'
# Когда восстановление достигнет точки, перестать читать WAL и «промоутиться» в обычный режим
recovery_target_action = 'promote'
В более старых версиях PostgreSQL (до 12) можно было создать файл recovery.conf
в папке с данными и прописать там:
restore_command = 'cp /var/lib/postgresql/data/archives/%f %p'
recovery_target_action = 'promote'
Размещение конфигурации в Docker
- Создайте или отредактируйте дополнительный файл конфигурации, например
recovery.conf
(для PostgreSQL < 12) или включите эти параметры напрямую вpostgresql.conf
(для PostgreSQL ≥ 12). При запуске контейнера в вашем
docker-compose.yml
можно указать:services: postgres: # ... volumes: - ./postgresql.conf:/etc/postgresql/postgresql.conf - ./my_recovery_signal_file:/var/lib/postgresql/data/recovery.signal command: > -c 'config_file=/etc/postgresql/postgresql.conf'
Зачем нужен
./my_recovery_signal_file
?Файл
recovery.signal
служит сигналом для PostgreSQL, что база данных должна быть запущена в режиме восстановления. Это необходимо в следующих случаях:- Восстановление из архива WAL: PostgreSQL использует
restore_command
, чтобы последовательно восстанавливать изменения из архивных WAL-файлов. - Point-in-time recovery (PITR): Если задан параметр
recovery_target_time
, PostgreSQL остановит восстановление на указанном моменте времени. Репликация: Если вы настраиваете реплику базы данных, режим восстановления необходим для синхронизации с мастером.
- Восстановление из архива WAL: PostgreSQL использует
- Убедитесь, что при старте базы нет конфликтующих настроек (например,
archive_mode=on
и одновременно попытка восстановиться).
Запуск и проверка
После того как PostgreSQL стартует в режиме восстановления, он будет последовательно копировать WAL-файлы командой restore_command
. В логах должны появляться сообщения вида:
LOG: starting point-in-time recovery to 2025-01-01 10:30:00
LOG: restored log file "00000001000000000000000A" from archive
LOG: consistent recovery state reached
Когда все нужные файлы будут обработаны, база «промоутится» в обычное рабочее состояние.
Шаг 5: Тонкости и частые подводные камни
- Совпадение версий
- Дамп, WAL-файлы и восстанавливаемая версия PostgreSQL должны совпадать (или быть совместимы). Если у вас дамп сделан на PostgreSQL 14, а восстанавливаете на 15, могут возникать проблемы с физической копией. Для логического дампа это менее критично, но всё же лучше избегать больших «скачков» версий.
- Чистота данных в каталоге
- Если в каталоге данных уже лежат какие-то «старые» файлы от другой установки PostgreSQL, возможно, восстановление пройдёт некорректно или не начнётся вовсе. Убедитесь, что папка чистая, прежде чем разворачивать в неё бэкап.
- Количество WAL-файлов
- Если в архиве не хватает нужных WAL-файлов, то восстановиться до последнего состояния не получится. Убедитесь, что архивирование велось непрерывно и все файлы с момента создания дампа до сбоя присутствуют.
- Если какого-то WAL-файла нет, PostgreSQL выдаст ошибку
could not restore file ...
и придётся искать обходные пути (например, отменить восстановление после последнего имеющегося файла).
- Конфликтующие настройки
- В современных версиях (12+)
recovery.conf
больше не используется, и сам файл вызовет ошибку при старте PostgreSQL. Нужно использовать сигнальные файлыrecovery.signal
илиstandby.signal
и прописывать параметры восстановления вpostgresql.conf
.
- В современных версиях (12+)
- Права доступа и пути
- При использовании Docker зачастую проблемы возникают из-за неправильных путей внутри контейнера. Проверяйте, соответствует ли путь в
restore_command
реальному пути к архиву. Если архив монтируется извне, нужно убедиться, что PostgreSQL внутри контейнера «видит» именно тот каталог, который вы указали.
- При использовании Docker зачастую проблемы возникают из-за неправильных путей внутри контейнера. Проверяйте, соответствует ли путь в
Таким образом, полный процесс восстановления выглядит так:
- Развернуть новое окружение или очистить существующее.
- Импортировать свежий дамп (логический или физический).
- Указать в конфигурации пути к архиву WAL и команды для его копирования.
- Запустить PostgreSQL в режиме восстановления, проверить логи и дождаться сообщения о завершении recovery.
- Получить базу в актуальном состоянии с учётом всех транзакций, которые были совершены после создания дампа.
Практические примеры
В этой главе мы рассмотрим конкретные команды и способы проверки, которые помогут убедиться, что наша конфигурация бэкапов и WAL работает без сбоев. Также поговорим о полезных лайфхаках и том, куда двигаться дальше, чтобы углублять знания в теме резервирования и масштабирования.
Примеры Docker-команд и команд psql
для бэкапа
Ниже — несколько команд, которые можно запускать в стандартном окружении Docker с PostgreSQL.
1. Создание логического дампа
# Допустим, у нас контейнер называется my_postgres
# Создаём дамп базы mydatabase, пользователь myuser
docker exec -it my_postgres \
pg_dump -U myuser mydatabase > /backup/pg_dumps/mydatabase_$(date +%Y%m%d_%H%M).sql
docker exec -it my_postgres
— заходим внутрь контейнера.pg_dump -U myuser mydatabase
— команда для бэкапа.> /backup/pg_dumps/
... — перенаправляем вывод в файл (предполагается, что папка/backup/pg_dumps/
смонтирована как volume или проброшена наружу).
Важно: Проверьте, что внутри контейнера действительно есть каталог
/backup/pg_dumps
. Иначе перенаправляйте вывод на хосте, используя что-то вродеdocker exec my_postgres pg_dump ... > backup.sql
.
2. Создание физического бэкапа при помощи pg_basebackup
docker exec -it my_postgres \
pg_basebackup -U myuser -D /backup/physical_backup -Fp -Xs -P
-D /backup/physical_backup
— каталог для сохранения физических файлов базы.-Fp
— формат Plain, копирование файлов.-Xs
— включение репликационных слотов (или стриминг WAL) в процессе.-P
— показывает прогресс.
После выполнения команды в /backup/physical_backup
будет готовая файловая структура, которую можно «поднять» вместо /var/lib/postgresql/data
при восстановлении.
3. Восстановление логического дампа
# Допустим, хотим восстановить в ту же базу (mydatabase),
# в том же контейнере
docker exec -i my_postgres \
psql -U myuser -d mydatabase < /backup/pg_dumps/mydatabase_20250101.sql
psql -U myuser -d mydatabase < ...
— применяем SQL-скрипт дампа к существующей базе.
Если нужно «чистое» восстановление (например, сбросить базу перед заливкой дампа), можно предварительно удалить/создать заново базу командой:
DROP DATABASE mydatabase;
CREATE DATABASE mydatabase;
И только потом залить дамп.
Примеры восстановления с WAL
Проверка наличия архивированных WAL-файлов
ls /var/lib/postgresql/data/archives
Если всё работает, вы увидите файлы формата
00000001000000000000000A
(и так далее).Проверка параметров архивации в работающем контейнере
docker exec -it my_postgres psql -U myuser -c "SHOW archive_mode;" docker exec -it my_postgres psql -U myuser -c "SHOW archive_command;" docker exec -it my_postgres psql -U myuser -c "SHOW wal_level;"
Убедитесь, что
archive_mode = on
,archive_command
не пуст, аwal_level
соответствуетreplica
илиlogical
.- Симуляция сбоя и восстановление
- Останавливаем контейнер и меняем volume (или его очищаем).
- Запускаем контейнер с пустой базой.
- Заливаем последний дамп.
- Указываем путь к архивным WAL-файлам в параметре
restore_command
(вpostgresql.conf
илиrecovery.conf
для версий < 12). - Перезапускаем контейнер и ждём, пока PostgreSQL «доиграет» WAL.
- Проверяем, что нужные данные (созданные после дампа) появились.
Полезные советы и лайфхаки
1. Регулярное тестовое восстановление
- Отрабатывайте план B: как только настроили бэкап и WAL — пробуйте на тестовом окружении развернуть базу из этих копий. Лишь проверив реальное восстановление, можно быть уверенным, что бэкап не окажется бесполезным.
- График тестов: раз в неделю или месяц делайте «учебную» процедуру восстановления, чтобы в случае ЧП не тратить время на изучение логов и документации.
2. Ротация старых WAL-файлов
- Используйте механизмы вроде
pg_archivecleanup
, чтобы автоматически удалять WAL-файлы, которые больше не нужны (если у вас нет целей откатываться на очень старые точки). - В больших системах накопление тысяч WAL-файлов может занимать много места и усложнять мониторинг.
3. Мониторинг и оповещения
- Логи PostgreSQL: анализируйте логи на предмет ошибок архивации. Если
archive_command
возвращает ненулевой код, в логах появятся соответствующие сообщения. - Сторонние инструменты: подключите Prometheus/Grafana или другую систему мониторинга, чтобы отслеживать использование дискового пространства, появление новых WAL-файлов и т.п.
4. Автоматизация бэкапов
- Cron-задачи: внутри контейнера (или на хосте) можно прописать cron, который вызывает
pg_dump
илиpg_basebackup
в нужное время. Логи работы cron нужно куда-то записывать, чтобы отслеживать возможные ошибки. - Docker-подход: некоторые предпочитают отдельный контейнер, который «подключается» к базе и делает бэкап, выкладывая результат в S3, локальную папку или сетевое хранилище.
5. Проверка совместимости версий
- При переходе на новую версию PostgreSQL (например, с 14 на 15) заранее убедитесь, что физический бэкап и WAL взаимно совместимы. Логический дамп обычно переносится проще, но всё же внимательно изучайте Release Notes.
6. Хранение бэкапов вне сервера
- Если вся система (сервер/хост Docker) выходит из строя, локальные бэкапы не спасут. Поэтому всегда держите бэкапы (дампы и WAL-архивы) как минимум в другом дата-центре или другом физическом месте.
Что дальше изучать и в каком направлении двигаться
- Потоковая репликация (Streaming Replication): позволяет иметь «горячий» стендбай-сервер, который уже получает WAL-файлы в реальном времени. В случае сбоя можно быстро переключиться на реплику.
- Логическая репликация: помогает избирательно реплицировать таблицы или даже отдельные данные в другие кластеры.
- Шардирование, Patroni, Stolon и другие менеджеры кластеров: для больших нагрузок и высоких требований к доступности используют дополнительные инструменты, которые упрощают администрирование нескольких узлов PostgreSQL.
- Автоматизированные инструменты бэкапа: например, Barman или WAL-G, которые берут на себя ротацию, мониторинг и экономию дискового пространства.
Таким образом, на основе всех рассмотренных глав можно собрать рабочую систему: от базового Docker Compose-файла и настройки archive_mode
до тестирования восстановления при сбое. Регулярные проверки, отслеживание логов и своевременная ротация WAL-файлов станут залогом надёжности и помогут избежать критических потерь данных.