2026년 07월 30일 | DBMS Error 가이드
이 글에서 다루는 내용
XX001 에러의 원인 분석, 해결 SQL, 예방 방법을 실무 관점에서 정리합니다.
XX001 data corrupted 는?
PostgreSQL 에러 코드 XX001 (data corrupted)는 데이터베이스 내부의 데이터 구조가 손상되어 더 이상 정상적으로 읽거나 처리할 수 없는 상태를 의미합니다. 이 에러는 PostgreSQL이 힙 파일, 인덱스 파일, WAL(Write-Ahead Log) 등의 물리적 파일을 읽는 과정에서 내부 일관성 검사를 통과하지 못할 때 발생합니다. 데이터 손상은 즉각적인 서비스 장애로 이어질 수 있으며, 방치할 경우 데이터 유실로 이어질 수 있는 매우 심각한 에러입니다.
주요 발생 원인
1. 하드웨어 장애 (스토리지 불량, 메모리 오류)
가장 흔하고 치명적인 원인으로, HDD/SSD의 배드 섹터나 RAID 컨트롤러 오류가 디스크에 기록된 데이터 블록을 변형시킵니다. ECC(Error Correcting Code)를 지원하지 않는 메모리를 사용하는 서버에서는 메모리 비트 플립(bit flip)이 발생하여 데이터가 디스크에 잘못 기록될 수 있으며, 이는 추후 XX001 에러로 나타납니다. 운영 환경에서는 반드시 ECC RAM과 검증된 스토리지 솔루션을 사용해야 합니다.
2. 비정상적인 PostgreSQL 프로세스 종료 (강제 kill, 전원 차단)
PostgreSQL 서버 프로세스를 SIGKILL로 강제 종료하거나 갑작스러운 전원 차단이 발생하면, 진행 중이던 WAL 쓰기 작업이 중단되어 데이터 파일과 WAL 간의 불일치가 생길 수 있습니다. PostgreSQL은 재시작 시 WAL을 이용한 복구(recovery)를 시도하지만, WAL 자체가 손상된 경우에는 복구가 불완전하게 끝나고 XX001이 발생하게 됩니다. 이를 방지하기 위해 OS 레벨의 UPS(무정전 전원장치) 사용과 fsync 설정 유지가 필수적입니다.
3. 파일 시스템 또는 볼륨 레벨의 오류
잘못된 파일 시스템(ext4, xfs 등)의 마운트 옵션(nobarrier 사용 등)이나 LVM/파티션 오류가 PostgreSQL 데이터 파일을 오염시킬 수 있습니다. 특히 클라우드 환경에서 볼륨 스냅샷을 잘못된 타이밍에 생성하거나 NFS 마운트를 사용하는 경우 데이터 손상 위험이 높아집니다. 파일 시스템 레벨의 일관성 확인(fsck)을 정기적으로 수행해야 합니다.
해결 방법
1단계: 손상 범위 파악 — pg_dump 및 VACUUM 으로 확인
먼저 어느 테이블 또는 인덱스가 손상되었는지 확인합니다.
-- 전체 데이터베이스 논리 백업 시도 (에러 발생 위치 파악)
-- 터미널에서 실행
-- pg_dump -Fc -d mydb -f /tmp/mydb_backup.dump 2>&1 | tee /tmp/dump_errors.log
-- 특정 테이블의 데이터 읽기 시도로 손상 여부 확인
SELECT COUNT(*) FROM your_table;
-- VACUUM VERBOSE로 손상된 페이지 탐지
VACUUM VERBOSE your_table;
-- pg_class를 통해 릴레이션 파일 경로 확인
SELECT relname, relfilenode, relpages
FROM pg_class
WHERE relname = 'your_table';
2단계: pg_filedump 로 블록 레벨 분석
-- pg_filedump는 외부 도구이므로 OS 상에서 실행
-- pg_filedump -i -f /var/lib/postgresql/14/main/base/16384/<relfilenode>
-- 손상된 페이지를 무시하고 데이터 추출 (zero_damaged_pages 활용)
-- postgresql.conf에 다음 설정 추가 후 재시작 (또는 세션 레벨 설정)
SET zero_damaged_pages = on;
-- 이후 손상된 테이블에서 데이터 추출
SELECT * FROM your_table;
> ⚠️ zero_damaged_pages = on 은 손상된 페이지를 0으로 채워 읽기를 강제로 진행하므로, 데이터 유실이 발생할 수 있습니다. 반드시 복구 목적으로만 일시적으로 사용하세요.
3단계: 인덱스 재생성
손상이 인덱스에 국한된 경우, 인덱스를 재생성하여 해결할 수 있습니다.
-- 손상된 인덱스 확인
SELECT indexrelid::regclass AS index_name,
indrelid::regclass AS table_name
FROM pg_index
WHERE indisvalid = false;
-- 인덱스 재생성 (잠금 최소화)
REINDEX INDEX CONCURRENTLY idx_your_table_column;
-- 테이블 전체 인덱스 재생성
REINDEX TABLE CONCURRENTLY your_table;
-- 데이터베이스 전체 재인덱싱 (PostgreSQL 12+)
REINDEX DATABASE CONCURRENTLY mydb;
4단계: pg_resetwal 을 이용한 WAL 초기화 (최후의 수단)
-- 반드시 PostgreSQL 서버를 중지한 후 실행
-- pg_resetwal 은 데이터 유실 가능성이 있으므로 최후 수단으로만 사용
-- 서버 중지
-- pg_ctl stop -D /var/lib/postgresql/14/main
-- WAL 상태 확인
-- pg_resetwal -n /var/lib/postgresql/14/main
-- 실제 초기화 (위험! 반드시 전체 백업 후 실행)
-- pg_resetwal /var/lib/postgresql/14/main
5단계: 백업에서 복구
모든 방법이 실패한 경우, 가장 안전한 방법은 최신 백업으로부터 PITR(Point-in-Time Recovery)를 수행하는 것입니다.
-- recovery.conf (PostgreSQL 11 이하) 또는 postgresql.conf (12+) 설정 예시
-- postgresql.conf (PostgreSQL 12+)
-- restore_command = 'cp /mnt/wal_archive/%f %p'
-- recovery_target_time = '2024-01-15 10:00:00'
-- recovery_target_action = 'promote'
-- 복구 후 데이터 무결성 확인
SELECT schemaname, tablename
FROM pg_tables
WHERE schemaname = 'public';
-- 각 테이블 행 수 확인
SELECT
schemaname,
tablename,
n_live_tup AS estimated_rows
FROM pg_stat_user_tables
ORDER BY n_live_tup DESC;
예방 방법
1. pg_checksum 및 정기적인 무결성 검사 활성화
PostgreSQL 12부터 pg_checksums 도구를 통해 데이터 블록 수준의 체크섬을 활성화할 수 있습니다. 체크섬이 활성화되면 PostgreSQL이 블록을 읽을 때마다 무결성을 검증하여 조기에 손상을 발견할 수 있습니다. 체크섬이 활성화된 상태에서는 손상이 심화되기 전에 XX001 에러를 통해 즉시 알림을 받을 수 있으며, 정기적인 pg_dump 테스트와 pg_basebackup 검증도 병행해야 합니다.
-- 체크섬 활성화 여부 확인
SHOW data_checksums;
-- 또는
SELECT name, setting FROM pg_settings WHERE name = 'data_checksums';
-- 오프라인에서 체크섬 활성화 (PostgreSQL 서버 중지 필요)
-- pg_checksums --enable -D /var/lib/postgresql/14/main
-- 체크섬 손상 감지 쿼리 (체크섬 활성화 시)
-- 로그에서 checksum failure 탐지
SELECT *
FROM pg_stat_database
WHERE checksum_failures > 0;
2. WAL 아카이빙 + PITR 체계 구축 및 주기적 복구 훈련
WAL 아카이빙을 설정하여 특정 시점으로 복구할 수 있는 PITR 체계를 반드시 갖추어야 합니다. 백업은 만들어 두는 것만으로는 부족하며, 정기적으로 실제 복구 테스트(DR Drill)를 수행하여 복구 절차가 동작하는지 검증해야 합니다. 또한 pg_basebackup을 이용한 베이스 백업과 WAL 아카이브를 분리된 스토리지에 보관하는 것이 필수입니다.
-- WAL 아카이빙 설정 확인
SHOW archive_mode;
SHOW archive_command;
-- 아카이빙 상태 모니터링
SELECT
last_archived_wal,
last_archived_time,
last_failed_wal,
last_failed_time,
archived_count,
failed_count
FROM pg_stat_archiver;
관련 에러
- XX002 (index corrupted): XX001과 유사하지만 인덱스 파일 전용 손상 에러입니다.
REINDEX로 해결 가능한 경우가 많아 XX001보다 복구가 용이합니다. - 58P01 (undefined_file): 데이터 파일 자체가 존재하지 않을 때 발생하며, 물리적 파일 삭제나 잘못된 파일시스템 작업 이후 나타날 수 있습니다.
- 53200 (out_of_memory): 간접적으로 연관되며, 메모리 부족으로 인한 비정상 종료가 XX001로 이어질 수 있습니다.
- 57P03 (cannot_connect_now): 데이터 손상으로 인해 PostgreSQL이 복구 모드에 진입하여 접속이 불가능한 상태를 나타냅니다.
주요 DBMS error code를 정리하는 시리즈입니다.
블로그 홈에서 다른 에러도 확인하세요.
본 포스트는 AI가 생성한 기술 가이드입니다. 운영 환경 적용 전 충분한 검토를 권장합니다.