본문으로 건너뛰기

5.2 DBLab Engine

앞 장의 ZFS 절차를 매번 수동으로 수행하려면 snapshot 주기, clone 수명, port 배정, 설정 정리를 누군가 기억해야 합니다. DBLab Engine(구 Database Lab Engine)은 이러한 반복 작업을 API와 CLI로 감싼 Apache 2.0 도구입니다. Postgres.ai가 만들고 유지합니다. 4.0부터 dblab branch, dblab commit, dblab switch 같은 Git 어휘의 명령이 추가되어 Neon과 비교할 만한 워크플로우를 갖추었습니다.

이 장도 Linux와 ZFS가 필요하므로 이 노트에서는 실측하지 않았습니다. 명령은 공식 CLI 레퍼런스를 기준으로 정리했습니다. 설치 절차의 세부 옵션은 공식 문서 링크로 대신합니다.

요약

  • 원리는 ZFS(기본) 또는 LVM의 snapshot과 thin clone입니다. 5.1에서 설명한 것과 같은 계층에서 CoW가 일어납니다.
  • 생성 시간은 데이터 크기와 거의 무관합니다. 공식 자료에서 제시한 예는 1 TiB 데이터베이스 clone이 약 10초입니다. 과거 자료에는 10 TiB가 수 초라는 사례도 있습니다. 버전, 하드웨어, 동시 clone 수가 함께 적히지 않은 수치이므로 사례로만 참고하고 보장값으로 사용하지 않습니다.
  • clone마다 별도 PostgreSQL 컨테이너가 기동되고 고유 port를 받습니다. compute와 storage가 분리되지는 않습니다. 그러나 branch마다 endpoint 하나를 제공한다는 사용자 경험은 Neon과 비슷합니다.
  • 원본 데이터베이스에는 ZFS도 Docker도 필요 없습니다. DBLab 서버가 원본에서 데이터를 가져와 자체 ZFS pool에 유지합니다. 원본은 자체 운영 PostgreSQL이든 RDS, Cloud SQL, Supabase 같은 관리형 서비스든 상관없습니다.

데이터를 가져오는 두 모드

DBLab은 원본에서 데이터를 받아 "골든 사본"을 만들고, 그 사본의 snapshot에서 clone을 만듭니다. 사본을 채우는 방법에 따라 모드가 나뉩니다.

모드방법갱신적합한 원본
physicalpg_basebackup, WAL-G, pgBackRest로 물리 복제 후 WAL 재생연속(WAL 스트림), PITR 가능자체 운영 PostgreSQL, 백업 저장소 접근 가능
logicalpg_dump/pg_restore주기적 전체 재적재관리형 서비스, 일부 테이블만 필요할 때

physical 모드는 원본과 바이트 단위로 동일한 사본이므로 실행 계획과 bloat까지 재현합니다. logical 모드는 관리형 서비스처럼 물리 접근이 불가능한 원본에 사용합니다. 마스킹이나 부분 추출을 적용하기에도 좋습니다. logical 모드는 Neon의 schema-only branch에 마스킹 데이터를 채우는 흐름에 대응합니다.

설치 개요

서버는 Docker 이미지 postgresai/dblab-server로 배포합니다. 설정 파일 server.yml에는 ZFS pool 이름, 데이터 소스 모드, snapshot 주기, clone 보존 정책을 적습니다. 컨테이너는 Docker 소켓과 설정, 메타데이터, ZFS 마운트 경로를 볼륨으로 받습니다. API는 2345 port에 노출합니다. 정확한 docker run 인자와 server.yml 예제는 배포 버전마다 다르므로 공식 문서를 그대로 따르는 것이 안전합니다.

클라이언트 CLI dblab은 별도 바이너리이며, 처음 실행할 때 서버 주소와 토큰을 등록합니다.

dblab init --environment-id dev --url "http://127.0.0.1:2345" \
--token "SECRET_TOKEN" --insecure
dblab instance status

--insecure는 TLS가 없는 로컬 연결에 사용합니다. 원격 서버는 TLS나 SSH 포트 포워딩 뒤에 둡니다.

branch, commit, clone 워크플로우

4.0의 개념은 세 층입니다. branch는 이름이 있는 snapshot 계열입니다. snapshot은 그 계열 위의 commit입니다. clone은 snapshot에서 기동한 쓰기 가능 인스턴스입니다.

# branch 목록과 생성
dblab branch
dblab branch test # 현재 기본 branch에서 분기
dblab branch --parent-branch dev test # dev에서 분기
dblab branch --snapshot-id <snapshot_id> test # 특정 snapshot에서 분기

# branch 위에 clone 기동
dblab clone create --username app --password secret --branch test --id test-clone
dblab switch test

# clone에서 작업한 결과를 새 snapshot(commit)으로 고정
dblab commit --clone-id test-clone --message "index rebuild rehearsal"
dblab log test

# clone을 snapshot 상태로 되돌리기
dblab clone reset test-clone
dblab clone reset --latest test-clone

# 정리
dblab branch --delete test

--parent-branch--snapshot-id는 동시에 지정하지 않습니다. dblab commit은 Neon과의 차이가 가장 두드러지는 지점입니다. Neon은 branch의 모든 LSN을 자동으로 history에 남깁니다. 반면 DBLab은 사용자가 commit한 시점만 snapshot으로 남깁니다. DBLab은 "이 상태를 이름 붙여 보존"하는 행위가 명시적이므로 리허설 결과를 팀에 공유하기 쉽습니다.

clone에는 서버가 배정한 port로 접속합니다. 원격이라면 CLI가 SSH 포트 포워딩을 대신합니다.

dblab --forwarding-server-url "ssh://dba@dblab-host:22" --forwarding-local-port 8888 \
clone port-forward test-clone
psql "host=127.0.0.1 port=8888 user=app dbname=postgres"

--forwarding-server-url--forwarding-local-port는 전역 옵션입니다. 공식 synopsis는 dblab [global options] clone port-forward CLONE_ID 형태입니다. 이 옵션을 clone 뒤에 두면 알 수 없는 플래그 오류가 발생합니다.

snapshot과 보존 정책

dblab snapshot list
dblab snapshot create --pool dblab_pool
dblab snapshot delete "dblab_pool/dataset_1@snapshot_20241028174127"

snapshot 이름에 ZFS 경로가 그대로 쓰인다는 점에서 내부 구조가 드러납니다. 서버 설정의 보존 정책에 따라 오래된 snapshot과 clone을 자동으로 삭제합니다. 삭제하면 안 되는 clone에는 --protected 8h처럼 보호 시간을 설정합니다. 이 계층에서는 5.1에서 언급한 "snapshot이 원본 크기만큼 자라는 문제"를 정책으로 관리합니다.

CI에서 쓰는 흐름

DBLab이 Neon보다 먼저 자리 잡은 용도는 마이그레이션 검증입니다. 파이프라인에서 dblab clone create로 운영 크기의 clone을 받아 마이그레이션 SQL을 실행합니다. 소요 시간과 lock 대기를 측정한 뒤 dblab clone reset 또는 삭제로 작업을 끝냅니다. 전체 데이터가 있으므로 "개발 DB에서는 1초였는데 운영에서는 40분"이라는 종류의 사고를 사전에 발견합니다.

CLONE=ci-$CI_PIPELINE_ID
dblab clone create --username ci --password "$CI_DB_PASS" --branch main --id "$CLONE"
PORT=$(dblab clone status "$CLONE" | grep -o 'port: [0-9]*' | cut -d' ' -f2)
psql "host=dblab-host port=$PORT user=ci dbname=app" -f migrations/next.sql
dblab clone destroy "$CLONE"

clone status의 출력 형식은 버전에 따라 다릅니다. 레퍼런스에서 JSON 출력 옵션을 제공하는지 확인한 뒤 파싱합니다.

에디션과 라이선스

엔진은 Apache 2.0이고 원본 호환성은 에디션에 따라 달라지지 않습니다. 공식 저장소는 자체 운영 PostgreSQL과 RDS, Cloud SQL, Supabase, Timescale 같은 관리형 서비스를 모두 원본으로 사용할 수 있다고 설명합니다. 관리형 원본에서 물리 접근이 제한되는 이유는 라이선스가 아니라 서비스 제약입니다. 이 경우 logical 모드를 사용합니다.

에디션에 따라 설치 자동화와 지원, 상용 기능이 달라집니다. Community Edition은 엔진과 CLI를 직접 설치하고 server.yml도 직접 관리합니다. Standard Edition은 설치 관리자와 상용 지원을 제공합니다. Enterprise Edition은 통합 control plane, 사용자 관리, 감사, SSO를 더합니다. 소수의 DBA가 도구와 설정을 직접 관리한다면 Community Edition으로 충분한 경우가 많습니다. 여러 팀에 self-service 방식으로 제공하려면 상위 에디션의 사용자 관리와 감사가 필요합니다.

Neon과 나란히 놓으면

공통점은 사용자 경험입니다. 이름 있는 branch, 즉시 생기는 사본, 부모로 되돌리기를 모두 제공합니다. 차이는 작동 계층입니다. Neon은 저장 엔진 안에서 페이지 버전 단위로 CoW를 수행합니다. DBLab은 파일시스템에서 ZFS 블록 단위로 CoW를 수행합니다. 따라서 DBLab의 clone은 vanilla PostgreSQL이고 확장과 버전 제약이 없습니다. 다만 clone마다 PostgreSQL 프로세스와 메모리를 따로 소비하며 scale-to-zero가 없습니다. 어느 쪽이 적합한지는 5.5 온프레미스 선택 매트릭스에서 정리합니다.

운영에서 걸리는 것

  • clone에는 원본의 접속 정보가 그대로 복제됩니다. DBLab이 clone 기동 시 별도 사용자와 비밀번호를 만들어 줍니다. 그러나 원본의 pg_hba.conf 규칙은 남아 있으므로 별도의 네트워크 경계로 격리합니다.
  • physical 모드는 선택한 retrieval 방식에 따라 의존 대상이 달라집니다. WAL-G나 pgBackRest 구성은 원본의 백업 저장소에 의존합니다. pg_basebackup -X stream이나 직접 스트리밍 구성은 원본의 replication 연결에 의존합니다. 해당 공급원이 끊기면 골든 사본 갱신이 멈춥니다. 그 시점부터 만든 clone은 오래된 데이터를 보여 줍니다. 갱신 지연을 모니터링 항목에 포함합니다.
  • snapshot 주기를 짧게 하고 보존 기간을 길게 설정하면 ZFS pool이 원본 변경량만큼 자랍니다. 보존 정책은 디스크 용량을 고려해 정합니다.
  • clone에서 pg_upgrade나 대량 재작성을 실행하면 해당 clone만 원본 크기만큼 블록을 새로 씁니다. 이러한 작업을 수행하는 clone은 수명을 짧게 설정합니다.

연습 문제

  1. physical 모드와 logical 모드 각각에서 원본의 bloat가 clone에 재현되는지 예측하고 그 이유를 적습니다.
  2. dblab commit 없이 clone만 계속 만들 때와 commit을 남길 때 ZFS snapshot 수가 어떻게 달라지는지 설명합니다.
  3. CI 파이프라인에서 clone을 삭제하지 못하고 종료된 경우에 대비한 보존 정책을 설계합니다.

참고