Перейти к основному содержимому

Восстановление после сбоя

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'и.

RPO в SLA

Формулировки в контракте ("не более 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): любое изменение, которое должно пережить сбой, сначала записывается в журнал (последовательный файл, только дописывание в конец), и потом (может быть через секунды) отражается в файлах таблиц на диске.

Зачем так делают:

  1. Скорость — дописать в конец одного файла журнала дешевле, чем искать случайные страницы по всем таблицам.
  2. Надёжность — при обрыве питания на диске в журнале уже есть "мы списали 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 (упрощённо):

  1. В WAL записано: "изменение balance на счёте 1".
  2. В WAL записано: "COMMIT транзакции № 12345".
  3. WAL сброшен на диск (fsync) — буква D (Durability) из ACID.
  4. Страница таблицы accounts может ещё жить только в RAM — это нормально.

Значит: commit ≠ "всё уже на диске в файле таблицы". Commit = "запись о результате не потеряется при сбое, потому что она в WAL".

Подробнее про транзакции: Транзакции, изоляция и блокировки.


Страницы в памяти и на диске

Данные в таблицах лежат страницами (часто 8 КБ) — см. Теоретические основы реляционных данных и Внутреннее устройство баз данных. Активная работа идёт в буферном пуле (RAM):

  1. транзакция меняет строку → меняется копия страницы в RAM;
  2. в WAL пишется запись "что изменилось";
  3. страница помечается "грязной" (dirty);
  4. позже фоновый процесс сбрасывает грязные страницы на диск — не обязательно до 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 (упрощённо):

  1. Изменения записаны в WAL-буфер.
  2. При COMMIT — сброс WAL на диск (wal_write, fsync в зависимости от synchronous_commit).
  3. Клиент получает "OK".
  4. Страницы таблиц могут всё ещё быть только в 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 восстановления — администрирование.


Сценарий по шагам

  1. Транзакция списала 100 ₽ — WAL записан, COMMIT в WAL есть.
  2. Страница accounts всё ещё только в RAM.
  3. Сбой — RAM пуста, на диске старая страница без списания.
  4. Старт PostgreSQL — redo проигрывает WAL → страница на диске с списанием.
  5. Другая транзакция без COMMITundo / откат её эффектов.

Пользователь после рестарта видит согласованные данные; приложение может переподключиться.


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).


Контрольные вопросы

  1. Почему COMMIT не означает "все страницы таблицы уже записаны на диск"?
  2. Чем redo отличается от undo при старте после сбоя?
  3. Зачем нужен checkpoint, если WAL всё равно есть?
  4. Чем crash recovery отличается от восстановления из pg_dump?
  5. Что настраивает synchronous_commit и почему это важно для бизнеса?
  6. Почему реплика не спасает от случайного DROP TABLE?

См. также