대상 독자: x-backup으로 PostgreSQL을 백업/복구하려는 운영자·개발자. 핵심: 외부
pg_dump/pg_restore없이 드라이버(tokio-postgres) 프로토콜만으로 풀 백업·복구·증분(logical decoding)·시점 복구(PITR)를 수행한다.
DB 종류는 source URI 스킴으로 자동 판별한다(postgres:// / postgresql:// → PostgreSQL,
그 외 → MongoDB). 별도 플래그가 필요 없다.
| 기능 | 명령 | 비고 |
|---|---|---|
| 풀 백업 | backup --type full |
스키마 DDL + COPY 데이터(xb-pg-v1) |
| 증분 백업 | backup --type incr |
logical decoding/pgoutput(xb-pg-incr-v1), opt-in |
| 풀 복구 | restore |
스키마 재생성 + COPY FROM STDIN |
| 시점 복구(PITR) | restore --at <RFC3339>|latest |
풀 복원 + 증분 DML 재생 |
| 상태 | status |
연결·버전·DB 크기·테이블/행 수 |
| 미리보기 | peek |
테이블/행 수·샘플 행 |
| 마이그레이션 | migrate |
PG→PG 드라이버 직접(외부 도구 없음) |
압축(zstd)·암호화(age/aes-256-gcm)·로컬/S3 destination·멀티 destination 복제는 Mongo 경로와 동일한 파이프라인을 그대로 탄다.
덤프/복구 대상: 테이블·제약(PK/FK/UNIQUE/CHECK)·인덱스·시퀀스(파라미터 포함)·행 데이터,
확장(extension), 타입(enum/domain/composite), 함수(f/p), 트리거, 뷰·머티리얼라이즈드 뷰,
파티셔닝(RANGE/LIST/DEFAULT — 부모 PARTITION BY + 자식 PARTITION OF, 다중 레벨; 자식
데이터를 직접 COPY), IDENTITY(GENERATED ALWAYS/BY DEFAULT)·생성(STORED) 컬럼.
미지원(경고만 — 백업은 진행):
- 집계(
a)/윈도우(w) 함수 —pg_get_functiondef가 정의를 주지 않는다. - 사용자 정의 range/base 타입.
[profiles.prod.source]
uri_env = "PROD_PG_URI" # 예: postgres://user:pass@host:5432/db?sslmode=require
[profiles.prod.features.incremental]
pg_logical = true # PG 증분 사용 여부(기본 false, 명시 opt-in)pg_logical(기본false):true면 풀 백업이 replication slot + publication(FOR ALL TABLES)을 만들어 그 시점부터 WAL을 잡고,backup --type incr로 변경을 캡처한다. 미사용 slot은 WAL을 무한 보존해 디스크를 채울 수 있으므로 명시적 opt-in이다.wal_level=logical(서버 전제, 증분에만): PG 증분은 logical decoding이 필요하다. 서버에서ALTER SYSTEM SET wal_level=logical;후 재시작한다(풀 백업/복구만 쓰면 불필요). 풀 백업 시pg_logical=true면SHOW wal_level로 사전 점검하고 아니면 거부한다(exit 3).sslmode(URI):prefer(기본)면 TLS 시도 후 미지원 서버엔 평문 폴백,require/verify-*면 TLS 강제(rustls + webpki 신뢰 루트).
# 풀 백업(증분 활성 프로파일이면 이때 slot+publication 생성)
x-backup backup --profile prod --type full
# 증분 백업(pg_logical=true 필요) — 직전 캡처 이후 변경만
x-backup backup --profile prod --type incr
# 풀 복구(다른 DB로 분리 복구)
x-backup restore --profile prod --target "postgres://u:p@host/restore_db" --force
# 시점 복구(PITR): 풀 + 증분을 목표 시각까지 재생
x-backup restore --profile prod --target "$URI" --at 2026-06-14T09:00:00Z --force
# 전체 재생(가용한 모든 증분):
x-backup restore --profile prod --target "$URI" --at latest --force--at은 RFC3339(UTC) 또는 latest. 경계는 각 변경의 commit 타임스탬프(아카이브 내장)로
거르므로 마이크로초 정밀도다. --id로 base 풀백업을 고정할 수 있다(미지정 시 최신 PG 풀백업).
- 아카이브 포맷: 풀
xb-pg-v1(태그 프레임 H/R/O/Q/T/D/X/E), 증분xb-pg-incr-v1(헤더/변경/끝 프레임, 변경당 BSON). - 증분 캡처:
pg_logical_slot_peek_binary_changes(비소비)로 pgoutput을 읽어 디코드 → 아카이브 저장 → 저장 성공 후pg_replication_slot_advance로 slot 전진(실패 시 다음에 재캡처 — 적용이 idempotent라 안전). - 증분 적용(복구):
session_replication_role=replica로 FK/트리거 우회, Insert=키 충돌 upsert(OVERRIDING SYSTEM VALUE), Update/Delete=키 기반. 값은 텍스트로 받아$n::text::<타입>로 캐스트(대상 카탈로그에서 컬럼명으로 타입 조회). 적용 후 IDENTITY/serial 시퀀스를max(컬럼)으로 재동기화한다(복구 후 PK 충돌 방지). - gap: slot이 없으면(드롭 등) 증분은 거부된다(
PrecheckFailed, exit 3) — 풀 백업을 다시 수행해 slot을 재생성한다.
함정·근거는 코드 주석과 메모리(pg-logical-decoding-apply, pg-identifier-quoting-and-regclass)
참조.
make postgres-up # docker compose로 PG(wal_level=logical) 기동(증분 가능)
make test-pg # PG 엔진 단위 테스트(engine::postgres, DB 불필요)
make scenario-pg # PG E2E: 풀→증분×2→복구→PITR(전체/중간)→시퀀스 재동기화
make postgres-down # 정리CI(postgres 잡, push main + nightly)도 동일하게 docker compose로 PG를 띄워 scenario-pg를
돌린다(상세: ci.md). GitHub 서비스 컨테이너는 command(-c wal_level=logical)
오버라이드를 지원하지 않아 docker compose를 쓴다.
Python venv처럼 디렉터리 하나에 config·키·store를 격리해 테스트한다. 전역 설정을 건드리지
않고, rm -rf로 흔적 없이 지워진다(activate가 XB_CONFIG/XB_PROFILE/시크릿/PATH를 잡음).
scripts/xbenv new ./ws --engine pg # 워크스페이스 + 격리 DB(xbenv_ws, xbenv_ws_restore) 생성
source ./ws/activate # 활성화 → 프롬프트 (xbenv:ws)
x-backup backup --type full # --profile 불필요(XB_PROFILE 자동), pg_logical 켜짐
x-backup backup --type incr
x-backup restore --target "$XBENV_TARGET_URI" --at latest --force
deactivate # 환경 원복
scripts/xbenv destroy ./ws # 워크스페이스 + 격리 DB + slot 제거--engine mongo면 source=:27017 RS / target=:27117 컨테이너를 가리킨다. 자세한 사용법은
scripts/xbenv help.
make 단축 — 빌드 + 컨테이너 기동 + 워크스페이스 생성을 한 번에(기본 경로 .xbenv-pg/
.xbenv-mongo, DIR=로 변경):
make xbenv-pg # build + postgres-up + .xbenv-pg 생성 → activate 한 줄 출력
make xbenv-mongo # build + mongodb-up + .xbenv-mongo 생성
make xbenv-clean # 워크스페이스(+격리 DB) 제거활성화(source)는 부모 셸 환경을 바꿔야 해서 make 타깃으로는 불가하다(레시피는 서브셸에서
실행 — venv도 source가 별도인 이유). make는 마지막에 실행할 source ... 한 줄을 출력한다.
한 단어로 끝내려면 셸 rc에 래퍼를 두면 된다:
# ~/.zshrc 또는 ~/.bashrc
xbenv() { make -s "xbenv-$1" && source ".xbenv-$1/activate"; }
# 사용: xbenv pg / xbenv mongo