PostgreSQL 19에서 data_checksums가 또 하나의 재시작 파라미터에서 벗어났어요. 이제 실행 중인 클러스터에서 재시작도 정지도 없이 page checksum을 켜고 끌 수 있어요. SQL 함수 하나를 실행하면 background worker가 모든 page를 다시 쓰면서 checksum을 입히고, 그동안 클러스터는 평소처럼 트래픽을 받아요.
이 글은 The Build의 Christophe Pettus(크리스토프 페투스)가 정리한 “All Your GUCs in a Row: data_checksums”를 한국어로 풀고, 13년에 걸친 data_checksums의 진화사와 PostgreSQL 19가 정확히 무엇을 바꿨는지를 DBA 시선으로 봅니다. 그리고 “온라인"이라는 단어가 “공짜"나 “즉시"를 뜻하지 않는다는 점까지 함께 짚습니다.
dbalog에는 PostgreSQL 19의 “재시작 없이 바꾼다” 계열 글이 이미 두 편 있습니다. wal_level이 고정값에서 동적 floor로 바뀐 이야기와 autovacuum_worker_slots로 worker 수를 재시작 없이 조절하는 이야기입니다. data_checksums의 온라인 전환은 그 흐름 위에 올라가는 또 한 칸입니다.
data_checksums가 무엇을 막아주나
data_checksums는 page 단위 checksum 기능을 켜는 read-only GUC입니다. 켜져 있으면 PostgreSQL은 data page를 디스크에 쓸 때마다 checksum을 계산해 page 안에 함께 적고, 그 page를 다시 읽어 올릴 때 checksum을 검증합니다.
값이 맞지 않으면 PostgreSQL은 깨진 데이터를 그대로 돌려주지 않고 error를 냅니다. 여기서 막아주는 대상은 silent data corruption, 즉 조용히 번지는 손상입니다.
- bit rot, 디스크 위 데이터가 시간이 지나며 미세하게 망가지는 현상
- 고장 직전의 디스크가 슬그머니 잘못된 비트를 돌려주는 경우
- “썼다"고 응답해 놓고 실제로는 쓰지 않은 storage layer의 거짓말
이런 손상은 error 없이 흘러갑니다. checksum이 없으면 PostgreSQL은 깨진 page를 멀쩡한 데이터로 믿고 그대로 읽어 들이고, 그 위에 연산을 쌓습니다. 문제를 알아챌 무렵엔 이미 backup에까지 손상이 번진 뒤입니다.
검증에 실패하면 PostgreSQL은 pg_stat_database의 checksum_failures 카운터를 올립니다. DBA는 이 값을 모니터링해 손상이 처음 감지된 시점을 잡아낼 수 있습니다.
비용은 어떻습니까. 2013년 도입 당시엔 checksum 계산 부담이 켤 가치가 없을 만큼 크다고 봤습니다. 그래서 기본값이 off였습니다. 그 뒤로 하드웨어가 좋아지면서 오버헤드는 한 자릿수 퍼센트 초반대까지 내려왔고, 손상을 조기에 잡는 가치에 비하면 충분히 감당할 만한 수준이 됐습니다.
과거엔 켜기가 왜 고통이었나
문제는 비용이 아니라 켜는 방법이었습니다. PostgreSQL 18까지 data_checksums를 켜는 길은 둘뿐이었고, 둘 다 운영 클러스터에는 무겁습니다.
첫째, initdb 시점에 정하는 것입니다. 클러스터를 처음 만들 때 checksum을 켜두면 그 클러스터는 평생 켜진 상태로 삽니다. 깔끔하지만 시점이 고약합니다. 이미 몇 년째 돌고 있는 운영 클러스터에는 적용할 길이 없습니다. “처음부터 켰어야 했다"는 후회만 남습니다.
둘째, pg_checksums로 오프라인 전환하는 것입니다. PostgreSQL 12에서 추가된 이 명령은 멈춰 있는 클러스터의 checksum 설정을 바꿔줍니다. 강조점은 “멈춰 있는"입니다.
# 반드시 클러스터를 먼저 정지한 상태에서 실행
pg_ctl -D /var/lib/pgsql/data stop
pg_checksums --enable -D /var/lib/pgsql/data
pg_ctl -D /var/lib/pgsql/data start
pg_checksums는 모든 heap과 index page를 한 장씩 읽어 checksum을 계산해 다시 씁니다. 멀티 테라바이트 클러스터라면 이 작업만 몇 시간이 걸립니다. 그리고 그 몇 시간 내내 클러스터는 내려가 있어야 합니다.
DBA에게 이건 사실상 “큰맘 먹고 잡는 점검 시간"입니다. 서비스 중단 공지를 내고, 새벽 시간을 확보하고, 작업이 예상보다 길어질 경우까지 대비해야 합니다. 그래서 많은 운영 클러스터가 checksum의 가치를 알면서도 “지금 켜기엔 다운타임이 부담"이라는 이유로 off인 채 남았습니다.
PostgreSQL 18에서 한 발 나아가긴 했습니다. initdb의 기본값이 checksum 켜짐으로 바뀌어, 새로 만드는 클러스터는 별도 조치 없이 checksum을 켠 채 출발합니다. 하지만 이는 새 클러스터 이야기입니다. 이미 돌고 있는 클러스터의 고민은 그대로였습니다.
PostgreSQL 19의 온라인 전환
PostgreSQL 19는 마지막 매듭을 풉니다. 클러스터를 멈추지 않고 재시작도 없이 SQL 함수 호출만으로 checksum을 켜고 끕니다. 새로 들어온 함수는 둘입니다.
pg_enable_data_checksums(cost_delay integer DEFAULT 0, cost_limit integer DEFAULT 100)
pg_disable_data_checksums()
켜는 동작은 이렇게 실행합니다.
SELECT pg_enable_data_checksums();
이 함수는 곧바로 반환됩니다. 밀리초 단위입니다. 하지만 그 시점에 checksum이 다 입혀진 것은 아닙니다. 실제 작업은 background에서 비동기로 흐릅니다.
내부 동작은 이렇습니다. background worker launcher가 데이터베이스마다 per-database worker를 띄웁니다. 이 worker는 storage를 가진 모든 relation의 buffer를 dirty로 표시합니다. dirty page는 디스크로 다시 쓰일 때 checksum을 계산해 함께 적게 됩니다. 모든 데이터베이스의 모든 relation이 처리되고 나면, 그제야 data_checksums 상태가 on으로 넘어갑니다.
OS의 process 목록에서도 이 launcher와 worker가 보입니다.
postgres: datachecksum launcher
postgres: datachecksum worker
진행 중에 data_checksums가 가질 수 있는 상태는 다음과 같습니다.
| 상태 | 의미 |
|---|---|
off | checksum 꺼짐 |
inprogress-on | 켜는 중, page 재작성 진행 중 |
on | 켜짐, 모든 page 처리 완료 |
inprogress-off | 끄는 중 |
SHOW로 현재 상태를 확인합니다.
SHOW data_checksums;
-- 진행 중: inprogress-on
-- 완료 후: on
끄는 동작도 같은 방식입니다.
SELECT pg_disable_data_checksums();
이 모든 과정에서 클러스터는 멈추지 않습니다. 읽기도 쓰기도 평소처럼 받습니다. PostgreSQL 19에서는 다운타임이 사라졌습니다.
전환 흐름 비교
오프라인 전환과 온라인 전환의 차이를 한눈에 보면 이렇습니다.
flowchart TD
A[checksum 켜야 함] --> B{PostgreSQL 버전}
B -->|18 이하| C[클러스터 정지]
C --> D[pg_checksums 실행]
D --> E[클러스터 재기동]
E --> F[on 완료]
B -->|19 이상| G[함수 실행
클러스터 가동 중]
G --> H[background worker가
page 재작성]
H --> F
PostgreSQL 18 이하의 경로는 정지-작업-재기동이라는 다운타임 구간을 통과해야 합니다. PostgreSQL 19는 그 구간 자체가 없습니다. 작업은 가동 중인 클러스터 위에서 background로 흐릅니다.
상태 전이로 보면 켜는 과정은 다음과 같이 움직입니다.
flowchart LR
A[off] -->|함수 실행| B[inprogress-on]
B -->|page 재작성 완료| C[on]
여기서 DBA가 기억할 점이 하나 있습니다. inprogress-on은 “켜지는 중"이지 “켜짐"이 아닙니다. 모든 page가 처리되기 전까지는 on으로 넘어가지 않습니다.
DBA 관점에서 보는 온라인 전환의 시간과 비용
함수가 밀리초 만에 반환된다고 해서 작업이 끝난 것은 아닙니다. 이 지점에서 운영 실수가 갈립니다. Christophe Pettus는 이 작업의 무게를 “minor version 업그레이드와 전체 클러스터 VACUUM FULL 사이 어디쯤"으로 보고 계획하라고 권합니다.
기억할 점을 정리하면 이렇습니다.
진짜 작업은 background에서 진행됩니다. 함수 반환은 시작 신호일 뿐이며, 멀티 테라바이트 클러스터에서 모든 page를 재작성하려면 몇 시간이 걸립니다.
이 작업은 다른 작업과 자원을 다툽니다. page 재작성은 autovacuum, 평상시 워크로드, backup 작업과 디스크 I/O를 두고 경쟁합니다. burst IOPS를 쓰는 클라우드 인스턴스라면 burst 예산을 일찍 소진하고 throttle 구간에 들어갑니다.
중간에 끊으면 일부 page에는 checksum이 입혀지고 일부에는 입혀지지 않은 mixed state로 남습니다. 이 상태 자체는 안전하지만, 작업이 끝나기 전까지 data_checksums는 on으로 넘어가지 않습니다. 오래 머물 상태는 아닙니다.
그래서 켜는 함수에는 throttle 제어가 붙어 있습니다. cost_delay와 cost_limit은 autovacuum의 vacuum cost 의미를 그대로 따릅니다. worker가 cost_limit만큼 작업 단위를 쌓을 때마다 cost_delay 밀리초씩 쉬게 해서, 평상시 워크로드에 주는 압박을 낮춥니다.
-- worker가 자원을 덜 차지하도록 천천히 진행
SELECT pg_enable_data_checksums(cost_delay => 1, cost_limit => 3000);
운영 현장에서 잡을 체크리스트는 단순합니다.
- 트래픽이 한가한 시간대를 골라 시작합니다.
- autovacuum이 급한 작업을 들고 있지 않은지 확인합니다.
- backup window와 겹치지 않게 합니다.
- 진행 중에는
pg_stat_io로 I/O 부하를, replication을 쓴다면 replica lag을 함께 봅니다.
PostgreSQL 19의 이번 변화를 앞선 두 글과 나란히 놓으면 방향이 또렷합니다. wal_level은 재시작 파라미터에서 동적 floor로, autovacuum worker 수는 재시작 없이 조절 가능하게, 그리고 이제 data_checksums는 클러스터를 멈추지 않고 켜고 끄는 대상이 됐습니다. “운영 중에 바꾸려면 재시작/정지가 필요하던 설정"의 목록이 한 칸씩 줄고 있습니다.
다만 방향이 같다고 비용까지 같진 않습니다. wal_level의 effective level 전환은 다음 checkpoint면 끝나지만, data_checksums의 온라인 전환은 디스크 위 모든 page를 다시 쓰는 무거운 작업입니다. “재시작이 사라졌다"와 “부담 없이 켤 수 있다"는 다른 말입니다. 다운타임은 없앴지만, I/O 비용과 소요 시간은 그대로 DBA의 계획표 위에 남습니다.
정리
data_checksums는 page 단위 checksum으로 silent data corruption을 조기에 잡아주는 기능입니다. 실패는pg_stat_database.checksum_failures로 드러납니다.- PostgreSQL 18까지는
initdb시점에 고정하거나, 클러스터를 정지하고pg_checksums로 오프라인 전환해야 했습니다. 운영 클러스터엔 다운타임이 부담이었습니다. - PostgreSQL 18부터
initdb기본값이 켜짐으로 바뀌어, 새 클러스터는 별도 조치 없이 checksum을 켠 채 출발합니다. - PostgreSQL 19는
pg_enable_data_checksums()/pg_disable_data_checksums()로 가동 중인 클러스터에서 재시작 없이 켜고 끌 수 있게 했습니다. background worker가 모든 page를 다시 쓰며, 진행 중 상태는inprogress-on/inprogress-off로 보입니다. - 다운타임은 사라졌지만 작업 자체는 무거워요. 멀티 테라바이트 클러스터에서 몇 시간이 걸리고 다른 I/O와 경쟁하므로,
cost_delay/cost_limitthrottle과 한가한 시간대 시작이 필요해요.
출처
- All Your GUCs in a Row: data_checksums — The Build
- Online Checksums Are Not Instant — The Build
- Waiting for PostgreSQL 19 – Online enabling and disabling of data checksums — depesz
- PostgreSQL 19: Online enabling of data checksums — dbi services
- PostgreSQL Documentation: Data Checksums
- PostgreSQL Documentation: pg_checksums