LabHub

블로그

Write-Ahead Logging 완전 가이드 2025: ARIES 복구, PostgreSQL WAL, InnoDB Redo Log, 체크포인트, 내결함성 심층 분석

들어가며: 데이터베이스가 절대 잊지 않는 비결

한 가지 질문으로 시작하자

당신의 은행 앱에서 10만 원을 송금한다. "송금 완료"가 화면에 뜬 순간, 데이터베이스 서버가 전원 차단된다. 서버가 재부팅된 후, 그 10만 원은 어떻게 될까?

답: 사라지지 않는다. 왜냐하면 데이터베이스는 "내가 커밋했다고 말한 순간" 을 절대 잊지 않기 때문이다.

그 마법의 정체가 바로 Write-Ahead Logging (WAL) 이다.

단순한 아이디어, 엄청난 결과

WAL의 핵심 원칙은 단 한 줄로 요약된다:

"데이터 파일에 변경을 적용하기 전에, 그 변경을 로그에 먼저 기록한다."

이 단순한 규칙에서 다음이 파생된다:

이 글에서는 WAL이 필요한지, 어떻게 동작하는지, 그리고 PostgreSQL과 InnoDB에서 실제로 어떻게 구현되었는지 깊이 들여다본다.


1. WAL이 없던 시절: Shadow Paging

초기 접근법

WAL이 표준화되기 전, 데이터베이스는 Shadow Paging 같은 기법을 썼다:

  1. 페이지를 수정할 때 원본을 그대로 두고 새 페이지를 할당.
  2. 새 페이지에 변경 내용 쓰기.
  3. 트랜잭션 커밋 시 페이지 테이블을 원자적으로 교체.
  4. 장애 시 그냥 구 페이지 테이블로 되돌리면 됨.

왜 실패했는가?

Shadow Paging은 개념적으로 우아하지만 치명적 단점이 있었다:

System R(IBM, 1970년대)과 초기 DB들이 Shadow Paging을 시도했다가 결국 WAL로 돌아섰다.

WAL의 등장

1970년대 후반 IBM의 연구진이 WAL을 공식화했고, 1992년 Mohan 등의 ARIES 논문이 현대 WAL의 표준이 되었다. ARIES는 지금도 거의 모든 RDBMS의 근간이다.


2. WAL의 기본 원리

두 가지 규칙

WAL은 두 가지 단순한 규칙으로 정의된다:

규칙 1 (WAL Rule):

데이터 페이지를 디스크에 쓰기 전에, 해당 변경의 로그 레코드가 먼저 디스크에 flush 되어야 한다.

규칙 2 (Force-at-Commit):

트랜잭션이 커밋된 것으로 간주되기 전에, 그 트랜잭션의 모든 로그 레코드가 디스크에 flush 되어야 한다.

이 두 규칙만 지키면 어떤 장애 시점에서도 일관된 상태로 복구할 수 있다.

로그 레코드 구조

전형적인 WAL 레코드는 다음을 포함한다:

LogRecord {
    LSN          : 로그 시퀀스 번호 (단조 증가)
    PrevLSN      : 같은 트랜잭션의 이전 레코드 LSN
    TransactionID: 트랜잭션 식별자
    Type         : UPDATE, INSERT, DELETE, COMMIT, ABORT, CHECKPOINT...
    PageID       : 영향받은 페이지
    Before       : 변경 전 이미지 (undo 정보)
    After        : 변경 후 이미지 (redo 정보)
}

LSN (Log Sequence Number) 이 핵심이다. LSN은 로그 파일 내 바이트 오프셋에 가까운 개념으로, 한 번 부여되면 절대 재사용되지 않는다.

페이지 LSN

각 데이터 페이지도 pageLSN 을 저장한다: 이 페이지에 가장 최근에 적용된 로그 레코드의 LSN. 복구 중에 "이 변경이 이미 적용됐나?"를 판단하는 데 쓰인다.

if pageLSN >= logRecord.LSN:
    이미 적용됨 → 건너뛰기
else:
    다시 적용 (redo)

3. ARIES: 현대 WAL의 표준

ARIES의 세 가지 원칙

1992년 IBM 연구소의 C. Mohan 등이 발표한 ARIES (Algorithms for Recovery and Isolation Exploiting Semantics) 는 세 가지 원칙을 중심으로 한다:

  1. Write-Ahead Logging: 위에서 설명한 두 규칙.
  2. Repeating History During Redo: 복구 시 모든 변경(커밋 여부와 무관)을 재적용.
  3. Logging Changes During Undo: 롤백도 로그 레코드로 기록해서 재귀적 복구 지원.

3단계 복구 프로토콜

장애 후 데이터베이스가 시작될 때, ARIES는 세 단계로 복구한다:

┌──────────────┐    ┌──────────────┐    ┌──────────────┐
Analysis   │ →  │     Redo     │ →  │     Undo  (분석 단계)  (재실행)  (취소)└──────────────┘    └──────────────┘    └──────────────┘

Phase 1: Analysis

목적: 장애 시점의 상태를 파악.

  1. 마지막 체크포인트부터 로그를 순방향 스캔.
  2. Dirty Page Table (DPT) 재구성: 장애 시점에 메모리에만 있던 페이지들.
  3. Transaction Table 재구성: 장애 시 진행 중이던 트랜잭션들.
  4. redoLSN 결정: 이 LSN부터 redo 시작.

Phase 2: Redo

목적: 모든 로그 레코드를 재적용해서 장애 직전 상태로 복원.

  1. redoLSN부터 로그 끝까지 순방향 스캔.
  2. 각 로그 레코드에 대해:
    • 해당 페이지를 읽어옴.
    • if pageLSN < logRecord.LSN → 변경 적용, pageLSN 갱신.
    • 이미 적용됐으면 건너뛰기.
  3. 커밋된 트랜잭션과 커밋되지 않은 트랜잭션 모두의 변경을 재적용.

"왜 커밋 안 된 것까지?" 이는 Phase 3에서 일관되게 undo하기 위해서다.

Phase 3: Undo

목적: 커밋되지 않은 트랜잭션들을 롤백.

  1. Transaction Table에서 loser(미커밋) 트랜잭션 목록 확인.
  2. 각 loser에 대해 역방향으로 로그 따라가며 원상복구.
  3. 각 undo 동작도 CLR (Compensation Log Record) 로 로그에 기록.
  4. 롤백 완료 시 ABORT 레코드 기록.

CLR: 롤백도 로그에 남긴다

CLR(Compensation Log Record)은 ARIES의 영리한 아이디어다. 언뜻 보면 "롤백인데 왜 또 로그에 쓰지?"라는 생각이 들지만:

CLR에는 undoNextLSN 필드가 있어서, 다음에 undo할 LSN을 가리킨다. 롤백을 중간부터 이어갈 수 있다.

체크포인트 (Checkpoint)

로그가 무한히 커질 수 없으므로 주기적으로 체크포인트를 찍는다:

  1. 모든 dirty page를 디스크에 flush.
  2. 현재 활성 트랜잭션 목록과 DPT를 로그에 기록.
  3. 체크포인트 레코드 작성.
  4. 체크포인트 이전의 로그는 (대부분) 버려도 됨.

ARIES의 Fuzzy Checkpoint는 더 영리하다: dirty page flush를 강제하지 않고, 현재 상태의 스냅샷만 기록. 백그라운드에서 flush가 이뤄진다.


4. PostgreSQL WAL 심층 분석

WAL 파일 구조

PostgreSQL의 WAL은 pg_wal 디렉토리(이전에는 pg_xlog)에 저장된다:

$PGDATA/pg_wal/
├── 000000010000000000000001  (16MB)
├── 000000010000000000000002
├── 000000010000000000000003
├── archive_status/
└── ...

각 파일은 기본 16MB 이고, 이름은 TIMELINEID + LOGID + SEGMENT 형식이다. 파일 내부는 8KB 페이지로 나뉘어 있으며, 각 페이지에 여러 WAL 레코드가 담긴다.

주요 WAL 레코드 타입

타입설명
XLOG_HEAP_INSERT새 튜플 삽입
XLOG_HEAP_UPDATE튜플 업데이트 (기존 튜플 xmax + 새 튜플)
XLOG_HEAP_DELETE튜플 삭제 (xmax 설정)
XLOG_BTREE_INSERT_LEAFB-Tree 리프에 키 삽입
XLOG_XACT_COMMIT트랜잭션 커밋
XLOG_XACT_ABORT트랜잭션 롤백
XLOG_CHECKPOINT_ONLINE온라인 체크포인트
XLOG_CHECKPOINT_SHUTDOWN셧다운 체크포인트

Full-Page Write

PostgreSQL의 독특한 기능: Full-Page Write.

문제: 8KB 페이지가 디스크에 쓰이는 도중 장애가 나면(torn page), 디스크에는 일부만 쓰인 페이지가 남는다. OS/디스크 수준에선 4KB 원자성만 보장되기 때문이다.

해결: 체크포인트 직후 첫 번째 수정 때 전체 페이지를 WAL에 기록한다. 이후 수정은 작은 증분만 기록.

-- 기본 활성화 (절대 끄지 마세요)
show full_page_writes;  -- on

이로 인해 WAL 크기가 2~3배 늘어나지만, torn page로 인한 데이터 손상을 막는다. 체크포인트 직후 쓰기 폭주(write storm)의 주요 원인이기도 하다.

fsync와 커밋

트랜잭션 커밋 시 PostgreSQL은:

  1. COMMIT 레코드를 WAL 버퍼에 추가.
  2. WAL 버퍼를 디스크로 fsync.
  3. 클라이언트에 성공 응답.

fsync = off로 설정하면 빠르지만 장애 시 데이터 손실 가능. 절대 프로덕션에서 끄지 마라.

synchronous_commit 설정:

체크포인트 튜닝

체크포인트는 성능에 큰 영향을 준다:

# postgresql.conf
checkpoint_timeout = 15min        # 최대 15분마다
max_wal_size = 4GB                # WAL이 이 크기에 도달하면 체크포인트
min_wal_size = 1GB
checkpoint_completion_target = 0.9  # 체크포인트를 이 비율 동안 분산 실행

Trade-off:

프로덕션에선 보통 timeout 기반 체크포인트가 자연스럽게 되도록 max_wal_size를 넉넉히 잡는다.

WAL과 복제

PostgreSQL의 스트리밍 복제는 WAL을 그대로 복제본에 전송한다:

Primary: WAL 생성 → 네트워크로 전송 → Standby가 재생(redo)

Logical Replication은 조금 다르다: 물리 WAL을 논리적 변경(INSERT/UPDATE/DELETE)으로 디코딩해서 전송. 버전 차이나 선택적 테이블 복제가 가능.

WAL 아카이빙과 PITR

Point-in-Time Recovery(PITR)를 위해선:

  1. 기본 백업 (pg_basebackup)
  2. WAL 아카이빙 (archive_command로 WAL 파일을 S3 등으로 복사)
  3. 장애 시 기본 백업 복원 + WAL 재생으로 원하는 시점까지 복구.
archive_mode = on
archive_command = 'aws s3 cp %p s3://my-bucket/wal/%f'

5. InnoDB의 Redo Log와 Undo Log

두 개의 로그 시스템

InnoDB는 PostgreSQL과 달리 두 종류의 로그를 유지한다:

  1. Redo Log: 변경을 재적용하기 위한 로그 (WAL 역할).
  2. Undo Log: 변경을 취소하기 위한 로그 (MVCC에도 사용).

이는 MVCC 구현이 PostgreSQL과 다르기 때문이다.

Redo Log 구조

InnoDB의 redo log는 고정 크기 원형 파일이다:

ib_logfile0  (기본 48MB, 여러 개 순환)
ib_logfile1

모든 수정이 redo log에 기록된다:

RedoLogRecord {
    type: MLOG_REC_INSERT, MLOG_REC_UPDATE, MLOG_REC_DELETE, ...
    space_id: 테이블스페이스 ID
    page_no: 페이지 번호
    offset: 페이지 내 오프셋
    data: 실제 변경 내용
}

Mini-Transaction (mtr)

InnoDB의 핵심 개념: Mini-Transaction (mtr). 이는 원자적인 페이지 수정 그룹이다.

예를 들어 B-Tree에 키를 삽입하면:

  1. 리프 페이지 수정
  2. 부모 페이지 수정 (split 시)
  3. 헤더 업데이트

이 모두가 하나의 mtr이다. mtr의 로그 레코드들은 원자적으로 flush된다. 복구 시 mtr 단위로 재적용된다.

LSN과 Checkpoint LSN

InnoDB도 LSN을 사용하지만 개념이 조금 다르다:

복구 시 checkpoint_lsn부터 로그를 재생한다.

Sharp vs Fuzzy Checkpoint

InnoDB는 두 종류의 체크포인트를 한다:

Fuzzy checkpoint 덕분에 평상시 성능 영향이 작다.

Undo Log와 Rollback Segment

Undo log는 별도의 세그먼트에 저장된다. 각 트랜잭션 시작 시 rollback segment의 undo slot을 할당받는다.

용도:

  1. 롤백: 트랜잭션 취소 시.
  2. MVCC: 오래된 버전을 조회할 때 undo log를 따라감.
  3. 복구 시 undo: 복구 중 미커밋 트랜잭션 취소.

InnoDB 복구 프로세스

  1. Redo 단계: ib_logfilecheckpoint_lsn부터 읽어 모든 변경 재적용.
  2. Rollback 단계: 커밋되지 않은 트랜잭션들을 undo log로 취소.

이는 ARIES의 Analysis/Redo/Undo 3단계와 동일한 개념이다.

Doublewrite Buffer: InnoDB의 Torn Page 해결법

PostgreSQL의 Full-Page Write에 대응하는 InnoDB의 기능이 Doublewrite Buffer다.

  1. Dirty page를 디스크로 쓸 때, 먼저 doublewrite buffer에 쓴다 (순차 I/O).
  2. doublewrite buffer에 성공적으로 쓰였으면, 실제 데이터 파일에 쓴다 (랜덤 I/O).
  3. 장애 시 실제 파일의 페이지가 손상되었으면, doublewrite buffer에서 복구.

이는 WAL을 두 배로 불리지 않는 대신 쓰기 I/O를 두 배로 만든다. 최신 NVMe에선 거의 무시할 수 있는 비용이다.


6. WAL의 성능 특성

순차 I/O의 축복

WAL의 가장 큰 성능 이점은 순차 쓰기다:

WAL은 항상 파일 끝에 추가하므로 디스크 암(arm)이 움직이지 않는다. 초당 수십만 트랜잭션이 가능한 이유다.

fsync의 지연

그러나 fsync는 여전히 비싸다:

커밋마다 fsync를 하면 트랜잭션 처리량이 초당 수천에 갇힌다. 해결책:

Group Commit

여러 트랜잭션의 커밋을 한 번의 fsync로 처리한다:

트랜잭션 T1: COMMIT (WAL 버퍼에 기록)
트랜잭션 T2: COMMIT (WAL 버퍼에 기록)
트랜잭션 T3: COMMIT (WAL 버퍼에 기록)
        한 번의 fsync()
    T1, T2, T3 모두에게 성공 응답

fsync 1번으로 여러 커밋을 처리하니 처리량이 폭발적으로 늘어난다. PostgreSQL과 InnoDB 모두 기본 활성화.

PostgreSQL commit_delay

commit_delay = 10           # μs 단위. 그룹 커밋 대기 시간.
commit_siblings = 5         # 이만큼 트랜잭션이 있을 때만 대기.

이 설정은 고동시성 환경에서 처리량을 높일 수 있지만, 응답 시간을 증가시킨다. 벤치마크가 필수.

WAL 압축

PostgreSQL은 wal_compression = on으로 Full-Page Write를 압축할 수 있다. CPU 비용 대비 I/O 대역폭과 네트워크(복제) 절약.

PG 15부터는 wal_compression에 알고리즘 선택 가능 (pglz, lz4, zstd).


7. WAL과 장애 시나리오

시나리오 1: 전원 차단

시나리오 2: OS 크래시

전원 차단과 동일. OS가 쓴 내용도 디스크에 반영되지 않을 수 있지만, fsync 이후의 데이터는 안전.

시나리오 3: 디스크 오류

여기서 WAL만으로는 부족하다. 디스크 자체가 손상되면 복구 불가. 해결책:

시나리오 4: 부분 쓰기 (Torn Page)

앞서 설명. PostgreSQL의 Full-Page Write 또는 InnoDB의 Doublewrite Buffer로 해결.

시나리오 5: "Lost Write"

디스크가 쓰기를 받았다고 거짓 응답하지만 실제로는 안 쓴 경우. fsync를 속이는 잘못된 저가 SSD에서 발생.

검증 방법:


8. WAL 운영 모범 사례

1. WAL 디스크 분리

가능하면 WAL을 데이터 파일과 다른 디스크에 두자:

# PostgreSQL
# data_directory: /data/pgdata
# pg_wal을 심볼릭 링크로 /wal/pg_wal에 연결

이유:

2. fsync는 무조건 켜라

fsync = off, synchronous_commit = off벤치마크용이지 프로덕션용이 아니다.

예외: 개발 환경, 일회성 데이터 로드, 복제본을 유지하는 경우 일시적으로 off 가능.

3. 체크포인트 빈도 조정

# 너무 자주 ← bad
checkpoint_timeout = 1min

# 균형 ← 권장
checkpoint_timeout = 15min
max_wal_size = 4GB

# 너무 드물게 ← bad (복구 느림)
checkpoint_timeout = 1h

4. WAL 크기 모니터링

-- PostgreSQL: 현재 WAL 크기
SELECT pg_size_pretty(pg_wal_lsn_diff(pg_current_wal_lsn(), '0/0'));

-- 미아카이빙된 WAL
SELECT count(*) FROM pg_ls_waldir() WHERE name < (SELECT last_archived_wal FROM pg_stat_archiver);

WAL이 비정상적으로 커지면:

5. 복구 시간 테스트

"백업은 있지만 복구해 본 적 없다" 는 흔한 악몽이다. 주기적으로:

  1. 백업으로부터 새 환경 구축.
  2. WAL 재생으로 특정 시점까지 복구.
  3. 데이터 무결성 검증.
  4. 소요 시간 기록.

6. synchronous_commit의 이해

# 가장 안전 + 느림
synchronous_commit = remote_apply  # 복제본 재생까지 대기

# 데이터 손실 없음 + 빠름
synchronous_commit = remote_write  # 복제본 수신까지만 대기

# 일반적 + 빠름
synchronous_commit = on            # 로컬 fsync까지

# 마지막 수 ms 손실 허용 + 매우 빠름
synchronous_commit = off

트랜잭션별로 바꿀 수도 있다:

SET LOCAL synchronous_commit = off;
INSERT INTO logs ...;  -- 로그성 쓰기는 빠르게
COMMIT;

9. 최신 트렌드와 연구

NVMe와 Storage Class Memory

새로운 스토리지 기술은 WAL 설계에 영향을 준다:

그러나 Optane은 2022년 단종되었고, PMEM 채택은 여전히 제한적. 실전에선 NVMe 위 전통 WAL이 여전히 표준이다.

Async WAL

일부 NoSQL(예: Redis AOF)은 async flush 옵션을 제공한다. 성능은 빠르지만 마지막 수 ms ~ 수 초 손실 가능.

Log-Structured Everything

LSM Tree (RocksDB, Cassandra) 자체가 WAL 기반이다. 메모리 테이블 + WAL → SST 파일로 flush → 주기적 compaction. 이는 "쓰기 증폭" 문제가 있지만 대규모 데이터에 적합.

SMR 드라이브와 WAL

Shingled Magnetic Recording(SMR) HDD는 덮어쓰기가 느리지만 순차 쓰기는 빠르다. WAL의 순차 특성과 잘 맞아 연구가 활발하다.


10. 직접 구현해 보자: 간단한 WAL

최소 WAL 구현 (Python)

import json
import os
import struct

class SimpleWAL:
    def __init__(self, log_path):
        self.log_path = log_path
        self.lsn = 0
        if os.path.exists(log_path):
            self._recover()

    def log(self, record: dict):
        """WAL에 레코드 기록 (force=True로 fsync)"""
        self.lsn += 1
        record['lsn'] = self.lsn
        data = json.dumps(record).encode()

        with open(self.log_path, 'ab') as f:
            # 길이(4B) + 데이터
            f.write(struct.pack('>I', len(data)))
            f.write(data)
            f.flush()
            os.fsync(f.fileno())  # 🔑 핵심: 디스크까지 확인

        return self.lsn

    def _recover(self):
        """시작 시 로그 재생"""
        with open(self.log_path, 'rb') as f:
            while True:
                length_data = f.read(4)
                if not length_data:
                    break
                length = struct.unpack('>I', length_data)[0]
                record = json.loads(f.read(length))
                self.lsn = max(self.lsn, record['lsn'])
                self._apply(record)

    def _apply(self, record):
        """로그 레코드를 상태에 적용 (redo)"""
        print(f"Applying: {record}")

# 사용 예시
wal = SimpleWAL('demo.wal')
wal.log({'type': 'insert', 'key': 'user:1', 'value': 'alice'})
wal.log({'type': 'update', 'key': 'user:1', 'value': 'bob'})
# 여기서 프로세스 죽어도, 재시작 시 로그 재생으로 복구

이건 극도로 단순화된 예시지만, "변경을 로그에 먼저 쓰고 fsync" 라는 핵심을 보여준다.

실전 구현에 필요한 것들

진짜 프로덕션 WAL은 이보다 훨씬 복잡하다:

그래서 PostgreSQL의 WAL 코드는 10,000줄 이상이다. 하지만 원리는 위 예시와 같다.


퀴즈로 복습하기

Q1. WAL의 두 가지 근본 규칙은?

A. (1) WAL Rule: 데이터 페이지를 디스크에 쓰기 전에 해당 변경의 로그 레코드가 먼저 디스크에 flush되어야 한다. (2) Force-at-Commit: 트랜잭션이 커밋된 것으로 간주되기 전에 그 트랜잭션의 모든 로그 레코드가 디스크에 flush되어야 한다. 이 두 규칙만 지키면 어떤 장애 시점에서도 일관된 상태로 복구할 수 있다.

Q2. ARIES의 복구 3단계와 각 단계의 목적은?

A. (1) Analysis: 마지막 체크포인트부터 로그를 읽어 장애 시점의 Dirty Page Table과 Transaction Table을 재구성. (2) Redo: 모든 로그 레코드(커밋/미커밋 무관)를 재적용해서 장애 직전 상태로 복원. "Repeating History". (3) Undo: 미커밋 트랜잭션들을 로그를 역방향으로 따라가며 롤백. 이 과정도 CLR(Compensation Log Record)로 로그에 남겨 재귀적 복구가 가능하게 한다.

Q3. PostgreSQL의 Full-Page Write와 InnoDB의 Doublewrite Buffer가 해결하는 공통 문제는?

A. Torn Page 문제다. 데이터베이스 페이지(보통 8KB/16KB)가 디스크에 쓰이는 중간에 장애가 발생하면, 일부만 쓰인 손상된 페이지가 남는다. OS/디스크는 보통 4KB 블록 단위 원자성만 보장하기 때문이다. PostgreSQL은 체크포인트 후 첫 수정 시 전체 페이지를 WAL에 기록해서 복구 시 사용한다. InnoDB는 doublewrite buffer에 먼저 쓴 후 실제 위치에 쓰는 방식으로 해결한다.

Q4. Group Commit이 성능을 얼마나 향상시키며, 왜 그런가?

A. Group Commit은 수십~수백 배의 처리량 향상을 가져올 수 있다. 단일 SSD의 fsync가 초당 1000~10000번 정도인데, 각 커밋이 fsync 1번을 요구하면 초당 수천 트랜잭션이 한계다. Group Commit은 여러 트랜잭션의 커밋 레코드를 WAL 버퍼에 모은 후 한 번의 fsync로 여러 커밋을 처리한다. fsync는 블로킹 I/O이므로 대기 중인 트랜잭션이 많을수록 효율이 높아진다. PostgreSQL과 InnoDB 모두 기본 활성화되어 있다.

Q5. 왜 복구 과정에서 미커밋 트랜잭션의 변경까지 먼저 redo하고 나중에 undo하는가?

A. ARIES의 "Repeating History" 원칙 때문이다. 이렇게 하면 복구 과정이 훨씬 단순하고 견고해진다:

  1. 상태 일관성: 일단 장애 직전 상태를 정확히 재현하면, 그 위에서 undo하는 것이 훨씬 쉽다. 어떤 변경이 디스크에 반영됐는지 일일이 구분할 필요가 없다.

  2. 구조 일관성: B-Tree 같은 복잡한 데이터 구조는 mtr(mini-transaction) 단위의 원자성이 필요하다. 일부 mtr만 적용된 상태에서 undo를 시도하면 구조가 깨질 수 있다.

  3. CLR 기록: undo 과정 자체도 로그에 CLR로 남기므로, undo 중 또 장애가 나도 일관되게 이어갈 수 있다.

  4. 재귀성: 로그 적용과 취소가 같은 프레임워크를 공유하니 구현이 단순해진다.


마치며: WAL이 가르쳐준 것

핵심 정리

  1. 변경 전에 로그 먼저: 단순한 규칙이지만 내결함성의 기초.
  2. 순차 I/O의 위력: 왜 DB가 SSD보다 빠를 수 있는가의 답.
  3. fsync는 타협 불가: 속도와 안전성의 경계.
  4. Group Commit: 병렬성을 I/O 차원에서 활용.
  5. ARIES 3단계: Analysis → Redo → Undo가 현대 DB 복구의 표준.
  6. 체크포인트: 복구 시간과 평상시 성능의 균형.

모든 분산 시스템의 토대

WAL 개념은 단일 DB를 넘어 어디에나 있다:

"먼저 로그에 쓰고, 나중에 실제 상태에 적용한다" 는 아이디어는 컴퓨터 과학에서 가장 유용한 패턴 중 하나다.

마지막 조언

데이터베이스를 운영하면서 WAL을 이해하고 있으면:

데이터베이스 내부를 아는 엔지니어와 모르는 엔지니어의 차이는, 장애가 났을 때 가장 극명하게 드러난다. WAL을 이해하는 당신은 이미 한 걸음 앞서 있다.


참고 자료

댓글

아직 댓글이 없습니다.

로그인하면 댓글을 쓸 수 있습니다