Восстановление после сбоя
Play ITЗагрузка интерактивного демо…
Две разные истории, которые новички смешивают
Фраза "восстановить базу" в разговоре означает две разные задачи. Их путают — и тогда ждут от pg_dump того, что делает WAL при перезагрузке, или наоборот.
| Задача | Типичный вопрос | Кто решает | Где в энциклопедии |
|---|---|---|---|
| Восстановление после сбоя | Сервер упал / выдернули питание — поднимется ли БД сама? | Движок СУБД (WAL, redo/undo) | эта глава |
| Восстановление из резервной копии | Удалили таблицу / сгорел диск — как вернуть данные? | DBA, pg_dump, PITR | Резервное копирование и восстановление PostgreSQL, Управление РСУБД |
Аналогия. Crash recovery — как если вы выключили Word без сохранения, а программа при следующем запуске сама подтянула автосохранение из служебного журнала. Бэкап — как копия всего документа на флешке вчера: если сгорел ноутбук, журнал Word уже не поможет.
Обе темы важны. Бэкап без понимания WAL — неясно, до какого момента времени можно откатиться (RPO). WAL без бэкапа — после уничтожения диска журнал на том же диске тоже пропал.
В теоретических основах мы уже упоминали Write-Ahead Logging (WAL): сначала запись в журнал, потом — в файлы таблиц. Здесь развернём цепочку: checkpoint → redo → undo и пройдём сценарий "упал сервер — подняли снова".
Кто пишет WAL на диск и куда попадают страницы таблиц — в напоминалке по архитектуре PostgreSQL (процессы WAL Writer, Background Writer, Checkpointer, буферы WAL buffers и shared buffers).
Восстановление базы данных — функция СУБД
Восстановление базы данных — функция восстановления данных, хранимых в СУБД: при сбоях база приводится к актуальному (на заданный момент времени) и согласованному состоянию.
Типичные механизмы:
| Механизм | Роль |
|---|---|
| Резервное копирование + restore | Возврат к копии на диске или логический импорт |
| Контрольные точки + журнал предзаписи (WAL) | Crash recovery при перезапуске; основа PITR |
| Снимок / реплика + журнал | Откат к образу и догон изменений (redo или undo — по продукту) |
Подсистему восстановления оценивают двумя целевыми показателями (см. следующий раздел). Практика бэкапов — Резервное копирование и восстановление PostgreSQL, администрирование РСУБД.
Восстановление данных в широком смысле (извлечение информации с носителя, когда обычное чтение невозможно) — отдельная область — форматирование, повреждение файловой системы, физический износ диска. Самый надёжный путь для продакшена — заранее сделанные резервные копии и проверенная процедура restore, а не "спасение" умершего диска в лаборатории.
Целевые показатели — RPO и RTO
При планировании резервного копирования и аварийного восстановления фиксируют два критерия. Они могут быть жёстко связаны (малый RPO требует частых бэкапов и архива WAL) или слабее — в зависимости от рисков бизнеса и бюджета.
| Показатель | Англ. | Смысл |
|---|---|---|
| Целевая точка восстановления | RPO (Recovery Point Objective) | Максимальный объём данных (интервал времени), допустимый к потере между последним успешным сохранением и аварией. Задаёт частоту бэкапов и непрерывную архивацию журналов |
| Целевое время восстановления | RTO (Recovery Time Objective) | Время от аварии до возврата сервиса в работу (после обнаружения инцидента, восстановления и проверки). Включает задержку мониторинга и реакции команды |
Финансовые организации с непрерывными транзакциями часто стремятся к минимальному RPO (зеркалирование, синхронная репликация, непрерывное архивирование WAL). Снижение RTO ниже порога резко увеличивает затраты на инфраструктуру и отработанные runbook'и.
Формулировки в контракте ("не более 15 минут несохранённых транзакций") переводятся в политику бэкапа и архивации. См. экономику сопровождения.
Холодное резервирование — БД остановлена или закрыта для пользователей; файлы данных во время копирования не меняются, снимок согласован при следующем запуске.
Горячее резервирование — БД работает; после копирования файлов копию доводят до согласованного состояния применением журналов (WAL, archive log, transaction log).
Термины главы
| Термин | Простыми словами |
|---|---|
| WAL | Журнал "что изменилось" — пишется раньше, чем данные на диске в файлах таблиц. |
| Страница | Кусок файла таблицы (часто 8 КБ в PostgreSQL) — единица чтения/записи с диска. |
| Dirty page | Страница в RAM изменена, на диске ещё старая копия. |
| Checkpoint | Точка, с которой при старте проигрывают меньший хвост WAL. |
| Redo | "Докатить" закоммиченные изменения на диск. |
| Undo | "Откатить" незавершённые транзакции. |
| PITR | Восстановление на момент времени из бэкапа + архив WAL (уже работа DBA). |
Что может пойти не так
- обрыв питания на сервере БД;
- падение процесса
postgres/mysqld/sqlservr; - "жёсткий" kill -9 во время активной записи;
- сбой диска после записи в WAL, но до сброса "грязных" страниц в файл таблицы.
Цель восстановления — при старте СУБД приводит базу к согласованному состоянию — либо все эффекты закоммиченных транзакций на месте, либо незавершённые откатаны, как будто их не было.
WAL — журнал опережающей записи
Принцип WAL (Write-Ahead Logging): любое изменение, которое должно пережить сбой, сначала записывается в журнал (последовательный файл, только дописывание в конец), и потом (может быть через секунды) отражается в файлах таблиц на диске.
Зачем так делают:
- Скорость — дописать в конец одного файла журнала дешевле, чем искать случайные страницы по всем таблицам.
- Надёжность — при обрыве питания на диске в журнале уже есть "мы списали 100 ₽ со счёта 1"; при старте СУБД повторит это на странице счёта (redo).
В PostgreSQL журнал лежит в каталоге pg_wal (раньше называли pg_xlog). В Oracle — redo log, в SQL Server — transaction log. Имена разные, роль одна.
Связь с COMMIT (разбор для новичка):
BEGIN;
UPDATE accounts SET balance = balance - 100 WHERE id = 1;
COMMIT;
После COMMIT клиент видит "OK". Внутри PostgreSQL (упрощённо):
- В WAL записано: "изменение balance на счёте 1".
- В WAL записано: "COMMIT транзакции № 12345".
- WAL сброшен на диск (
fsync) — буква D (Durability) из ACID. - Страница таблицы
accountsможет ещё жить только в RAM — это нормально.
Значит: commit ≠ "всё уже на диске в файле таблицы". Commit = "запись о результате не потеряется при сбое, потому что она в WAL".
Подробнее про транзакции: Транзакции, изоляция и блокировки.
Страницы в памяти и на диске
Данные в таблицах лежат страницами (часто 8 КБ) — см. Теоретические основы реляционных данных и Внутреннее устройство баз данных. Активная работа идёт в буферном пуле (RAM):
- транзакция меняет строку → меняется копия страницы в RAM;
- в WAL пишется запись "что изменилось";
- страница помечается "грязной" (dirty);
- позже фоновый процесс сбрасывает грязные страницы на диск — не обязательно до
COMMIT.
При сбое в RAM всё теряется. На диске остаются старые версии страниц + полный WAL с момента последней контрольной точки.
Контрольная точка (checkpoint)
Checkpoint — момент, когда СУБД гарантирует — все грязные страницы, изменённые до этой точки, записаны в файлы данных, а соответствующие записи WAL можно считать "уже отражёнными" в файлах (упрощённо — для понимания; детали зависят от СУБД).
Зачем: при старте после сбоя не нужно проигрывать WAL с начала времени — только с последнего checkpoint.
В PostgreSQL параметры checkpoint_timeout, checkpoint_completion_target — в справочнике администрирования.
Частая ошибка: думать, что checkpoint "заменяет" commit. Нет: commit фиксирует транзакцию в WAL; checkpoint разгружает объём redo при recovery.
Redo и undo — две стороны recovery
При старте после аварии движок выполняет crash recovery — автоматически, до того как пустит клиентов.
Redo (повтор, "докатить вперёд")
Задача: применить к страницам на диске изменения из WAL, которые уже закоммичены, но не успели попасть в файлы таблиц до сбоя.
Пример. В WAL есть: "счёт 1: balance = 900" и "COMMIT". На диске в файле таблицы всё ещё balance = 1000 (страница не сбросили из RAM). Redo перепишет страницу так, чтобы на диске стало 900.
Undo (откат, "убрать лишнее")
Задача: отменить эффекты транзакций без COMMIT в WAL — они оборвались при падении.
Пример. В WAL есть "UPDATE счёт 2: balance = 5000", но нет COMMIT для этой транзакции. Пользователь не должен видеть 5000 — undo (или эквивалент в MVCC) возвращает согласованное состояние, как до начала этой транзакции.
| Фаза | Вопрос | Действие |
|---|---|---|
| Redo | Что успели зафиксировать? | Применить закоммиченное из WAL на диск |
| Undo | Что не зафиксировали? | Стереть следы незавершённого |
В Oracle явно говорят про undo tablespace; в PostgreSQL многое завязано на MVCC и статусы транзакций в WAL — для экзамена и архитектуры пара redo/undo остаётся полезной моделью.
Durability — что именно обещает COMMIT
Буква D в ACID — долговечность: после успешного COMMIT результат переживёт сбой при принятых настройках СУБД.
Цепочка в PostgreSQL (упрощённо):
- Изменения записаны в WAL-буфер.
- При
COMMIT— сброс WAL на диск (wal_write,fsyncв зависимости отsynchronous_commit). - Клиент получает "OK".
- Страницы таблиц могут всё ещё быть только в RAM — это нормально.
Параметр synchronous_commit влияет на баланс скорость / надёжность:
| Значение (идея) | Поведение |
|---|---|
on (типично) | Commit ждёт устойчивой записи WAL |
off / локальные варианты | Быстрее, но при сбое питания последние commits могут "откатиться" |
Разработчик думает "commit = навсегда", DBA проверяет, какой уровень durability настроен на prod. Подробнее параметры — справочник PostgreSQL.
Три вида "восстановления" (не путать)
| Вид | Когда | Инструмент |
|---|---|---|
| Crash recovery | Перезапуск после падения процесса / питания | Автоматически, redo/undo из WAL |
| Media recovery | Повреждён или утерян файл данных / диск | Бэкап + WAL (PITR), восстановление кластера |
| Logical recovery | Удалили таблицу, нужна одна БД или старая версия схемы | pg_dump / pg_restore |
Эта глава — про первый вид. Резервное копирование и восстановление PostgreSQL — про второй и третий.
Репликация и WAL (соседняя тема)
Физическая реплика в PostgreSQL стримит WAL на standby. Primary и standby разделяют одну историю изменений в журнале — поэтому понимание WAL нужно и для "аварийного" recovery, и для отставания реплики (replication lag).
Реплика не заменяет бэкап: при DROP DATABASE на primary ошибка часто повторится на replica. Нужны snapshot + периодический pg_dump и drill восстановления — администрирование.
Сценарий по шагам
- Транзакция списала 100 ₽ — WAL записан,
COMMITв WAL есть. - Страница
accountsвсё ещё только в RAM. - Сбой — RAM пуста, на диске старая страница без списания.
- Старт PostgreSQL — redo проигрывает WAL → страница на диске с списанием.
- Другая транзакция без
COMMIT— undo / откат её эффектов.
Пользователь после рестарта видит согласованные данные; приложение может переподключиться.
Point-in-Time Recovery (PITR) — мост к администрированию
PITR — восстановление на момент времени между бэкапом и "сейчас", используя архив WAL + базовую копию. Это уже административное восстановление (удалили данные час назад — откатимся на 10:58), но опирается на тот же WAL, что и crash recovery.
Практика: Резервное копирование PostgreSQL, раздел про PITR в 3-08/2.
Что должен знать разработчик (не только DBA)
- Короткие транзакции — меньше окно "висящих" незавершённых изменений.
- Не глотать ошибки после
BEGIN— иначе соединение вернётся в пул с незавершённой транзакцией. - Идемпотентность при повторе запроса после сбоя сети — клиент мог на сервере commit уже в WAL.
- Понимать, что реплика и бэкап — дополнение, а не замена WAL на primary.
Повреждение данных и сбой процесса
Crash recovery предполагает, что файлы на диске целы, а RAM потеряна. Если повреждена страница на диске (битый сектор, ручная правка файла), движок может не подняться — нужны бэкап, реплика, иногда pg_checksums и восстановление из копии. Это снова аргумент в пользу правила 12 Кодда: не субвертировать файлы БД в обход СУБД.
Сколько длится recovery и от чего зависит
После аварии администратор видит в логе "database system was not properly shut down; automatic recovery in progress". Время зависит от:
- объёма WAL с момента последнего checkpoint;
- скорости диска (random I/O при redo);
- числа затронутых страниц.
Профилактика — регулярные checkpoint, мониторинг размера WAL, не копить гигантские незакоммиченные транзакции (раздувают undo/MVCC и окно recovery).
Контрольные вопросы
- Почему
COMMITне означает "все страницы таблицы уже записаны на диск"? - Чем redo отличается от undo при старте после сбоя?
- Зачем нужен checkpoint, если WAL всё равно есть?
- Чем crash recovery отличается от восстановления из
pg_dump? - Что настраивает
synchronous_commitи почему это важно для бизнеса? - Почему реплика не спасает от случайного
DROP TABLE?
См. также
- Теоретические основы реляционных данных — WAL и страницы
- Конкурентный доступ — durability и транзакции
- Резервное копирование PostgreSQL
- Управление реляционными СУБД — стратегии бэкапа и RPO/RTO