WAL: журнал опережающей записи
WAL: журнал опережающей записи
WAL (write-ahead log, журнал опережающей записи) — способ фиксировать изменения базы сначала в отдельном журнале, а уже потом переносить их в основной файл. В SQLite это позволяет читателям продолжать видеть согласованный снимок данных, пока другая транзакция записывает новые изменения.
История
Идея опережающей записи возникла не в SQLite: журналы восстановления давно применяются в системах управления базами данных. Если работа прервалась, журнал позволяет выяснить, какие операции успели завершиться, и восстановить согласованное состояние. Ключевой принцип write-ahead logging: информацию, необходимую для восстановления, записывают до того, как считают соответствующее изменение базы устойчивым.
SQLite появилась в 2000 году. Её создал Д. Ричард Хипп (D. Richard Hipp); впоследствии она стала самостоятельной встраиваемой базой данных. Изначально SQLite применяла rollback journal (журнал отката): до изменения основного файла сохраняла прежние версии страниц, чтобы при незавершённой транзакции можно было вернуться назад. Это решало задачу восстановления, но читатели и писатель иногда мешали друг другу.
Режим WAL появился в SQLite 3.7.0 в 2010 году. Новые версии страниц стали дописываться в журнал, а основной файл обновляться позже. Так запросы чтения смогли чаще выполняться параллельно с записью. Дальнейшее развитие касалось, в частности, checkpoint (контрольной точки), управления блокировками и восстановления после прерывания. WAL сейчас является режимом журналирования SQLite, а не отдельной базой или сервером.
Что это такое
Основной файл SQLite содержит страницы таблиц и индексов. Когда транзакция меняет данные в режиме WAL, новые версии страниц сначала попадают в соседний файл журнала. Изменение считается видимым новым читателям после фиксации транзакции. Позднее checkpoint переносит накопленное из журнала в основной файл. Поэтому подтверждённые изменения не обязаны немедленно появляться в самом файле базы.
Зачем это полезно? Читателю нужна стабильная картина данных на протяжении операции, а писателю нужно сохранить обновления. WAL позволяет читателю продолжать читать прежний согласованный снимок, пока писатель добавляет новые страницы в конец журнала. Следующее чтение после фиксации записи может получить более свежий снимок. Это улучшает совместную работу операций разных типов без необходимости превращать SQLite в сетевой сервер.
Но «читатели не блокируют писателей» — полезное упрощение, а не обещание отсутствия любых конфликтов. Параллельно может работать только одна транзакция записи; другие писатели ждут или получают ошибку занятости. Долгие читатели могут мешать очистке WAL. В SQLite существуют ограничения для конкретных транзакций, запросов, файловых систем и соединений: режим не следует включать только потому, что название звучит быстрее.
WAL отличается от rollback journal направлением сохранения изменений. Rollback journal хранит данные для отмены незавершённой записи в основной файл. WAL хранит новые версии для последующего переноса в основной файл. Оба режима помогают обеспечивать атомарность транзакций; ни один не подменяет резервное копирование, управление доступом или синхронизацию с удалённым сервером.
Аналогии из жизни
Черновик изменений к книге. Редактор фиксирует правки отдельно, пока читатели пользуются прежним изданием; позднее правки попадают в основной экземпляр. Аналогия объясняет отдельное хранение новых страниц до checkpoint. Где ломается: журнал не является свободным текстом предложений, а читатели SQLite могут увидеть зафиксированные изменения до переноса в основной файл.
Кассовая лента. Покупки последовательно печатаются на ленте, а итоговые остатки обновляются позже. Если компьютер выключился, записи помогают восстановить произошедшее. Это показывает ценность журнала при сбое. Где ломается: обычная лента сама по себе не гарантирует атомарность нескольких операций и согласованные снимки для параллельных читателей.
Входящая почта. Новые письма поступают во входящий ящик, пока сотрудники читают уже рассортированные материалы; затем накопившееся разносят по папкам. Аналогия показывает разделение поступления и переноса изменений. Где ломается: WAL не ждёт «разбора всей почты», чтобы новые читатели увидели зафиксированную транзакцию; каждая операция чтения работает с определённым снимком.
Как это работает
Упрощённо рядом с app.db при использовании WAL могут появиться app.db-wal и app.db-shm. Первый файл содержит саму базу, второй — новые версии страниц, третий помогает соединениям координировать чтение журнала. Приложение не должно вручную менять эти служебные файлы: их жизненным циклом управляет SQLite.
- Писатель начинает транзакцию, получает доступ к записи и изменяет необходимые страницы. SQLite следит, чтобы другая запись не смешалась с текущей.
- Новые страницы попадают в WAL. В конце транзакции записывается отметка commit (фиксации). Пока её нет, незавершённые изменения не должны стать подтверждённым результатом для других соединений.
- Когда транзакция завершена, новый читатель может читать последние зафиксированные данные из основного файла и WAL. Уже работающий читатель продолжает видеть snapshot (снимок), соответствующий моменту начала его операции.
- Checkpoint переносит подходящие страницы журнала в основной файл. Это отдельная внутренняя работа, которая не меняет смысла пользовательских транзакций.
- Когда старые версии больше никому не нужны, журнал можно переиспользовать, сбросить или усечь в зависимости от режима checkpoint и состояния соединений.
Представь, что чтение началось в 10:00, а запись завершилась в 10:01. У начатого раньше чтения остаётся прежний согласованный снимок. Новое чтение после commit уже может увидеть изменения. Это свойство помогает не получить половину старого и половину нового результата. Границы транзакций важнее того, сколько миллисекунд прошло между запросами.
читатель: снимок A --------------------- завершение
писатель: запись WAL -> commit -> checkpoint
файл базы: версия A --------------> версия B
Checkpoint может запускаться автоматически по порогу накопленного WAL или явно приложением. Если читатель долго держит старый снимок, checkpoint не всегда может завершить работу и освободить все старые версии: файл WAL растёт. Поэтому полезно наблюдать за его размером и временем жизни транзакций, а не просто принудительно удалять служебные файлы.
Настройка synchronous задаёт компромисс между скоростью и сохранностью подтверждённых данных при внезапном отключении питания. В режиме WAL значение FULL предусматривает синхронизацию журнала при commit; NORMAL уменьшает число таких операций и сохраняет целостность базы, но последние подтверждённые транзакции могут потеряться при отказе питания. Фактические гарантии зависят также от устройства и ОС.
PRAGMA journal_mode = WAL;
После этой команды проверь возвращённый режим: запрос показывает, удалось ли его установить. Если ожидается конкуренция за запись, продумай обработку SQLITE_BUSY и busy_timeout; таймаут позволяет подождать освобождения блокировки, но не делает параллельные записи возможными. Открытые соединения следует корректно закрывать, а транзакции — завершать без неоправданных пауз.
Где встречается в обычной жизни
- Приложение заметок сохраняет локальные изменения, пока экран перечитывает список заметок. SQLite с WAL может помогать этим действиям не мешать друг другу.
- Мобильная программа обновляет локальную историю в фоне, а пользователь листает сохранённые записи. Если она использует SQLite в режиме WAL, чтение может продолжаться на прежнем снимке.
- Настольное приложение после сбоя запускается снова: журнал позволяет базе восстановить согласованное состояние. Это не значит, что WAL заменяет резервную копию.
- Офлайн-приложение сохраняет данные на устройстве перед последующей синхронизацией. WAL относится к локальной базе, а не к протоколу обмена с сервером.
Пользователь обычно не видит WAL напрямую. Соседний с базой файл -wal сам по себе не является признаком повреждения: при активной работе он ожидаем.
Где встречается в IT и бизнесе
- Встраиваемые приложения. Локальная база без отдельного сервера подходит для настроек, каталогов и истории; WAL полезен, когда чтение и запись пересекаются.
- Внутренние сервисы. Агент или небольшая служба может читать состояние из нескольких потоков и периодически записывать изменения. Если писателей много, нужно измерить задержки и очередь записи.
- Локальные очереди. SQLite может хранить задания до обработки. WAL помогает работе базы, но защиту от двойной обработки и правила подтверждения заданий проектируют отдельно.
- Тестовые стенды. Проверка на SQLite удобна, однако режим WAL не устраняет различий с серверной СУБД. Одновременные операции записи важно тестировать отдельно.
- Резервное копирование. При активной базе нельзя считать, что вся актуальная информация уже в
app.db. Используй документированный механизм SQLite Online Backup API либо другую штатную процедуру согласованного копирования.
Кто пользуется
SQLite широко применяется в браузерах, мобильных и настольных приложениях, а также во встраиваемом ПО. Однако наличие SQLite у конкретного продукта не доказывает, что он включил именно WAL: режим зависит от настроек приложения. Поэтому было бы неверно приписывать всем пользователям SQLite работу именно с этим журналом.
Универсальной цифры «сколько запросов в секунду выдерживает WAL» нет. Пропускная способность зависит от размера транзакций, скорости хранилища, частоты синхронизаций, количества писателей и продолжительности чтения. Для решения о внедрении нужны измерения на устройстве и нагрузке, похожих на настоящие.
Альтернативы и конкуренты
- Rollback journal в SQLite. Плюс: другой стандартный механизм транзакций, удобный для ряда файловых сценариев. Минус: читатели и писатель чаще мешают друг другу.
- PostgreSQL. Плюс: серверная система для многих клиентов и сложных конкурентных нагрузок. Минус: требует обслуживания сервера и сети; для маленькой локальной базы это может быть избыточно.
- Другая встраиваемая база. Плюс: может лучше подходить конкретному формату или рабочей нагрузке. Минус: отличаются запросы, миграция, поддержка и правила восстановления.
- Простые файлы. Плюс: понятное хранение очень небольшого объёма настроек. Минус: конкурентная запись, поиск и атомарность быстро становятся проблемой самого приложения.
Когда НЕ стоит использовать
- Если база размещена на сетевой файловой системе, сначала изучи ограничения SQLite. Координация WAL через общую память рассчитана на процессы одного компьютера; произвольное сетевое хранилище не подходит.
- Если требуется много одновременно пишущих клиентов, WAL не отменит единственного писателя. Серверная СУБД может соответствовать требованиям лучше.
- Если резервное копирование устроено как копирование одного файла при работающей базе, сначала исправь процедуру. Подтверждённые изменения могут ещё оставаться в WAL.
- Если чтения держат транзакции открытыми часами, устрани долгие снимки: они могут мешать checkpoint и увеличивать журнал независимо от скорости записи.
Связанные понятия
- Транзакция — операции, которые фиксируются как единое целое или отменяются.
- Checkpoint — перенос данных из WAL в основной файл базы.
- Снимок данных — согласованная версия, с которой работает начатое чтение.
- Rollback journal — способ сохранять информацию для отката незавершённых изменений.
- ACID — свойства транзакций: атомарность, согласованность, изоляция и долговечность.
- SQLite — встраиваемая реляционная база данных без отдельного серверного процесса.
Литература и источники
- SQLite, «Write-Ahead Logging»: https://sqlite.org/wal.html
- SQLite, «PRAGMA journal_mode»: https://sqlite.org/pragma.html#pragma_journal_mode
- SQLite, «Online Backup API»: https://sqlite.org/backup.html
- SQLite, «Atomic Commit»: https://sqlite.org/atomiccommit.html
- SQLite, «Appropriate Uses For SQLite»: https://sqlite.org/whentouse.html
Где встретилось у меня
Понятие возникло при обсуждении хранения состояния в локальной базе и одновременного обслуживания операций чтения и записи. Контекст за вчера частично обрезан системным маркером, поэтому тема выбрана только по доступным записям.
Краткое резюме
- WAL записывает новые версии страниц в журнал, а позже переносит их в основной файл.
- Читатели и один писатель часто могут работать одновременно; нескольких одновременных писателей WAL не даёт.
- Долгие снимки задерживают checkpoint и могут увеличить WAL.
- Журнал не заменяет резервную копию; копируй активную базу документированными средствами.
- Выбор режима зависит от файловой системы, конкуренции и требований к сохранности данных.