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

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

Разработчику Архитектору Инженеру

Две разные истории, которые новички смешивают

Фраза «восстановить базу» в разговоре означает две разные задачи. Их путают — и тогда ждут от pg_dump того, что делает WAL при перезагрузке, или наоборот.

ЗадачаТипичный вопросКто решаетГде в энциклопедии
Восстановление после сбояСервер упал / выдернули питание — поднимется ли БД сама?Движок СУБД (WAL, redo/undo)эта глава
Восстановление из резервной копииУдалили таблицу / сгорел диск — как вернуть данные?DBA, pg_dump, PITR106, Управление РСУБД

Аналогия. Crash recovery — как если вы выключили Word без сохранения, а программа при следующем запуске сама подтянула автосохранение из служебного журнала. Бэкап — как копия всего документа на флешке вчера: если сгорел ноутбук, журнал Word уже не поможет.

Обе темы важны. Бэкап без понимания WAL — неясно, до какого момента времени можно откатиться (RPO). WAL без бэкапа — после уничтожения диска журнал на том же диске тоже пропал.

В теоретических основах мы уже упоминали Write-Ahead Logging (WAL): сначала запись в журнал, потом — в файлы таблиц. Здесь развернём цепочку: checkpoint → redo → undo и пройдём сценарий «упал сервер — подняли снова».

Термины главы

ТерминПростыми словами
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».

Подробнее про транзакции: 77.md.


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

Данные в таблицах лежат страницами (часто 8 КБ) — см. 4.md и 3.md. Активная работа идёт в буферном пуле (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

Эта глава — про первый вид. 106.md — про второй и третий.


Репликация и 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?

См. также


См. также

Другие статьи этого же раздела в боковом меню (как на странице «О разделе»).