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

Суть протокола WAL одной фразой

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

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

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

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

Жизненный цикл транзакции с точки зрения журнала

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

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

Для наблюдательного инженера характер коммита виден непосредственно: всплеск записи в журнальный файл на каждый commit, то задержка fsync на дисковом стеке. Транзакционные системы на медленных дисках упираются именно в эту операцию, и настройки групповой фиксации, где несколько коммитов сбрасываются одним fsync, существуют для экономии на этом узком участке.

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

Контрольные точки и зачем они нужны

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

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

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

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

Знание механики точек помогает объяснять странные явления: внезапные всплески нагрузки после долгого простоя это типично встречающийся эффект первой контрольной точки после разгона, когда вся скопившаяся грязь уходит на диск одномоментной волной.

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

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

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

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

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

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

Производительность журнала и борьба за дисковую полосу

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

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

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

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

Групповая фиксация, асинхронный commit и компромиссы долговечности

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

Существуют режимы ослабленной долговечности: асинхронный коммит возвращает успех, не дожидаясь сброса журнала. Выигрыш в латентности значителен, цена это окно потери последних транзакций при сбое. Такие режимы легальны для нагрузок, где потеря секунд допустима, и запрещены для финансовых регистров. Выбор принимается с владельцем продукта явно, а не по умолчанию.

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

Контрольный список настройки долговечности содержит ровно осознанные решения:

  1. Подтвердить, что сброс журнала доходит до энергонезависимого носителя на реальном железе стойки;
  2. Настроить групповую фиксацию согласно с загрузкой и лимитом задержки коммитов;
  3. Задокументировать выбор синхронного или асинхронного режима с оценкой допустимых потерь;
  4. Периодически проверять репетицией восстановления, что журнал читается и применяется корректно.

WAL за пределами классической базы

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

Репликация это второе гражданство журнала. Записи журнала не только оживляют локальную базу после сбоя, но и стримятся на реплики, где применяются в том же порядке, порождая точную копию. Запаздывание реплики измеряется по LSN, а согласованность кластеров строится на кворумной фиксации журнальных записей.

Журнал становится и источником интеграционных событий: системы CDC читают записи WAL как поток изменений и питают ими аналитические витрины, поисковые индексы и всевозможные подписчиков. Так журнал, изобретённый для надёжности, стал шиной данных целых архитектур.

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