Logo Craft Homelab Docs Контакты Telegram
Write-ahead logging и журналирование — WAL в PostgreSQL
Sun Dec 28 2025

Write-Ahead Logging: надёжность баз данных

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

Концепция

WAL меняет порядок операций для гарантии сохранности данных при сбое.

Традиционный подход:
1. Изменить данные на диске
2. Записать в лог

WAL:
1. Записать в лог (WAL)
2. Изменить данные на диске

Преимущество: лог записывается последовательно (быстро), данные могут записываться в любом порядке. При сбое можно восстановить состояние из лога.

Структура WAL

┌────────────────────────────────┐
│            WAL Segment         │
├────────────────────────────────┤
│ Header (checkpoint, segno)     │
├────────────────────────────────┤
│ XLOG Record 1:                 │
│   - LSN (Log Sequence Number)  │
│   - prev LSN                   │
│   - Transaction ID             │
│   - redo/undo                  │
│   - Page data                  │
├────────────────────────────────┤
│ XLOG Record 2:                 │
│   ...                          │
└────────────────────────────────┘

PostgreSQL WAL

-- Проверка WAL
SELECT pg_current_wal_lsn();

-- Checkpoint
CHECKPOINT;

-- Настройка
ALTER SYSTEM SET wal_level = 'replica';
ALTER SYSTEM SET max_wal_size = '1GB';

Восстановление

WAL позволяет восстанавливать базу данных до точки во времени (point-in-time recovery):

# Восстановление до точки во времени
pg_restore -h localhost -d mydb backup.dump

# Восстановление из WAL
restore_command = 'cp /archive/%f %p'
recovery_target_time = '2025-01-01 00:00:00'

SQLite WAL

-- Включить WAL mode
PRAGMA journal_mode = WAL;

-- Synchronous режим
PRAGMA synchronous = NORMAL;  # 0=off, 1=normal, 2=full, 3=extra

-- Checkpoint
PRAGMA wal_checkpoint(TRUNCATE);

Уровни durability

// SQLite sync modes
// NORMAL: fsync() только для commit record
// FULL: fsync() для каждой записи (безопаснее, медленнее)
// EXTRA: ещё один fsync() (самый безопасный)

Реализация в приложении

// Простой WAL на Node.js
const fs = require('fs');
const path = require('path');

class WAL {
  constructor(dir) {
    this.dir = dir;
    this.currentFile = 0;
    this.buffer = [];
  }
  
  async append(record) {
    // Добавить в буфер
    this.buffer.push({
      lsn: this.getNextLSN(),
      timestamp: Date.now(),
      data: record
    });
    
    // Флюш в файл при накоплении
    if (this.buffer.length >= 100) {
      await this.flush();
    }
  }
  
  async flush() {
    const filepath = path.join(this.dir, `wal-${this.currentFile}.log`);
    const data = this.buffer.map(b => JSON.stringify(b)).join('\n');
    await fs.promises.appendFile(filepath, data + '\n');
    this.buffer = [];
  }
}

ARIES

Algorithm for Recovery and Isolation Exploiting Semantics — алгоритм WAL в IBM DB2, Oracle, SQL Server.

Компоненты

  1. Log Sequence Number (LSN) — уникальный ID записи
  2. Transaction Table — активные транзакции
  3. Dirty Page Table — модифицированные страницы

Фазы восстановления

  1. Analysis — определить точку восстановления
  2. Redo — проигрывание лога вперёд
  3. Undo — откат незакоммиченных транзакций

Performance considerations

Batch commits

// Вместо записи на каждый запрос
await db.query('BEGIN');
for (const op of operations) {
  await db.query(op);  // не пишет в WAL сразу
}
await db.query('COMMIT');  // один fsync

WAL shipping

-- PostgreSQL репликация через WAL
-- Master
ALTER SYSTEM SET synchronous_standby_names = 'replica1';

-- Standby
recovery_target_timeline = 'latest'

Заключение

WAL — основа надёжности БД. Понимание принципов помогает правильно настраивать и оптимизировать базы данных.