Резервное копирование и восстановление

Рейтинг: 67.6% · 8 голосов
Подробный курс по PostgreSQL: SQL по демобазе, типы данных и JSONB, индексы, транзакции и MVCC, VACUUM, EXPLAIN и планировщик, роли и привилегии, репликация, бэкап, настройка под нагрузку и под 1С. Актуально на 2026.
Ответить
Аватара пользователя
Egor_DBA
Сообщения: 47
Зарегистрирован: 11 май 2026, 05:31

Резервное копирование и восстановление

Сообщение Egor_DBA »

Оглавление курса (47)
  1. Что такое PostgreSQL: история, философия, где применяется
  2. Урок 1. Что нового в PostgreSQL 15 и далее (15 -> 16 -> 17)
  3. Установка и первый запуск: Linux, Windows, Docker
  4. psql детально: метакоманды и работа в консоли
  5. Демобаза Авиаперевозки Postgres Pro: структура и развёртывание
  6. SELECT: проекция, фильтрация, сортировка
  7. Транзакции и ACID
  8. Уровни изоляции транзакций: Read Committed, Repeatable Read, Serializable
  9. Соединения таблиц (JOIN)
  10. Агрегация: GROUP BY, HAVING, GROUPING SETS
  11. Подзапросы и CTE (WITH), рекурсия
  12. Оконные функции
  13. Изменение данных: INSERT/UPDATE/DELETE, UPSERT, MERGE
  14. Числовые и булевы типы, NULL и трёхзначная логика
  15. Строки, текст, дата и время, таймзоны
  16. Массивы, диапазоны, enum, составные типы
  17. JSON и JSONB: операторы и индексация
  18. DDL: CREATE TABLE, схемы, ALTER
  19. Ограничения целостности
  20. Представления и материализованные представления
  21. Последовательности, IDENTITY, генерируемые столбцы
  22. Индексы: B-tree и когда индекс не используется
  23. Типы индексов: Hash, GiST, SP-GiST, GIN, BRIN
  24. Продвинутые индексы: частичные, по выражению, покрывающие
  25. Обслуживание индексов и таблиц: bloat, REINDEX, CONCURRENTLY
  26. Полнотекстовый поиск
  27. Роли и пользователи
  28. Привилегии: GRANT/REVOKE
  29. Row-Level Security и безопасность данных
  30. Подключение приложения: pg_hba.conf, SSL, пулы соединений
  31. Серверное программирование: функции и процедуры
  32. Триггеры и события
  33. Архитектура PostgreSQL: процессы и память
  34. MVCC: версии строк и видимость
  35. VACUUM, autovacuum, freeze и wraparound
  36. WAL, контрольные точки и долговечность
  37. Блокировки и взаимоблокировки
  38. Планировщик запросов
  39. EXPLAIN и EXPLAIN ANALYZE: чтение планов
  40. Конфигурация сервера: ключевые параметры
  41. Настройка под нагрузку и под 1С
  42. Параллельные запросы и партиционирование
  43. Резервное копирование и восстановление (вы здесь)
  44. Репликация: потоковая и hot standby
  45. Логическая репликация и кластерные решения
  46. Внешние данные, расширения и сертификация
  47. Разбор планов запросов на explain.tensor.ru: глубокое чтение EXPLAIN ANALYZE
Урок 42. Резервное копирование и восстановление

Бэкап нужен не для галочки, а чтобы пережить удалённую по ошибке таблицу, сгоревший диск и кривую миграцию в проде. В этом уроке разберём, какие вообще бывают копии в postgresql, чем логический дамп отличается от физического, как настроить непрерывную архивацию WAL и сделать восстановление на точный момент времени (PITR). Главная мысль урока: бэкап, который ни разу не восстанавливали, считается несуществующим, поэтому проверку восстановления мы выносим в отдельный пункт.

Изображение

Как это работает

Есть два мира резервных копий, и их полезно не путать. Логическая копия - это, грубо говоря, набор команд (CREATE TABLE, COPY, INSERT), который заново собирает данные с нуля. Физическая копия - это побайтовый слепок самих файлов кластера плюс журнал предзаписи (WAL), из которого СУБД доигрывает изменения.

Логический бэкап делает pg_dump (одна база) и pg_dumpall (весь кластер целиком, включая роли и табличные пространства). Он переносим между версиями PostgreSQL и даже между архитектурами, легко достать одну таблицу, удобно хранить в git как схему. Платите за это скоростью: на большой базе дамп и особенно последующая загрузка идут долго, потому что заново строятся индексы и проверяются ограничения.

Физический бэкап делает pg_basebackup. Он снимает копию каталога данных на уровне файлов, работает быстрее на крупных базах и является фундаментом для реплик и для PITR. Минус - копия привязана к мажорной версии и платформе, отдельную таблицу из неё так просто не вынуть.

Теперь про сердце физического подхода - WAL. Любое изменение сначала пишется в журнал, а уже потом попадает в файлы данных. Если мы сохраняем базовую копию плюс непрерывный поток WAL-сегментов, то можем восстановить кластер на любой момент между базовой копией и последним заархивированным журналом. Это и есть PITR (point-in-time recovery): откатиться ровно к мгновению перед роковым DELETE.

Связка простая. Параметр archive_command говорит сервью, куда складывать заполненные WAL-сегменты (archive_mode при этом должен быть on). При восстановлении restore_command говорит, откуда их брать. В PostgreSQL 12 настройки восстановления переехали из recovery.conf в обычный postgresql.conf, а сигналом к восстановлению служит пустой файл recovery.signal в каталоге данных - это актуально для PG 15/16/17.

SQL и примеры

Логический дамп демобазы bookings в сжатом custom-формате (это не plain SQL, а контейнер, из которого pg_restore умеет доставать объекты выборочно и параллельно):

Код: Выделить всё

pg_dump -h localhost -U postgres -d demo \
        -F c -Z 6 -f demo.dump
Здесь -F c - формат custom, -Z 6 - уровень сжатия. Восстановление в новую базу с распараллеливанием на 4 потока:

Код: Выделить всё

createdb -U postgres demo_restored
pg_restore -U postgres -d demo_restored -j 4 demo.dump
Выгрузить только одну таблицу из схемы bookings, например рейсы:

Код: Выделить всё

pg_dump -U postgres -d demo -F c -t bookings.flights -f flights.dump
Дамп всего кластера вместе с ролями и правами (это умеет только pg_dumpall):

Код: Выделить всё

pg_dumpall -U postgres --roles-only -f roles.sql
Перед бэкапом полезно понимать масштаб - вот запрос к демобазе, который показывает, сколько строк в основных таблицах перевозок и сколько они весят на диске:

Код: Выделить всё

SELECT relname AS table,
       to_char(reltuples, 'FM999G999G999') AS approx_rows,
       pg_size_pretty(pg_total_relation_size(c.oid)) AS size
FROM   pg_class c
JOIN   pg_namespace n ON n.oid = c.relnamespace
WHERE  n.nspname = 'bookings' AND c.relkind = 'r'
ORDER  BY pg_total_relation_size(c.oid) DESC;
Самыми тяжёлыми обычно окажутся ticket_flights и boarding_passes - по ним и оценивайте время дампа.

Физическая базовая копия для PITR или для будущей реплики:

Код: Выделить всё

pg_basebackup -h localhost -U replicator \
              -D /backup/base -F t -z -X stream -P
Флаг -X stream дотягивает WAL прямо в копию, -F t даёт tar, -P рисует прогресс.

Настройка непрерывной архивации в postgresql.conf:

Код: Выделить всё

wal_level = replica
archive_mode = on
archive_command = 'test ! -f /arch/%f && cp %p /arch/%f'
Здесь %p - путь к готовому сегменту, %f - его имя. Команда сначала проверяет, что файла ещё нет, и только потом копирует.

Восстановление на момент времени. Распаковываем базовую копию в пустой каталог, кладём recovery.signal и в postgresql.conf задаём:

Код: Выделить всё

restore_command = 'cp /arch/%f %p'
recovery_target_time = '2026-06-13 18:30:00+03'
recovery_target_action = 'promote'
При старте сервер проиграет WAL до указанного времени и откроется на запись. Так вы возвращаете базу в состояние за секунду до инцидента.

Частые грабли
  • archive_command вернул успех, хотя копирование не прошло - сервер считает сегмент заархивированным и может его удалить. Команда обязана падать с ненулевым кодом при любой ошибке.
  • Один pg_dump в проде нагружает диск и держит снапшот транзакции долго - на горячей базе это конфликтует с агрессивным VACUUM и раздувает таблицы.
  • pg_dump не переносит глобальные объекты - роли, права на уровне кластера и табличные пространства остаются за бортом, их забирает только pg_dumpall.
  • Параллельный pg_restore (-j) ускоряет, но требует формата custom или directory; на plain SQL-дампе флаг -j молча игнорируется.
  • Забыли -X у pg_basebackup или не настроили архив - в копии не хватит WAL, и кластер не стартует.
  • recovery_target_time без таймзоны трактуется в локали сервера - легко промахнуться на пару часов и недо- или перевосстановить.
  • Версии не совпадают: физическую копию с PG 15 нельзя поднять на PG 16. Логический дамп между версиями переносится, обратное - нет.
Мини-лаба
  • Создайте тестовую базу: createdb lab42 и наполните таблицу заметным набором строк через generate_series.
  • Сделайте custom-дамп: pg_dump -d lab42 -F c -f lab42.dump.
  • Уроните таблицу (DROP TABLE) и восстановите её из дампа в новую базу через pg_restore -j 2.
  • Включите archive_mode и archive_command, перезапустите сервер, сделайте pg_basebackup в отдельный каталог.
  • Запишите точное время (SELECT now()), затем вставьте мусорные строки и снова запомните время.
  • Поднимите вторую копию кластера с recovery_target_time перед вставкой мусора и убедитесь, что мусорных строк нет.
  • Сравните число строк до и после - так вы проверили, что PITR реально работает.
Контрольные вопросы
  • Чем логический бэкап pg_dump принципиально отличается от физического pg_basebackup и когда какой выбирать?
  • Почему archive_command обязан возвращать ошибку при неудаче и что случится, если этого не сделать?
  • Какие объекты сохраняет pg_dumpall, но не сохраняет pg_dump?
  • Что должно быть в наличии, кроме базовой копии, чтобы выполнить восстановление на момент времени?
  • Зачем нужен файл recovery.signal и какие параметры управляют целевой точкой PITR?
  • Почему бэкап без регулярной проверки восстановления нельзя считать рабочим?
👍2 ❤️3 🔥1 😄 🤔5
Аватара пользователя
gjfmac
Сообщения: 1
Зарегистрирован: 30 май 2026, 08:52

Re: Резервное копирование и восстановление

Сообщение gjfmac »

А правда что pg_dump держит длинную транзакцию и мешает вакууму? У нас как раз ночью дамп идёт и таблицы пухнут, теперь понятно куда копать.
👍 ❤️ 🔥 😄 🤔
Аватара пользователя
vault_addict
Сообщения: 1
Зарегистрирован: 02 июн 2026, 13:21

Re: Резервное копирование и восстановление

Сообщение vault_addict »

Споткнулся ровно на recovery_target_time без таймзоны - восстановил не туда на 3 часа. Теперь всегда пишу +03 явно, спасибо что предупредили.
👍 ❤️1 🔥 😄 🤔
Ответить
← Предыдущая глава
Параллельные запросы и партиционирование
Следующая глава →
Репликация: потоковая и hot standby

Все главы курса «PostgreSQL: от первого запроса до продакшена»

Поделиться темой: ✈ Telegram VK
Похожие запросы: бэкап и восстановление postgresql через pg_dump

Вернуться в «PostgreSQL: от первого запроса до продакшена»

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и 1 гость