백업과 복원 가능 기간¶
대상의 기록은 하나의 체인입니다. 일정에 따른 전체 백업과, 그 사이를 잇는 연속적인 변경 스트림(Postgres WAL, MySQL binlog)으로 이루어집니다. 전체 백업과 그 이후의 변경 사항이 포괄하는 모든 초를 복원할 수 있습니다. 이 구간이 특정 시점 복원 가능 기간입니다.
gantt
dateFormat YYYY-MM-DD HH:mm
axisFormat %a %d
section Full backups
daily full :milestone, 2026-10-01 02:07, 0d
daily full :milestone, 2026-10-02 02:07, 0d
daily full :milestone, 2026-10-03 02:07, 0d
daily full :milestone, 2026-10-04 02:07, 0d
section Change stream
WAL / binlog segments :active, 2026-10-01 02:07, 2026-10-04 18:00
전체 백업¶
| 엔진 | 모드 | 도구 | 복원 |
|---|---|---|---|
| Postgres 15–17 | physical (기본값) |
복제 프로토콜을 통한 pg_basebackup -Ft -X fetch |
기준 백업 + 초 단위까지 WAL 재생 |
| Postgres 15–17 | logical |
pg_dump -Fc, 데이터베이스마다 오브젝트 하나; 테이블 제외와 선택적 내보내기 |
pg_restore, 물리 체인이 있으면 이를 통한 WAL 재생 |
| MySQL 8.4 | logical |
mysqldump --single-transaction --source-data=2 (루틴, 이벤트, 트리거) |
불러오기 + 초 단위까지 binlog 재생 |
모든 백업은 인벤토리를 기록합니다. 데이터베이스, 테이블, 열, 인덱스, 추정 행 수와 크기, 그리고 마이그레이션
테이블이 있으면 마이그레이션 버전입니다. 콘솔과 tenax diff는 이것을 비교합니다.
변경 스트림¶
특정 시점 복구를 쓰는 대상마다 streamer가 하나씩 있습니다.
- Postgres: 물리 복제 슬롯에 연결하는 Tenax 자체 WAL 수신기(ADR 0005). 슬롯 덕분에 streamer가 재시작하는 동안에도 WAL이 손실되지 않습니다.
- MySQL: 마지막 전체 백업의 binlog 위치부터
mysqlbinlog --read-from-remote-server --raw --stop-never.
세그먼트는 완료되는 대로 업로드되며, 아직 쓰이고 있는 세그먼트도 partialInterval마다(기본값 60초) 업로드되므로
마지막 1분도 복원할 수 있습니다. 각 세그먼트에는 요약이 담깁니다. 테이블별 커밋, INSERT, UPDATE, DELETE, DDL,
그리고 선택적으로 마스킹된 행 미리 보기입니다.
스트림이 끊기면(슬롯 손실, binlog 삭제) Tenax는 체인을 끊어진 것으로 표시하고, 알림을 보내며
(TenaxStreamChainBroken), 새 체인을 시작하고 즉시 전체 백업을 수행합니다(사유 chain-restart). 이전 기간은
끊긴 지점까지 계속 복원할 수 있습니다.
보존¶
전체 백업은 티어별로 보존되고, 세그먼트는 복원 가능 기간에 필요한 만큼만 보존되며, 가비지 컬렉션이 나머지를 모두 삭제합니다. 고정된 것은 절대 삭제하지 않습니다.
| 프리셋 | 기간 | 일간 | 주간 | 월간 | 연간 |
|---|---|---|---|---|---|
prod |
7일 | 14 | 8 | 12 | 5 |
dev |
3일 | 7 | 4 | 3 | 0 |
critical |
14일 | 30 | 12 | 24 | 7 |
하루 중 처음 커밋된 전체 백업이 그날의 일간 백업이 되고, ISO 주 중 처음 것이 주간 백업이 되는 식입니다. 백업 하나가
여러 티어를 가질 수 있으며, 아무것도 복사되지 않습니다. 고정(tenax pin <id> --reason …)은 티어와 관계없이 백업을
유지합니다. GC는 삭제하기 전에 계획을 버킷에 기록하고, 데이터보다 매니페스트를 먼저 삭제하며, 고아 업로드와 미완료
업로드는 하루 뒤에 정리합니다.
저장 형식¶
<store prefix>/<org>/<project>/<namespace>/<target>/
full/<backup-id>/manifest.json # written last: the commit marker
full/<backup-id>/data/<database>.zst.age # dumps or the base backup tar
full/<backup-id>/inventory.json.zst.age # also readable with the catalog key
full/<backup-id>/tags.json # tiers, pins, verification results
stream/…/<segment>.zst.age # WAL / binlog segments and their summaries
stream/position.json # the streamer's confirmed position
- 압축: 암호화 전에 정책의 레벨로 zstd 압축을 한 번 수행하며, 기본적으로 켜져 있습니다
(ADR 0013).
compression.algorithm: none이면 데이터를 그대로 저장합니다. - 암호화: 모든 오브젝트는 클라이언트에서 스토어의 수신자에 맞춰 age로 암호화됩니다. 버킷은 평문을 절대 보지 못합니다.
- 무결성: 모든 오브젝트의 크기와 SHA-256이 매니페스트에 있으며, 읽을 때마다 검증됩니다.
- 커밋: 백업은
manifest.json이 기록된 뒤에야 존재합니다. 그 전에 크래시가 나면 GC가 삭제할 고아 오브젝트만 남을 뿐, 완성된 것처럼 보이는 백업은 절대 남지 않습니다.
부하 제어¶
백업은 프로덕션과 무작정 경쟁하지 않습니다. 호스트별, 대상별, 전역 슬롯, 대역폭 제한, 우선순위, 일정의 지터, 그리고
서버에 활성 연결이 너무 많거나 복제 지연이 크거나 오래 실행되는 트랜잭션이 있으면 전체 백업을 연기하는 부하 보호
장치가 있습니다. 이 모든 것은 BackupPolicy에서 설정합니다.