«Никакие изменения в данных на диске не должны происходить, пока запись об этом изменении не сохранена в WAL».

сначала пишем лог, потом — данные

Этот принцип гарантирует ACID-свойство Durability (долговечность): даже при аварийном отключении питания СУБД сможет восстановить все зафиксированные транзакции.

  • WAL — это последовательность файлов в каталоге pg_wal/ (в старых версиях — pg_xlog/).

  • Каждый файл имеет размер 16 МБ (по умолчанию) и имя вида: 000000010000000000000001 это LSN (Log Sequence Number) в шестнадцатеричном виде

  • WAL состоит из записей (WAL records), каждая из которых описывает одно атомарное изменение:

    • Вставка/удаление строки,
    • Обновление индекса,
    • Создание таблицы,
    • Изменение системного каталога,
    • Даже VACUUM и CHECKPOINT.

Пример WAL-записи:
«На странице 123 файла таблицы 16450 замени 8 байт, начиная со смещения 456, на такие-то данные».

А на диске:

ls -lh $PGDATA/pg_wal/
# Видны файлы по 16 МБ

Как WAL используется при записи данных?

Рассмотрим UPDATE accounts SET balance = 100 WHERE id = 1;:

  1. Backend формирует WAL-запись, описывающую изменение.
  2. Пишет её в wal_buffers (буфер WAL в shared memory).
  3. Изменяет страницу в shared_buffers (теперь она «грязная»).
  4. При COMMIT (если synchronous_commit = on):
    • Выполняется fsync() — WAL-запись гарантированно сбрасывается на диск (pg_wal/).
    • Только после этого клиент получает подтверждение COMMIT.
  5. Сама изменённая страница (shared_buffers) может быть сброшена на диск позже — например, background writer или checkpointer.

Благодаря WAL:
даже если сервер упадёт сразу после COMMIT, но до сброса страницы на диск — при перезапуске PostgreSQL прочитает WAL и восстановит изменение.


Восстановление после сбоя (Crash Recovery)

При старте после аварии:

  1. PostgreSQL читает последнюю контрольную точку (checkpoint) из pg_control.
  2. Находит соответствующий WAL-файл.
  3. Проигрывает (replay) все WAL-записи от точки checkpoint’а до конца.
    • Все зафиксированные транзакции — применяются (REDO).
    • Все незафиксированные — откатываются (UNDO через специальные записи или CLOG).
  4. Система возвращается в согласованное состояние.

WAL и репликация

  • Primary сервер записывает WAL.
  • WAL sender процесс отправляет WAL-записи по сети.
  • Standby сервер получает их через WAL receiver и применяет локально.
  • Результат: точная копия данных на реплике.

Это позволяет делать:

  • Hot Standby (чтение с реплики),
  • Automatic failover,
  • Point-in-Time Recovery (PITR).
КомпонентРоль
BackendПишет WAL-записи в wal_buffers при изменениях
WAL writerАсинхронно сбрасывает wal_buffers на диск (pg_wal/)
CheckpointerПишет запись CHECKPOINT в WAL; позволяет удалять старые WAL-файлы
WAL sender / WAL receiverПередача WAL между серверами (репликация)
wal_buffersБуфер WAL в shared memory (по умолчанию — 1/32 от shared_buffers, минимум 64 КБ)
XLogCtlГлобальное состояние WAL в shared memory: insert LSN, write LSN, flush LSN
pg_wal/Каталог с WAL-файлами на диске
pg_controlСлужебный файл с метаданными: LSN последнего checkpoint’а, состояние кластера

Ограничения и нюансы

  • WAL не сжимается (в стандартном PostgreSQL).
  • При высокой нагрузке на запись — диск для WAL должен быть быстрым (лучше SSD, отдельный от данных).
  • Если не настроена архивация или репликация — старые WAL-файлы удаляются автоматически.
  • При synchronous_commit = off возможна потеря последних транзакций при сбое.