안동민 개발노트 아이콘

안동민 개발노트

12장 : 복구와 로깅

WAL과 로그 기반 복구

DBMS는 언제든 장애가 발생할 수 있습니다. 정전, 디스크 오류, 프로세스 충돌 등의 상황에서도 커밋된 트랜잭션의 변경은 보존되어야 하고, 커밋되지 않은 트랜잭션의 변경은 일관되게 취소되어야 합니다. 이 요구를 충족시키는 핵심 기술이 WAL(Write-Ahead Logging)입니다. 데이터 페이지가 안정 저장소에 기록되기 전에, 그 변경을 복구할 로그를 먼저 안정화하라는 원칙이 현대 데이터베이스 복구 메커니즘의 토대입니다. 단, 비동기 커밋이나 완화된 flush 설정을 켠 경우에는 COMMIT 응답과 로그 안정화 시점이 분리될 수 있으므로 지속성 보장 수준도 설정에 따라 달라집니다.

WAL 없이 데이터베이스를 운영한다면, 장애 발생 시 이 데이터가 커밋된 건가, 아닌 건가?를 판단할 근거가 부족해집니다. COMMIT을 실행했지만 데이터 페이지가 디스크에 반영되기 전에 전원이 꺼지면, 해당 변경을 다시 적용할 로그가 남아 있어야 합니다. WAL은 이 문제를 해결합니다.


WAL 원칙

WAL의 핵심은 두 가지 규칙입니다.

WAL 처리 순서

트랜잭션이 데이터를 변경할 때의 내부 처리 순서를 따라가 봅시다.

이 순서에서 핵심은 ③번입니다. 데이터 페이지가 아직 디스크에 기록되지 않았더라도, 필요한 로그가 안정 저장소에 있으면 장애 후 Redo로 변경을 재적용할 수 있습니다. 반대로 ④번에서 데이터 페이지 기록이 늦어져도 복구 기준은 로그에 남습니다. 또한 Dirty Page를 디스크에 쓰기 전에는 그 페이지의 pageLSN 이하 로그가 먼저 안정화되어 있어야 합니다.

WAL의 성능 이점

왜 데이터를 바로 디스크에 안 쓸까요? 로그는 순차 쓰기(Sequential Write)이고, 데이터는 랜덤 쓰기(Random Write)이기 때문입니다.

예를 들어 10건의 UPDATE가 서로 다른 테이블의 서로 다른 페이지에 흩어져 있다면, 데이터를 직접 쓰려면 여러 번의 랜덤 I/O가 필요합니다. 하지만 WAL을 쓰면 커밋 경로에서는 로그 레코드를 순차적으로 기록하고, 실제 데이터 페이지의 디스크 기록은 나중에 모아서 처리할 수 있습니다.

No-Force / Steal 정책

WAL과 함께 사용되는 버퍼 관리 정책을 이해하면 복구 메커니즘의 전체 그림이 보입니다.

정책설명필요한 복구 동작
No-Force커밋돼도 변경 페이지가 디스크에 없을 수 있음Redo 필요
Steal커밋 안 된 변경 페이지가 디스크에 내려갈 수 있음Undo 필요

로그 레코드 구조

Redo/Undo 로그에는 각 변경에 대한 레코드가 기록됩니다. DBMS에 따라 Redo와 Undo가 물리적으로 분리되기도 하고, WAL 레코드와 별도 undo 영역, 보상 로그를 조합하기도 합니다. 교육용으로 추상화하면 다음 정보들이 핵심입니다.

각 필드의 역할을 설명합니다.

LSN (Log Sequence Number): 로그 레코드의 고유 식별자입니다. 단조 증가하는 값으로, 이벤트의 발생 순서를 나타냅니다. ARIES 계열의 설명에서는 데이터 페이지에도 "이 페이지에 마지막으로 적용된 로그의 LSN"이 기록되어 있어, 복구 시 어떤 로그까지 적용되었는지 판단할 수 있습니다.

TxID: 트랜잭션 식별자입니다. 같은 트랜잭션의 로그 레코드를 묶어서 추적할 수 있습니다.

이전 값 또는 취소 정보: Undo(롤백) 시 변경을 되돌리는 데 필요한 정보입니다. 단순한 이전 값일 수도 있고, 변경을 취소하는 동작 정보일 수도 있습니다.

이후 값 또는 재적용 정보: Redo(재적용) 시 변경을 다시 적용하는 데 필요한 정보입니다. 물리적 값, 논리적 명령, 페이지 내부 동작 정보 등으로 표현될 수 있습니다. 실제 엔진은 순수 물리/순수 논리보다 페이지 단위와 연산 의미를 섞은 생리적 로깅을 활용하는 경우가 많습니다.

PrevLSN: 같은 트랜잭션의 이전 로그 레코드를 가리킵니다. Undo 시 역방향으로 추적하는 연결 리스트 역할을 합니다.

물리적 로깅 vs 논리적 로깅


ARIES 복구 알고리즘

ARIES(Algorithm for Recovery and Isolation Exploiting Semantics)는 IBM에서 개발한 대표적인 로그 기반 복구 알고리즘입니다. 여러 상용 DBMS의 복구 설계에 큰 영향을 주었지만, 실제 제품은 저장 엔진과 로그 형식에 맞게 세부 구현이 달라집니다.

ARIES의 세 가지 핵심 원칙은 WAL(Write-Ahead Logging), Repeating History During Redo, Logging Changes During Undo입니다. 이 원칙에 따라 세 단계로 진행됩니다.

ARIES 3대 원칙
1. WAL: 데이터 페이지 flush 전에 필요한 로그를 먼저 안정화
2. Repeating History: Redo 시 필요한 변경을 커밋 여부와 무관하게 재검토
3. Logging Undo: Undo 작업 자체도 CLR로 기록하여 멱등성 보장

1단계: 분석 (Analysis Phase)

마지막 체크포인트 레코드가 가리키는 상태부터 로그 끝까지 순방향으로 읽으며, 장애 시점에 어떤 트랜잭션이 활동 중이었는지와 어떤 데이터 페이지가 Dirty(메모리에서 변경되었지만 디스크에 반영되지 않음)였는지를 파악합니다. ARIES 용어로는 ATT(Transaction Table)와 DPT(Dirty Page Table)를 재구성합니다.

2단계: Redo (Redo Phase)

분석 단계에서 결정된 시작점부터 로그 끝까지 순방향으로 읽으며, 복구에 필요한 변경을 재적용합니다. 보통 DPT의 가장 이른 recLSN이 Redo 시작 후보가 되고, 커밋 여부와 관계없이 로그를 재검토하되 실제 적용 여부는 DPT 포함 여부와 각 페이지의 pageLSN을 기준으로 판단합니다. 이를 Repeating History라 합니다.

Redo 시에는 각 데이터 페이지의 pageLSN(이 페이지에 마지막으로 적용된 로그의 LSN)을 확인합니다. 로그 레코드가 해당 페이지의 Redo 대상이고 LSN이 pageLSN보다 크면 아직 적용 안 된 변경이므로 Redo를 수행합니다. 이미 적용된 변경은 건너뜁니다(멱등성).

3단계: Undo (Undo Phase)

분석 단계에서 파악된 미완료 트랜잭션(ATT에 있는 트랜잭션)의 변경을 역방향으로 되돌립니다.

CLR(Compensation Log Record)은 Undo 작업 자체를 기록하는 로그입니다. Undo 도중에도 장애가 발생할 수 있으므로, Undo를 얼마나 진행했는지 기록해두어야 합니다. CLR은 다시 Undo되지 않고 Redo 대상이 되며, undoNextLSN 같은 정보를 통해 다음에 취소할 위치를 이어갈 수 있게 합니다.

ARIES 복구 전체 흐름


체크포인트 (Checkpoint)

체크포인트는 복구 시작 위치를 관리하고 메모리의 변경된 데이터(Dirty Pages)를 점진적으로 디스크에 기록하는 기준점입니다. 체크포인트의 주된 목적은 장애 후 다시 읽어야 할 로그 범위를 줄이는 것입니다. 다만 Fuzzy Checkpoint에서는 체크포인트 이전 로그를 단순히 모두 버리는 것이 아니라, Dirty Page Table 같은 정보를 이용해 Redo 시작점을 계산합니다. 체크포인트 자체도 디스크 I/O를 발생시키므로 운영 환경에서는 복구 시간과 정상 처리량의 균형을 조정해야 합니다.

체크포인트가 필요한 이유

체크포인트의 종류

Fuzzy Checkpoint에서는 체크포인트 시점에 모든 Dirty 페이지가 디스크에 기록되는 것이 아닙니다. 따라서 복구 시 체크포인트의 DPT를 참조하여 Redo의 시작점을 결정해야 합니다.

DBMS별 체크포인트 설정

PostgreSQL
파라미터:
  checkpoint_timeout = 5min      → 시간 기준 체크포인트 간격
  max_wal_size = 1GB             → WAL 증가 압박 시 체크포인트 유도
  checkpoint_completion_target = 0.9  → 체크포인트 기간 분산

프로세스:
  Checkpointer: 체크포인트 수행
  Background Writer: Dirty 페이지를 점진적으로 기록

수동 체크포인트:
  CHECKPOINT;
MySQL InnoDB
파라미터:
  innodb_redo_log_capacity         → Redo 로그 용량과 checkpoint age에 영향
  innodb_max_dirty_pages_pct = 75  → Dirty 페이지 목표 비율
  innodb_io_capacity = 200         → 초당 I/O 작업 수
  innodb_adaptive_flushing = ON    → Redo 압박을 고려한 적응적 flush

프로세스:
  Page Cleaner Thread: Dirty 페이지를 디스크에 기록

로그 버퍼와 디스크 기록 시점

로그는 먼저 메모리의 로그 버퍼에 기록되고, 특정 시점에 디스크에 기록(flush)됩니다.

로그 디스크 기록 시점 (Oracle LGWR 예시)
1. 트랜잭션이 COMMIT할 때
2. 로그 버퍼가 일정 수준 이상 찼을 때
3. 주기적 flush 조건을 만족할 때
4. DBWR이 관련 Dirty 페이지를 기록하기 전에

로그 기반 시점 복구 (PITR)

보존된 로그 체인을 활용하면 특정 시점으로 데이터베이스를 복구할 수 있습니다. 이를 PITR(Point-In-Time Recovery)이라 합니다. PostgreSQL은 WAL 아카이브, Oracle은 archived redo log, MySQL은 백업과 binary log 조합처럼 제품마다 사용하는 로그 이름과 절차가 다릅니다. 특히 MySQL binary log는 InnoDB redo log와 달리 서버 계층의 논리 로그에 가깝기 때문에, 장애 복구용 redo와 PITR용 로그를 구분해서 이해해야 합니다.

PostgreSQL PITR
# PostgreSQL 12 이전: recovery.conf
# PostgreSQL 12+: recovery.signal을 만들고 postgresql.conf 또는
# postgresql.auto.conf에 복구 설정을 둔다.
touch recovery.signal
restore_command = 'cp /archive/%f %p'
recovery_target_time = '2024-03-15 13:55:00'
recovery_target_action = 'pause'
Oracle PITR (RMAN)
-- RMAN에서 시점 복구
RMAN> RUN {
    SET UNTIL TIME "TO_DATE('2024-03-15 13:55:00', 'YYYY-MM-DD HH24:MI:SS')";
    RESTORE DATABASE;
    RECOVER DATABASE;
}

PITR은 잘못된 DELETE나 DROP TABLE 같은 인적 오류에서 복구할 때 매우 유용합니다. 실수하기 직전 시점으로 되돌릴 수 있기 때문입니다.


로그 관련 장애 유형과 복구

트랜잭션 장애

개별 트랜잭션의 실패(제약 위반, 교착 상태 등)로 인한 롤백입니다. Undo 정보 또는 보상 로그를 사용하여 해당 트랜잭션의 변경만 되돌립니다. 다른 트랜잭션에는 영향을 주지 않습니다. 트랜잭션 장애는 정상적인 운영 중에도 빈번하게 발생하며, DBMS가 자동으로 처리합니다. 개발자가 명시적으로 ROLLBACK 명령을 실행하는 경우도 같은 원리로 변경을 되돌립니다.

시스템 장애 (Instance Crash)

정전, DBMS 프로세스 충돌, OS 충돌 등으로 인스턴스가 비정상 종료된 경우입니다. 인스턴스 재시작 시 DBMS는 로그 기반 인스턴스 복구를 자동으로 수행합니다. 데이터 파일 자체가 손상되지 않았다면 온라인 로그와 데이터 파일을 기준으로 복구할 수 있습니다. 시스템 장애 후 복구 시간은 체크포인트 정책, Dirty Page 수, 로그량에 영향을 받습니다.

미디어 장애 (Disk Failure)

디스크 물리적 손상으로 데이터 파일이 손실된 경우입니다. 백업과 아카이브/트랜잭션 로그 체인을 사용하여 목표 시점으로 복구합니다. 이 경우에는 필요한 로그가 별도의 디스크나 아카이브 스토리지에 보존되어 있어야 합니다. RAID는 가용성에 도움이 되지만 백업을 대체하지 못하므로, 정기 백업과 복구 리허설이 함께 필요합니다.


아카이브 로그 vs 온라인 로그

DBMS의 로그 파일은 보존 방식에 따라 복구 가능 범위가 크게 달라집니다. Oracle의 온라인 redo/archived redo처럼 명확히 구분되는 제품도 있고, PostgreSQL WAL 아카이브나 SQL Server 로그 백업처럼 다른 이름과 절차를 쓰는 제품도 있습니다.

운영 환경에서 적절한 모드를 선택하는 것은 DBA의 핵심 업무 중 하나입니다.

Oracle 아카이브 로그 모드 설정
-- 현재 모드 확인
SELECT LOG_MODE FROM V$DATABASE;

-- ARCHIVELOG 모드로 변경 (MOUNT 상태에서)
ALTER DATABASE ARCHIVELOG;

로그 설계 실무 고려사항


요약 정리

개념설명
WAL데이터 페이지보다 복구 로그를 먼저 안정화하는 원칙
Redo 로그변경을 다시 적용하기 위한 정보 기록
Undo 로그미완료 변경을 취소하기 위한 정보 또는 저장 영역
LSN로그 레코드 고유 번호, 적용 여부 판단 기준
ARIES분석→Redo→Undo를 설명하는 대표 복구 알고리즘
체크포인트복구 시작 위치와 Dirty Page 기록 관리
CLRUndo 작업 기록, 재장애 시 undoNextLSN으로 재개
PITR로그 기반 특정 시점 복구
No-Force/Steal많은 DBMS의 버퍼 정책, Redo+Undo 필요 근거
로그 아카이브백업 이후 목표 시점까지 재적용할 로그 보존
로그 다중화로그 파일을 여러 디스크에 복사하여 안전성 확보

WAL은 단순한 기법이 아니라 데이터베이스의 내구성(Durability)을 보장하는 근본 원리입니다. 기본적인 완전 내구성 설정에서 COMMIT 응답을 받은 클라이언트가 이 변경은 보존된다고 신뢰할 수 있는 이유는, 필요한 로그가 안정 저장소에 먼저 남기 때문입니다. 비동기 커밋이나 완화된 flush 설정을 선택하면 성능은 좋아질 수 있지만 장애 시 최근 커밋 일부가 사라질 수 있습니다. ARIES 계열의 복구 알고리즘은 이 WAL 원칙 위에서 분석, Redo, Undo를 체계적으로 수행하여 시스템 장애 후 데이터베이스를 일관된 상태로 되돌립니다.

다음 절에서는 Oracle의 RMAN과 실무 백업 전략을 다루겠습니다.