АрхитектураАрхитектура данныхИнженер по базам данных

После сбоя транзакционная СУБД подтверждила запись, но не успела перенести изменённые страницы таблиц на ди...

После сбоя транзакционная СУБД подтверждила запись, но не успела перенести изменённые страницы таблиц на диск. Какой механизм позволяет восстановить подтверждённое состояние?

Проходите собеседования с ИИ помощником Hintsage

Краткий ответ

Это обеспечивает журнал предзаписи, или WAL (Write-Ahead Logging). Сначала сведения об изменении и фиксации транзакции надёжно записываются в журнал, а страницы таблиц могут быть сброшены на диск позже. После сбоя СУБД анализирует журнал и повторно применяет подтверждённые изменения к страницам данных.

Исторический контекст

При изменении данных СУБД обычно работает не непосредственно с дисковыми страницами, а с их копиями в оперативной памяти. Запись изменённых страниц на диск может происходить позже, поэтому сбой между фиксацией транзакции и записью страниц создаёт риск потери подтверждённых данных.

WAL появился как способ отделить момент подтверждения транзакции от момента физической записи всех изменённых страниц. Это позволяет сочетать высокую производительность буферизации с требованием долговечности транзакций.

Постановка проблемы

Предположим, транзакция изменила остаток товара и была подтверждена клиенту, но изменённая страница ещё находится только в памяти. Если питание пропало, после перезапуска на диске останется старое значение.

Без журнала СУБД не сможет надёжно определить, какие операции были завершены, какие выполнялись в момент сбоя, а какие страницы содержат неполные изменения. Неверное решение может привести как к потере подтверждённых данных, так и к сохранению незавершённых изменений.

Подробное решение

При изменении страницы СУБД формирует запись WAL, содержащую сведения, достаточные для восстановления: идентификатор страницы или объекта, новую версию изменения либо информацию для её получения, а также идентификатор транзакции. До подтверждения транзакции соответствующая запись журнала должна попасть в устойчивое хранилище; это правило называется write-ahead.

Изменённые страницы данных можно записать позже. После сбоя СУБД выполняет восстановление: анализирует журнал, определяет состояние транзакций, повторно применяет изменения подтверждённых транзакций (redo) и устраняет эффект незавершённых транзакций (undo либо откат через обратные записи — конкретная реализация зависит от СУБД).

Контрольные точки периодически фиксируют согласованное состояние части данных и сокращают объём журнала, который нужно просматривать при восстановлении. Они не отменяют WAL: до записи изменённой страницы журнал всё равно должен быть устойчиво сохранён.

Гарантия зависит от настройки долговечности. Если СУБД подтверждает транзакцию до сброса журнала из буферов операционной системы или накопителя, физический отказ может привести к потере последних подтверждений. Поэтому важны корректная синхронизация журнала, надёжность диска и понимание того, какие сбои входят в модель отказа.

WAL не равен резервному копированию и не гарантирует сохранность данных при полном уничтожении хранилища. Он также не заменяет репликацию: реплика может использовать журнал для доставки изменений, но для защиты от отказа узла нужны дополнительные механизмы.

Главный компромисс — задержка подтверждения. Чем строже требование к устойчивости записи журнала, тем выше потенциальная стоимость операции фиксации. Ослабление этого требования может повысить производительность, но уменьшает гарантию сохранности последних транзакций.

Ситуация из практики

Платёжный сервис после подтверждения платежа обновляет баланс и отвечает клиенту. При нагрузочном тесте разработчики заметили, что принудительная запись всех изменённых страниц перед каждым ответом резко увеличивает задержку.

Рассматривались два варианта. Синхронно записывать все страницы данных проще для понимания, но это создаёт много случайных операций ввода-вывода. Подтверждать транзакцию только после записи WAL быстрее, поскольку журнал обычно компактнее и записывается последовательно, однако требуется надёжный механизм сброса журнала и корректная процедура восстановления.

Выбрали WAL с синхронной фиксацией журнала, отложенной записью страниц и регулярными контрольными точками. После имитации сбоя СУБД восстановила подтверждённые платежи из журнала, а незавершённые транзакции не повлияли на баланс. Такой вариант сохранил требуемую долговечность без необходимости немедленно сбрасывать все страницы данных.

Что кандидаты часто упускают

  1. Достаточно ли наличия WAL, если транзакция подтверждается до физической записи журнала?

Нет. Сам факт существования записи в журнале в оперативной памяти ещё не обеспечивает долговечность. Для гарантии подтверждённая транзакция должна дождаться переноса нужной части журнала в устойчивое хранилище, а надёжность этой операции зависит от настроек СУБД, операционной системы и накопителя.

Если журнал остаётся только в энергозависимом кэше, сбой питания может уничтожить и данные, и журнал. Поэтому при анализе гарантии нужно уточнять режим фиксации, свойства диска и допустимую модель отказа.

  1. Зачем нужны контрольные точки, если журнал уже содержит все изменения?

Без контрольных точек восстановление пришлось бы начинать с очень старого места журнала. СУБД должна была бы просмотреть большой объём записей и применить множество операций, даже если большинство страниц данных уже актуальны.

Контрольная точка отмечает момент, до которого определённая часть изменений согласованно отражена в файлах данных. После неё восстановление обычно может ограничиться более коротким диапазоном журнала. Цена — дополнительная нагрузка при записи страниц и возможные пики ввода-вывода.

  1. Почему WAL не гарантирует, что другая СУБД немедленно увидит подтверждённую запись?

WAL прежде всего обеспечивает восстановление локального экземпляра и долговечность его состояния. Видимость данных на реплике зависит от доставки, записи и применения журнала на реплике, поэтому между узлами может существовать задержка.

Если приложению нужна гарантия чтения именно подтверждённого значения после записи, одной локальной фиксации недостаточно. Нужно выбрать подходящую модель репликации и чтения, например дождаться подтверждения нужных реплик или читать с узла, для которого выполнено требуемое условие согласованности.