PostgreSQL 18에서 즉시 데이터베이스 복제 구현
(boringsql.com)- PostgreSQL 18은 파일 복제 전략(FILE_COPY) 과 파일 시스템 클론 기능을 결합해 데이터베이스를 거의 즉시 복제할 수 있음
- 새로운 설정값
file_copy_method = clone을 사용하면 XFS, ZFS, APFS 등 현대적 파일시스템의 복제 기능(FICLONE) 을 활용 가능 - 벤치마크 결과, 6GB 데이터베이스 복제 시 기존 WAL_LOG 방식은 약 67초, 클론 방식은 0.2초 수준으로 단축됨
- 복제된 데이터베이스는 초기에는 동일한 물리 블록을 공유하지만, 쓰기 작업 시 copy-on-write로 분리됨
- 단, 활성 연결이 없는 상태에서만 복제 가능하며, 단일 파일시스템 내에서만 작동하는 제약 존재
PostgreSQL의 템플릿 기반 복제 구조
- PostgreSQL은
CREATE DATABASE dbname명령 시 내부적으로template1데이터베이스를 복제해 새 데이터베이스를 생성- 이는
CREATE DATABASE dbname TEMPLATE template1과 동일한 동작
- 이는
-
template1대신 다른 데이터베이스를 지정할 수 있어, 사용자 정의 템플릿을 활용한 복제 가능 - PostgreSQL 18에서는 이 템플릿 시스템을 즉시 복제 가능한 구조로 확장
CREATE DATABASE ... STRATEGY
- PostgreSQL 15부터
CREATE DATABASE ... STRATEGY매개변수가 도입되어 복제 방식 선택 가능- 기본값은
WAL_LOG로, Write-Ahead Log를 통한 블록 단위 복제 수행 - 이 방식은 I/O 부하를 줄이고 동시성 지원을 개선하지만, 대용량 복제 시 속도가 느림
- 기본값은
-
STRATEGY=FILE_COPY를 지정하면 기존 파일 복사 방식으로 되돌릴 수 있으며, PostgreSQL 18에서는 이를 기반으로 새로운 복제 옵션 추가
FILE_COPY와 file_copy_method
- PostgreSQL 18의
file_copy_method설정은 운영체제 수준의 파일 복제 방식을 제어- 기본값은
copy이며, 모든 바이트를 읽고 새 위치에 기록 -
clone으로 변경하면 파일시스템의 클론 기능(FICLONE) 을 사용해 즉시 복제 및 추가 공간 소모 없음
- 기본값은
- 지원 파일시스템: XFS, ZFS, APFS, FreeBSD ZFS
- 설정 절차
- 해당 파일시스템 위에 PostgreSQL 클러스터 구성
-
file_copy_method = clone설정 후 재로드
벤치마크 결과
- 약 6GB 크기의 테스트 데이터베이스(
source_db) 생성 후 두 가지 방식 비교-
WAL_LOG방식: 67,000ms (약 67초) -
FILE_COPY+clone방식: 212ms
-
- 동일한 데이터 크기에서 약 300배 이상 속도 향상 확인
- 복제된 데이터베이스(
fast_clone)는 추가 디스크 공간을 거의 사용하지 않음
복제된 데이터의 동작 원리
-
file_copy_method = clone사용 시, 파일시스템 메타데이터만 복제되어 두 데이터베이스가 동일한 물리 블록을 공유 - PostgreSQL이 보고하는 데이터베이스 크기는 논리적 크기(약 6GB)로 동일
- 쓰기 작업 발생 시 copy-on-write(COW) 가 작동하여 해당 페이지가 분리됨
- 수정된 행이 포함된 페이지
- 새 튜플이 기록되는 페이지
- 인덱스 페이지 및 FSM, visibility map 페이지 등
- VACUUM 실행 시에도 추가적인 페이지 분리 발생
XFS에서의 공유 블록 검증
-
filefrag -v명령으로 두 데이터베이스의 물리 블록 공유 여부 확인- 초기 상태에서는 모든 extents가
shared로 표시 - 일부 행을 업데이트하면 첫 40블록(약 160KB)이 분리되어 서로 다른 물리 주소로 변경
- 나머지 extents는 여전히 공유 상태 유지
- 초기 상태에서는 모든 extents가
주의사항 및 제약
-
복제 시 원본 데이터베이스에 활성 연결이 없어야 함
- 이는 PostgreSQL의 제약이며, 파일시스템 문제는 아님
- 실서비스 환경에서는 별도의 템플릿 데이터베이스를 사용하는 것이 일반적
-
단일 파일시스템 내에서만 복제 가능
- 여러 테이블스페이스가 서로 다른 마운트 포인트에 있을 경우, 일반 복사로 대체됨
-
클라우드 관리형 서비스(AWS RDS, Google Cloud SQL 등) 에서는 파일시스템 접근이 불가하므로 이 기능 사용 불가
- 자체 VM이나 베어메탈 환경에서는 완전한 제어 가능
결론
- PostgreSQL 18의
file_copy_method = clone기능은 운영체제 수준의 클론 기능을 직접 활용해
대용량 데이터베이스 복제 시간을 극적으로 단축 - 테스트, 개발, 학습 환경에서 즉시 복제 및 리셋 가능한 데이터베이스 워크플로우 구현 가능
- 단, 활성 연결 제약과 파일시스템 단일성을 고려한 운영 설계 필요
Hacker News 의견들
-
기다릴 수 없거나 PG18의 완전한 인스턴스 격리가 필요한 사람들을 위해, 나는 ZFS 스냅샷을 이용해 즉시 브랜칭하는 도구 Velo를 만들었음
어떤 PostgreSQL 버전에서도 작동하며, 각 브랜치는 독립된 컨테이너와 포트를 가짐
100GB DB 기준 약 2~5초면 생성 가능함
PG18 방식과의 차이는, 단일 인스턴스를 공유하지 않고 완전한 서버 격리를 제공한다는 점임
GitHub 링크- 다른 댓글에서 Claude Code 사용에 대한 불만이 있었지만, GitHub 페이지의 데모 영상을 보고 흥미롭게 느꼈음
- 요즘 대부분의 소프트웨어가 AI 에이전트의 도움을 받아 작성되는데, 왜 불평이 나오는지 모르겠음. 접근 방식이 흥미로움
- 나도 비슷한 걸 btrfs로 프로토타입 해보려던 참이었음
- “너”라는 표현이 흥미롭다고 생각했는데, 표절했다는 말이 있어서 좀 놀랐음
-
예전에 회사가 RDS로 마이그레이션할 때 비슷한 시스템을 직접 구축했음
프로덕션 마이그레이션 중 자주 문제가 생겨서, 이를 방지하기 위해 다음 단계를 자동화했음- RDS DB를 복제하거나 백업에서 새 인스턴스를 생성
- ARN으로부터 CNAME 또는 퍼블릭 IP 추출
- 앱의 DB 연결 설정에 반영
- 가짜 프로덕션 환경에서 마이그레이션 실행
이 과정 덕분에 로컬이나 CI에서는 잡히지 않던 프로덕션 특유의 버그를 많이 잡을 수 있었음
이후 간단한 Ruby 스크립트로 자동화했고, 아직도 그 스크립트를 사용 중이라고 들었음
- 나도 그런 “데이터 특이성 때문에 프로덕션에서만 실패하는 마이그레이션” 버그를 정말 싫어함. 몇 번은 그 때문에 릴리스를 취소한 적도 있음
-
템플릿 클로닝 전략이 설정 가능하다는 걸 이번에 처음 알았음
나는 Neon을 이용해 실시간 통합 환경을 만들었고, 내 Golang 프로젝트 pgtestdb 에서는 각 테스트마다 완전한 스키마 마이그레이션이 적용된 Postgres DB를 생성함
예전에 스타트업에서 btrfs로 즉시 스테이징 DB를 만드는 걸 본 적 있는데, 비슷한 아이디어가 반복 등장하는 게 흥미로움
이런 빠른 복제와 테스트는 Postgres와 Sqlite의 큰 장점이며, Clickhouse나 MySQL에서도 가능했으면 좋겠음 -
요즘 PostgreSQL이 거의 모든 SQL 용도를 커버하는 만능 DB가 된 것 같음
게다가 무료임
이제 굳이 다른 SQL DB를 쓸 이유가 있을까 궁금함- Postgres는 훌륭하지만, MySQL은 마스터-마스터 복제가 더 쉽고, MongoDB는 지리적 분산과 샤딩이 간단함
Clickhouse는 분석용으로 훨씬 빠르고, Cassandra 같은 DB는 쓰기 중심 워크로드에 유리함
즉, 각 DB마다 여전히 강점이 있음 - “모든 걸 잘한다”는 표현은 과장임
데이터가 많아지면 성능 저하나 마이그레이션 문제가 생김
내 경우, 기본 파티셔닝 성능이 떨어져서 직접 커스텀 파티션을 구현해야 했음 - Postgres는 여전히 MVCC 구현 방식(copy-on-write)이 비효율적임
이 선택이 부하가 커질 때 여러 부정적 영향을 줌 - 예전에는 MySQL/InnoDB가 업데이트 중심 워크로드에서 더 나았음
Uber의 블로그 글에서도 다뤘던 주제임
그래도 클라우드 환경에서는 Postgres를 가장 신뢰함 - Postgres에는 아직 Vitess 수준의 성숙한 대체재가 없음
그래서 대규모 OLTP 배포에서는 여전히 MySQL이 주로 쓰임 (예: YouTube, Uber)
- Postgres는 훌륭하지만, MySQL은 마스터-마스터 복제가 더 쉽고, MongoDB는 지리적 분산과 샤딩이 간단함
-
불변 데이터 구조(HAMT) 를 이용하면 파일시스템 종류와 상관없이 즉시 클론이 가능한 DB를 만들 수 있음
이론이라고 말했지만 실제로 구현해봤음
왜 이런 HAMT 기반 DB가 더 많지 않은지 이해가 안 됨- 나는 ClickHouse의 작성자인데, ClickHouse도 불변 데이터 파트를 사용해 테이블 복제를 지원함
관련 문서 링크 - Datomic에도 이런 클로닝 기능이 내장되어 있는지 궁금함. 예전부터 써보고 싶었지만 실제 앱을 만들기엔 아직 마음의 준비가 안 됨
- 나는 ClickHouse의 작성자인데, ClickHouse도 불변 데이터 파트를 사용해 테이블 복제를 지원함
-
Postgres v15에서 WAL_LOG가 기본으로 바뀐 걸 몰랐음
병렬 CI 테스트 환경에서는 FILE_COPY 전략으로 되돌리는 게 더 합리적임
예전 프로젝트 integresql에 관련 이슈를 올렸음 -
로컬에서 Postgres 기반 앱을 테스트하기 위한 간단한 GUI 도구 pgtt 를 만든 적 있음
개발 환경 설정을 훨씬 단순화해줌- README만 봐서는 잘 모르겠는데, 템플릿을 스냅샷처럼 다루는 구조인지 궁금함
SQL 마이그레이션 반복 작업에 도움이 될 것 같음 - README에 GUI 스크린샷이 있으면 좋겠고, Docker 링크가 깨져 있음
- README만 봐서는 잘 모르겠는데, 템플릿을 스냅샷처럼 다루는 구조인지 궁금함
-
블로그의 다른 글들도 읽어봤는데 전반적으로 훌륭함
특히 Postgres의 range 타입을 처음 알게 되었음- range 타입은 시간/날짜 구간 겹침 계산 같은 데서 정말 유용함
-
MariaDB에서도 이런 기능이 있는지 궁금함
테스트마다 DB를 초기 상태로 되돌리는 게 느려서 고민 중임
프로덕션에서 MariaDB를 쓰기 때문에 DB를 바꾸긴 어려움
Postgres 쪽이 더 좋아 보이긴 함- 각 테스트를 트랜잭션 세션 안에서 실행하고, 끝날 때 롤백하면 빠르게 초기 상태로 복원 가능함
이 방식이 꽤 효율적임 - DB를 재시작해도 괜찮다면 LVM이나 btrfs 스냅샷을 파일시스템 레벨에서 사용하는 것도 방법임
- 각 테스트를 트랜잭션 세션 안에서 실행하고, 끝날 때 롤백하면 빠르게 초기 상태로 복원 가능함
-
AWS에서도 유사한 기능을 지원함
Aurora 클론 문서- Aurora의 클론은 스토리지 레벨에서 copy-on-write로 동작하지만, 여전히 새 클러스터를 프로비저닝해야 해서 약 10분 정도 걸림
통합 테스트용으로는 비현실적임 - Aurora는 클러스터 단위 복제이고, 여기서 논의된 건 데이터베이스 단위 복제임
- Aurora의 클론은 스토리지 레벨에서 copy-on-write로 동작하지만, 여전히 새 클러스터를 프로비저닝해야 해서 약 10분 정도 걸림