WAL 신뢰성 — 커밋된 데이터가 정말 안전하려면
WAL 신뢰성 — 커밋된 데이터가 정말 안전하려면
데이터베이스가 진지하게 운영되려면 "커밋된 트랜잭션의 데이터는 반드시 남는다"는 신뢰성이 기본이에요. PostgreSQL은 이걸 보장하기 위해 정말 할 수 있는 걸 다 하는데, 그 핵심이 바로 이번 주제입니다. 중요한 건 "영구 저장소에 잘 써졌다"가 생각보다 복잡한 일이라는 점이에요. 파워 셧다운, OS 실패, 하드웨어 고장 같은 시나리오를 하나씩 따져보면서 신뢰성이 어디서 무너질 수 있는지 알아볼게요.
출처: 공식문서
"영구 저장소에 썼다" = 안전하다?
커밋된 트랜잭션이 기록한 모든 데이터는 전원 손실·OS 실패·하드웨어 고장으로부터 안전한 비휘발성 영역에 저장되어야 해요. 컴퓨터의 영구 저장소(디스크 드라이브 등)에 제대로 쓰기만 하면 보통 이 요건을 충족하죠. 실제로 컴퓨터 자체가 치명적으로 망가져도, 디스크 드라이브만 살아있다면 비슷한 하드웨어의 다른 컴퓨터로 옮겨서 모든 커밋 트랜잭션을 그대로 유지할 수 있어요.
하지만 주기적으로 데이터를 디스크 플래터에 강제로 써내는(write-through) 일은 겉보기처럼 단순하지 않아요. 디스크는 메모리·CPU보다 훨씬 느리기 때문에, 주 메모리와 디스크 플래터 사이에 여러 겹의 캐시가 존재합니다.
- 첫 번째는 OS 버퍼 캐시예요. 자주 요청되는 디스크 블록을 캐시하고 디스크 쓰기를 합쳐줍니다. 다행히 모든 OS가 버퍼 캐시에서 디스크로 쓰기를 강제하는 방법을 애플리케이션에 제공하고, PostgreSQL은 그 기능을 사용해요(
wal_sync_method파라미터로 방식을 조절해요). - 다음은 디스크 드라이브 컨트롤러의 캐시인데, RAID 컨트롤러 카드에서 특히 흔해요. 일부는 write-through(쓰기가 도착하자마자 드라이브로), 일부는 write-back(나중에 드라이브로) 방식이에요. 이 캐시의 메모리는 휘발성이라 전원 손실 시 내용이 사라질 수 있다는 게 신뢰성 위험 요소죠. 더 좋은 컨트롤러 카드는 **BBU(Battery-Backup Unit)**를 달아서, 전원이 나가도 배터리로 캐시에 전원을 공급하고 복구 후 데이터를 디스크에 씁니다.
- 마지막으로 대부분의 디스크 드라이브 자체 캐시가 있어요. 역시 write-through와 write-back이 섞여 있고, write-back 드라이브 캐시는 컨트롤러 캐시와 똑같은 데이터 손실 우려가 있어요. 소비자용 IDE·SATA 드라이브는 전원 손실에도 살아남지 못하는 write-back 캐시일 가능성이 특히 높고, SSD도 휘발성 write-back 캐시를 가진 경우가 많아요.
캐시를 꺼야 하는 이유와 방법
이런 캐시들은 보통 비활성화할 수 있는데, 방법은 OS·드라이브 종류마다 달라요.
- Linux에서 IDE·SATA 드라이브는
hdparm -I로 조회할 수 있어요.Write cache옆에*가 있으면 쓰기 캐싱이 켜진 상태이고,hdparm -W 0으로 끌 수 있어요. SCSI 드라이브는 sdparm을 쓰는데,sdparm --get=WCE로 쓰기 캐시 활성 여부를 확인하고sdparm --clear=WCE로 비활성화해요. - FreeBSD에서 IDE 드라이브는
camcontrol identify로 조회하고,hw.ata계열 설정으로 쓰기 캐싱을 끌 수 있어요 (환경에 따라 명령·설정이 다르니 공식 문서를 함께 참고하세요).
부분 페이지 쓰기(Partial Page Writes)와 full_page_writes
쓰기 백 캐시가 또 다른 위험을 만들기도 해요. 이런 실패를 막기 위해 PostgreSQL은 실제 페이지를 디스크에서 수정하기 전에, 전체 페이지 이미지(full page image)를 주기적으로 영구 WAL 저장소에 기록해요. 이 덕분에 크래시 복구 중 WAL로부터 부분적으로만 쓰여진 페이지를 복원할 수 있죠.
만약 ZFS처럼 부분 페이지 쓰기를 막아주는 파일 시스템을 쓰고 있다면 full_page_writes 파라미터를 꺼서 페이지 이미지 기록을 중단할 수 있어요. BBU 디스크 컨트롤러는 데이터가 BBU에 전체(8kB) 페이지로 쓰인다는 걸 보장하지 않는 한 부분 페이지 쓰기를 막아주지 못합니다.
데이터 손상으로부터의 보호
PostgreSQL은 하드웨어 오류나 매체 노후로 인한 데이터 손상(가비지 데이터 읽기·쓰기 등)에도 대비해요.
- WAL 파일의 각 개별 레코드는 CRC-32C(32비트) 체크로 보호돼서 레코드 내용의 정확성을 판별할 수 있어요. CRC 값은 각 WAL 레코드를 쓸 때 설정되고, 크래시 복구·아카이브 복구·복제 중에 검사됩니다.
- 데이터 페이지는 기본적으로 체크섬되며, WAL 레코드에 기록된 전체 페이지 이미지는 항상 체크섬으로 보호돼요.
pg_xact,pg_subtrans,pg_multixact,pg_serial,pg_notify,pg_stat,pg_snapshots같은 내부 데이터 구조와 full page write로 보호되는 페이지들은 직접 체크섬되지 않아요. 다만 이들이 영구적인 곳에서는 최근 변경을 크래시 복구 시 정확히 재구성할 수 있도록 WAL 레코드가 쓰이고, 그 WAL 레코드는 위에서 말한 대로 보호돼요.pg_twophase의 개별 상태 파일은 CRC-32C로 보호됩니다.- 대형 SQL 쿼리에서 정렬·구체화(materialization)·중간 결과에 쓰이는 임시 데이터 파일은 현재 체크섬되지 않고, 그 파일 변경에 대한 WAL 레코드도 쓰이지 않아요.
메모리 오류에 관해서는
PostgreSQL은 교정 가능한 정정 메모리 오류까지는 막아주지 못해요. 업계 표준의 ECC(오류 정정 코드) 또는 그보다 나은 보호를 쓰는 RAM에서 운영하는 걸 전제로 합니다.
더 알아보기 (Learn more)
- WAL 구성 (wal-configuration) — 체크포인트·sync 방법 등 파라미터
- 비동기 커밋 (wal-async-commit) — 커밋 동기화와 내구성의 트레이드오프
- WAL 소개 (wal-intro) — WAL 개념과 작동 원리