※ PostgreSQL: WAL.
안녕하세요. 듀스트림입니다.
오늘은 매우 중요한 데이터 무결성과 복구를 보장하는 핵심 메커니즘인 WAL(Write-Ahead Logging)에 대한 내용입니다.
1. WAL의 기본 개념
Write-Ahead Logging (WAL)은 데이터베이스의 ACID 속성 중 원자성(Atomicity)과 지속성(Durability)을 보장하기 위한 기술입니다.
데이터 파일에 변경 사항을 적용하기 전에, 해당 변경 내용을 로그에 기록하고 이를 디스크에 저장함으로써, 시스템 장애 발생 시 로그를 통해 복구할 수 있습니다.
- 기본 원칙: 데이터 파일에 대한 변경은 해당 변경이 WAL에 기록되고 디스크에 저장된 후에만 수행됩니다.
- 복구 메커니즘: 시스템 장애 발생 시, WAL에 기록된 로그를 재생하여 데이터베이스를 일관된 상태로 복구합니다.
28.3. Write-Ahead Logging (WAL)
28.3. Write-Ahead Logging (WAL) # Write-Ahead Logging (WAL) is a standard method for ensuring data integrity. A detailed description can be …
www.postgresql.org
2. WAL의 내부 동작 방식
2.1 WAL 기록 흐름
- 트랜잭션 수행
- 트랜잭션이 수행되면 데이터베이스는 shared_buffers에 변경 내용을 기록합니다.
- shared_buffers는 메모리 캐시로 디스크 I/O를 최소화하기 위해 임시 저장소로 사용됩니다. 트랜잭션이 데이터베이스의 데이터를 변경하면 해당 변경 내용은 shared_buffers에 먼저 기록됩니다.
- 이 단계는 데이터베이스 내부의 작업을 처리하는 중요한 초기 단계로 변경 사항을 메모리 상에 임시 저장하고, 이후 이 데이터를 디스크에 기록하기 위한 준비 단계입니다.
- WAL 버퍼에 기록
- 트랜잭션의 변경 내용은 wal_buffers에 기록됩니다.
- WAL (Write-Ahead Log)는 트랜잭션의 변경 사항을 디스크에 기록하기 전에 로그 파일에 기록하여 장애 발생 시 데이터베이스 복구를 가능하게 합니다.
- 이 로그는 디스크에 기록되기 전에 wal_buffers에 임시로 저장되며, 트랜잭션이 커밋될 때 해당 로그가 안전하게 디스크로 플러시됩니다.
- 디스크에 플러시(WAL 파일)
- 트랜잭션 커밋 시점에 XLogFlush() 함수가 호출됩니다. 이 함수는 지정된 LSN(Log Sequence Number)까지의 WAL 로그를 디스크에 플러시합니다.
- WAL 로그는 pg_wal/ 디렉토리에 저장되며, 디스크에 안전하게 기록됩니다.
- XLogFlush() → fsync_wal() → fsync() 순서로 호출되어 디스크에 WAL 로그가 안전하게 기록됩니다.
- 이 과정은 트랜잭션의 내구성을 보장하며, 장애 발생 시 복구를 가능하게 합니다. 디스크에 기록된 WAL 로그는 트랜잭션의 변경 사항을 영구적으로 보관하게 됩니다.
- 데이터 파일에 반영
- WAL에 기록된 변경 내용은 주기적으로 shared_buffers에서 실제 데이터 파일로 반영됩니다.
- 이 작업은 백그라운드 프로세스인 bgwriter와 walwriter에 의해 처리됩니다.
- bgwriter는 shared_buffers에 있는 더티 페이지(dirty pages)를 주기적으로 디스크의 데이터 파일에 반영합니다. 이 과정은 디스크 I/O 부하를 분산시키고 성능을 최적화하는 데 중요한 역할을 합니다. 데이터 변경 사항을 바로바로 디스크에 반영하는 것이 아니라, WAL에 기록된 내용을 기반으로 효율적이 데이터를 갱신하는 방식입니다.
- walwriter는 WAL 로그 파일을 주기적으로 디스크에 플러시하는 작업을 처리하지만, shared_buffers의 데이터 파일 반영은 bgwriter가 담당합니다.
- WAL에 기록된 내용이 주기적으로 실제 데이터 파일에 반영되어 데이터베이스의 영구적인 상태가 갱신됩니다.
+ OS 레벨에서 보면 WAL 기록 시 open() → write() → fsync() 순으로 동작이 일어납니다.
28.6. WAL Internals
28.6. WAL Internals # WAL is automatically enabled; no action is required from the administrator except ensuring that the disk-space requirements …
www.postgresql.org
postgres/src/backend/access/transam/xlog.c at master · postgres/postgres
Mirror of the official PostgreSQL GIT repository. Note that this is just a *mirror* - we don't work with pull requests on github. To contribute, please see https://wiki.postgresql.org/wiki/Subm...
github.com
postgres/src/backend/postmaster/walwriter.c at master · postgres/postgres
Mirror of the official PostgreSQL GIT repository. Note that this is just a *mirror* - we don't work with pull requests on github. To contribute, please see https://wiki.postgresql.org/wiki/Subm...
github.com
2.2 WAL 파일 구조
- WAL 세그먼트: WAL 파일은 일반적으로 16MB 크기의 세그먼트로 구성되며, pg_wal/ 디렉토리에 저장됩니다.
- 페이지 구성: 각 세그먼트는 8KB 크기의 페이지로 나뉘며, 각 페이지에는 WAL 레코드가 저장됩니다.
- LSN(Log Sequence Number): 각 WAL 레코드는 고유한 LSN을 가지며, 이는 복제 및 복구 시 진행 상황을 추적하는 데 사용됩니다.
3. pg_wal 디렉토리 구조 및 관리
3.1 디렉토리 구성
- WAL 세그먼트 파일: 변경 사항이 기록된 16MB 크기의 파일들입니다.
- archive_status/ 디렉토리: WAL 파일의 아카이빙 상태를 추적합니다.
- .partial 파일: 아직 완전히 기록되지 않은 WAL 세그먼트 파일입니다.
65.1. Database File Layout
65.1. Database File Layout # This section describes the storage format at the level of files and directories. Traditionally, the configuration …
www.postgresql.org
3.2 WAL 파일의 재사용 및 삭제
- 재사용: 체크포인트 이후에 필요 없어지는 WAL 파일은 디스크 공간을 절약하기 위해 삭제하거나 다시 덮어써서 재사용할 수 있습니다.
- 삭제: 더 이상 필요하지 않은 WAL 파일은 삭제됩니다.
하지만 다음과 같은 경우에는 삭제되지 않습니다.
- 아카이빙 실패: WAL 파일이 아직 아카이빙되지 않은 경우.
- 복제 슬롯 사용: 복제 슬롯이 WAL 파일을 참조하고 있는 경우.
- wal_keep_size 설정: 설정된 크기만큼의 WAL 파일을 유지해야 하는 경우.
체크포인트란?
데이터베이스가 현재까지의 변경 내용을 실제 데이터 파일에 반영했다고 "마크"하는 지점입니다.
즉, 해당 시점 이전의 WAL은 복구용으로 더 이상 필요하지 않습니다.
4. 주요 WAL 관련 파라미터
| 파라미터 | 설명 | 기본값 |
| WAL 크기 및 보존 | ||
| min_wal_size | 자동 체크포인트 간 보존할 WAL의 최소 크기 (초과하지 않아도 유지) | 80MB |
| max_wal_size | 자동 체크포인트 간 허용되는 WAL 최대 크기. 초과 시 체크포인트 트리거됨 | 1GB |
| wal_keep_size | 복제 또는 PITR을 위해 보존할 최소 WAL 크기 | 0 |
| wal_recycle | 불필요한 WAL을 삭제하지 않고 재사용할지 여부 | on |
| WAL 쓰기 및 플러시 동작 | ||
| wal_buffers | WAL 기록 전 공유 메모리에 할당되는 버퍼 크기 (자동 계산됨) | -1 (자동) |
| wal_writer_delay | WALWriter 프로세스의 작동 주기 | 200ms |
| wal_writer_flush_after | WALWriter가 flush할 최소 데이터량 | 1MB |
| commit_delay | WAL 기록 후 fsync 전에 기다리는 시간 (μs 단위) | 0 |
| commit_siblings | commit_delay 적용을 위한 최소 동시 트랜잭션 수 | 5 |
| full_page_writes | 변경된 페이지의 전체 이미지를 WAL에 기록하여 복구 보장 | on |
| wal_compression | full_page_writes로 기록되는 페이지의 압축 여부 | off |
| wal_log_hints | hint bit만 변경돼도 WAL에 기록. 복제 및 logical decoding에 필요 | off |
| WAL 아카이빙 및 백업 관련 | ||
| archive_mode | WAL 아카이빙 기능 활성화 여부 (on, off, always) | off |
| archive_command | WAL 파일을 아카이브하기 위한 명령어. %p와 %f 사용 가능 | '' |
| archive_timeout | 아카이빙을 강제하기 위한 WAL 스위치 시간 | 0 (비활성) |
| 복제 및 logical decoding 관련 | ||
| wal_level | WAL 정보 수준: minimal, replica, logical | replica |
| max_wal_senders | 동시에 실행할 수 있는 WAL sender 프로세스 수 | 10 |
| max_replication_slots | 생성 가능한 replication slot 수 | 10 |
| wal_sender_timeout | standby가 응답하지 않을 때 연결 종료까지 대기 시간 | 60s |
28.5. WAL Configuration
28.5. WAL Configuration # There are several WAL-related configuration parameters that affect database performance. This section explains their use. Consult Chapter 19 …
www.postgresql.org
5. WAL 관련 주요 함수 및 소스 코드
5.1 주요 함수
- XLogInsertRecord(): 새로운 WAL 레코드를 WAL 버퍼에 삽입합니다.
- XLogFlush(): WAL 버퍼의 내용을 디스크에 플러시합니다.
- XLogWrite(): WAL 데이터를 디스크에 기록하는 내부 함수입니다.
postgres/src/backend/access/transam/xlog.c at master · postgres/postgres
Mirror of the official PostgreSQL GIT repository. Note that this is just a *mirror* - we don't work with pull requests on github. To contribute, please see https://wiki.postgresql.org/wiki/Subm...
github.com
6. WALWriter 프로세스
- 역할: 백그라운드에서 주기적으로 WAL 버퍼의 내용을 디스크에 기록하여, 트랜잭션 커밋 시의 디스크 I/O 부담을 줄입니다.
- 동작 주기: wal_writer_delay 파라미터에 따라 주기적으로 실행됩니다.
7. WAL과 스트리밍 레플리케이션의 관계
- 스트리밍 레플리케이션은 WAL을 기반으로 primary 서버의 변경 사항을 standby 서버로 실시간 전송하여 데이터 일관성을 유지합니다.
- WALSender 프로세스: primary 서버에서 WAL 데이터를 standby 서버로 전송합니다.
- WALReceiver 프로세스: standby 서버에서 WAL 데이터를 수신하여 로컬 디스크에 저장합니다.
- startup 프로세스: standby 서버에서 수신한 WAL 데이터를 적용하여 데이터베이스 상태를 갱신합니다.
26.2. Log-Shipping Standby Servers
26.2. Log-Shipping Standby Servers # 26.2.1. Planning 26.2.2. Standby Server Operation 26.2.3. Preparing the Primary for Standby Servers 26.2.4. Setting Up …
www.postgresql.org
8. WAL과 로지컬 레플리케이션의 관계
- 로지컬 레플리케이션은 WAL을 기반으로 특정 테이블이나 데이터 변경 사항을 선택적으로 복제하는 기능입니다.
- WALSender 프로세스: primary 서버에서 WAL 데이터를 logical decoding을 통해 디코딩하여 standby 서버로 전송합니다.
- apply 프로세스: standby 서버에서 수신한 데이터를 적용하여 데이터베이스 상태를 갱신합니다.
29.8. Architecture
29.8. Architecture # 29.8.1. Initial Snapshot Logical replication starts by copying a snapshot of the data on the publisher database. Once …
www.postgresql.org
9. 실무 팁
실제로 가장 많이 발생하 장애 중 pg_wal 디렉토리에 WAL 파일이 계속 쌓여 디스크 풀로 DB가 다운되는 케이스들이 있습니다.
- archive_mode = on으로 해뒀지만, archive_command가 실패하면 WAL은 재사용되지 않고 무한하게 쌓입니다.
- replication_slot 사용 중 Standby(Replica) 노드 장애가 발생하면 WAL이 무한히 쌓입니다.
주기적인 모니터링이 반드시 필요하며, 이상 발생 시 빠른 조치가 필요합니다.
+ 관련 모니터링 쿼리들
-- 아카이브 실패 여부 확인
SELECT * FROM pg_stat_archiver;
-- 현재 WAL 위치 및 사이즈 확인
SELECT pg_current_wal_lsn(), pg_wal_lsn_diff(pg_current_wal_lsn(), '0/0');
-- replication lag 확인 (physical)
SELECT client_addr, sent_lsn, replay_lsn, pg_wal_lsn_diff(sent_lsn, replay_lsn) AS byte_lag
FROM pg_stat_replication;
-- logical replication slot lag
SELECT slot_name, active, pg_wal_lsn_diff(pg_current_wal_lsn(), restart_lsn) AS lag_bytes
FROM pg_replication_slots;
++ archive_command 설정 예시
# 아카이빙은 rsync보다 cp + fsync + 리턴코드 체크를 권장
archive_command = 'test ! -f /archive/wal/%f && cp %p /mnt/backup/wal/%f && sync'
+++ 추가로 체크포인트 설정을 적정 값으로 하면 성능에 긍정적 영향을 줄 수 있습니다.
- 체크포인트는 dirty page를 디스크에 flush하는 작업입니다.
- 너무 자주 실행되면:
- 많은 디스크 쓰기 I/O → 성능 저하 (특히 OLTP 시스템에서)
- 너무 늦게 실행되면:
- pg_wal 디렉토리에 WAL 파일이 계속 쌓임
- 장애 시 복구 시간 증가 (WAL 리플레이 구간이 길어짐)
- 관련 파라미터
| 파라미터 | 설명 | 기본값 |
| checkpoint_timeout | 최대 시간 간격마다 체크포인트를 강제로 수행 | 5분 |
| checkpoint_completion_target | checkpoint를 전체 주기 내 어느 정도 분산해서 천천히 끝낼지를 정하는 비율 | 0.5 (절반 시간에 걸쳐서 완료) |
오늘은 여기까지~
'PostgreSQL' 카테고리의 다른 글
| PostgreSQL: Disk Spill (0) | 2025.05.26 |
|---|---|
| PostgreSQL: ExprContext 기반 GeoJSON 조회 쿼리로 인한 OOM(Out of Memory) 발생 사례 분석 (0) | 2025.05.24 |
| PostgreSQL: reload (0) | 2025.05.22 |
| PostgreSQL: TOAST (0) | 2025.05.21 |
| PostgreSQL: VACUUM (0) | 2025.05.17 |