백업 보관 정책: retention, immutable backup, 비용 최적화
MySQL 백업의 복구 가능 기간과 의존성을 기준으로 보존·삭제 정책을 설계하고, 불변 백업의 보호 범위와 저장 비용 최적화 원칙을 정리한다.
백업 보관 정책은 오래된 파일을 정리하는 규칙이 아니라, 어떤 사고에 대해 어느 시점까지 복구할 수 있는지를 유지하는 규칙이다. 백업 작업이 매일 성공해도 기준 전체 백업을 먼저 삭제하거나, binlog 일부가 끊기거나, 복호화 키가 사라지면 약속한 복구 기간은 성립하지 않는다. 반대로 모든 백업을 무기한 보존하면 비용과 개인정보 보유 부담이 커지고, 사고 때 사용할 복구본을 찾는 시간도 길어진다.
이 글은 Community MySQL 8.0 이상에서 직접 관리하는 백업을 중심으로 보존 기간, 불변성, 삭제 승인, 비용을 하나의 정책으로 연결한다. Aurora MySQL의 관리형 백업은 별도 구분한다. SQL 실습은 폐기용 MySQL 8.0에서 실행한 설명용 백업 목록의 판정과 용량 계산이며, 실제 백업 삭제·S3 잠금·Aurora 복원 시험은 아니다.
1. 먼저 보관할 파일이 아니라 복구 약속을 정의한다
운영 정책에는 최소한 다음 항목을 분리해 기록해야 한다.
| 항목 | 답해야 할 질문 | 정책에 미치는 영향 |
|---|---|---|
| 복구 시점 목표(RPO) | 사고 직전 얼마나 많은 변경을 잃어도 되는가? | 백업·로그 수집 빈도와 외부 반출 지연 |
| 복구 시간 목표(RTO) | 서비스 복구까지 얼마나 기다릴 수 있는가? | 저장 계층, 복원 대역폭, 적용할 증분·로그 길이 |
| 복구 가능 기간 | 며칠 전의 임의 시점까지 돌아가야 하는가? | 기준 백업과 연속 로그의 최소 보존 범위 |
| 사고 발견 지연 | 잘못된 변경을 며칠 뒤 발견할 수 있는가? | 정상 시점이 만료되지 않도록 할 안전 여유 |
| 장기 증빙 보존 | 월말·연말 등의 특정 시점을 얼마나 보존하는가? | 장기 복구 지점과 접근 통제 |
| 삭제 제한 | 법적 보존이나 불변 잠금이 있는가? | 만료 후에도 삭제할 수 없는 예외 |
예를 들어 매월 말 백업을 장기간 남기는 정책은 월말 복구 지점을 제공할 뿐, 그 사이 모든 날의 PITR을 제공하지 않는다. 일·주·월 단위로 복구본을 남기는 GFS 방식도 각 지점이 독립적인지, 다른 전체·증분 백업을 요구하는지부터 확인해야 한다.
또한 백업 간격이 짧다는 이유만으로 RPO가 충족되는 것은 아니다. 커밋한 변경이 복구 저장소까지 반출되는 지연과 수집 실패를 포함해야 한다. 보존 기간이 충분하더라도 냉각 저장소의 인출 대기 때문에 RTO를 지키지 못할 수 있다.
2. 보존 단위는 파일이 아니라 복구 의존성의 묶음이다
전체 백업과 증분 백업
독립적으로 복원 가능한 전체 백업은 그 자체가 기준점이다. 증분 물리 백업은 기준 백업과 필요한 이전 증분을 요구한다. 실제 조합은 사용하는 도구와 백업 방식에 따라 달라지며, XtraBackup 같은 물리 백업에서는 LSN 연결과 prepare 가능 여부를 함께 확인해야 한다.
따라서 “생성 후 일정 기간이 지난 객체”와 “삭제 가능한 객체”는 다르다. 최근 증분을 살리려면 명목상 보존 기간이 지난 전체 백업도 남겨야 한다. 최신 전체 백업을 새로 만들었더라도 이전 시점의 복구 약속이나 장기 보존 증분이 그보다 오래된 전체 백업을 계속 요구할 수 있다.
PITR과 binlog
PITR에는 기준 백업의 일관성 있는 좌표와 목표 트랜잭션까지의 연속 binlog가 필요하다. 보존 창의 가장 이른 시점보다 앞선 기준 백업을 사용해야 한다면, 그 기준 좌표부터 보존 창 시작까지의 로그도 필요하다. 시간순 파일명만 보고 보존 창보다 오래된 로그를 모두 지우면 이 연결이 끊길 수 있다.
서버의 binlog_expire_logs_seconds는 서버 로컬 로그 수명 설정이지, 외부 백업 저장소의 완전성 검증이 아니다. 복제 지연·중단 중인 replica의 필요 로그도 별도 고려한다. 로컬 purge를 허용하려면 최소한 다음 두 문제를 나눠 판단해야 한다.
- 복구 문제: 필요한 로그가 외부에 완전하게 저장되어 있고, 기준 백업부터 목표까지 재생 가능한가?
- 복제 문제: 해당 로그를 아직 수신하지 않은 replica가 있는가? 없다면 어떤 근거로 확인했는가?
GTID 집합은 이력 경계를 확인하는 자료이지, 삭제된 트랜잭션 내용을 복원하는 백업 자체가 아니다. 파일 수와 최신 업로드 시각만 확인하는 점검 역시 중간 누락을 놓칠 수 있다.
flowchart TD
A[복구 기간과 장기 보존 지점 선정] --> B[필요한 전체·증분·binlog 의존성 확장]
B --> C[법적 보존·불변 잠금·검증 상태 대조]
C --> D{삭제 후보인가}
D -->|아니요| E[보존 또는 원인 조사]
D -->|예| F[격리 환경 복원과 목록 재검증]
F --> G[승인된 객체 버전만 삭제]
G --> H[삭제 결과와 남은 복구 가능 기간 감사]
암호화 키, 복원 도구의 호환 버전, 백업 manifest, 파일 체크섬, 압축 형식도 이 묶음에 속한다. 데이터 객체만 보존하면서 키를 폐기하거나 복원 도구를 확보하지 못하면 보존 약속은 깨진다.
3. 불변 백업은 무엇을 막고 무엇을 막지 못하는가
불변 백업(immutable backup)은 정해진 조건 아래 이미 저장한 복구본을 덮어쓰거나 삭제하지 못하게 하는 보호 장치다. 운영 계정 탈취나 랜섬웨어가 원본과 백업을 함께 지우는 위험을 줄이지만, 잘못된 데이터를 정상적으로 백업하는 일까지 막지는 않는다.
S3 Object Lock의 적용 단위를 이해한다
S3 Object Lock은 Versioning을 사용하는 버킷의 객체 버전에 적용된다. 보존 중인 버전이 잠겨 있어도 같은 키에 새 버전을 만들거나 delete marker를 추가하는 일이 가능하다. 따라서 최신 키 조회에서 객체가 보이지 않는 현상과 보호된 버전의 영구 삭제를 구분해야 한다. 복구 manifest에는 객체 키만 아니라 version ID와 체크섬을 함께 남기는 편이 안전하다.
| 보호 방식 | 핵심 성질 | 운영 판단 |
|---|---|---|
| Governance mode | 적절한 우회 권한과 요청 조건을 가진 주체는 보존 제한을 우회할 수 있음 | 권한 분리와 우회 권한 감사가 필수 |
| Compliance mode | 보존 중인 버전을 일반 사용자나 계정 root가 삭제하거나 보존 기간을 단축할 수 없음 | 시험 없이 긴 기간을 확정하면 비용·삭제 요구 대응이 어려움 |
| Legal hold | 명시적으로 해제할 때까지 삭제 보호가 유지됨 | 고정된 만료 날짜와 별도로 추적해야 함 |
이 글에서 날짜 기반 보존은 고정 retain-until을 기준으로 설명한다. 실제 정책은 사용하는 Object Lock 기능과 객체별 설정을 조회해 판정해야 한다. 기본 버킷 정책을 설정했다는 사실만으로 과거의 모든 객체 버전이 같은 조건으로 보호된다고 가정하지 않는다.
AWS Backup Vault Lock은 별도의 보호 계층이다
AWS Backup Vault Lock은 AWS Backup vault의 복구 지점을 보호하는 기능이다. S3 Object Lock과 이름이 비슷해도 설정 대상과 API가 다르며, Aurora 네이티브 스냅샷 전체에 자동으로 적용되는 개념도 아니다.
Governance mode는 충분한 IAM 권한을 가진 주체가 잠금을 제거할 수 있다. Compliance mode는 유예 기간이 지나면 복구 지점이 있는 vault의 잠금 구성을 변경·삭제할 수 없으므로, 확정 전에 복구 지점 수명과 최소·최대 보존 설정을 검토해야 한다. vault의 보존 범위 설정과 개별 백업 생성 시 정해진 lifecycle은 같은 항목이 아니다. 잘못된 무기한 보존은 장기 비용 부담으로 이어질 수 있다.
삭제 방지와 복구 가능성은 별개의 조건이다
불변 저장소도 다음 실패를 해결하지 못한다.
- 백업 수집 계정이 탈취되어 이후 백업이 중단되거나 오염된 백업만 계속 저장되는 경우
- 암호화 키가 비활성화·삭제되거나, 복구 계정이 복호화 권한을 잃는 경우
- 하나의 계정·리전·운영 주체에 모든 사본과 권한이 집중된 경우
- 기준 전체 백업만 먼저 만료되고 그에 의존하는 증분만 잠겨 남는 경우
따라서 저장 계정 분리, 필요한 경우 독립 사본, 키 정책, 복원 계정, 경보, 실제 복원 시험을 함께 설계한다. 불변 보존 기간은 침해를 발견하고 정상 복구본을 식별·확보할 시간을 고려하되, 개인정보 삭제 의무와 비용 한도를 보안·법무 담당자와 조정한다.
4. SQL로 확인하는 삭제 후보와 의존성 보존
다음은 실제 시스템 테이블이 아니라 정책 설계를 위한 작은 백업 목록이다. 기준 시각은 설명용 UTC 시각인 2026-10-06 00:00:00으로 고정한다. policy_until은 개별 항목의 명목상 보존 종료 시각이며, 실제 최종 삭제일이 아니다. integrity_ok는 해당 목록의 검증 상태를 단순화한 값으로, 0이면 자동 삭제 판단에서 보수적으로 보류한다.
먼저 전체·증분 백업과 예외 항목을 준비한다. 3번 증분은 2번 증분과 1번 전체 백업을 필요로 한다. 5번은 불변 보존 중이고, 6번은 legal hold가 있으며, 7번은 검증이 완료되지 않았다.
CREATE TABLE retention_demo (
backup_id INT PRIMARY KEY,
backup_kind VARCHAR(12) NOT NULL,
parent_id INT NULL,
policy_until DATETIME NOT NULL,
lock_until DATETIME NULL,
legal_hold BOOLEAN NOT NULL,
integrity_ok BOOLEAN NOT NULL
) ENGINE=InnoDB;
INSERT INTO retention_demo VALUES
(1, 'FULL', NULL, '2026-09-08 00:00:00', NULL, 0, 1),
(2, 'INCREMENTAL', 1, '2026-09-27 00:00:00', NULL, 0, 1),
(3, 'INCREMENTAL', 2, '2026-10-29 00:00:00', NULL, 0, 1),
(4, 'FULL', NULL, '2026-08-08 00:00:00', NULL, 0, 1),
(5, 'FULL', NULL, '2026-08-22 00:00:00', '2026-11-01 00:00:00', 0, 1),
(6, 'FULL', NULL, '2026-08-27 00:00:00', NULL, 1, 1),
(7, 'FULL', NULL, '2026-09-01 00:00:00', NULL, 0, 0),
(8, 'FULL', NULL, '2026-11-01 00:00:00', NULL, 0, 1);
실행 결과(MySQL 8.0.x):
mysql> CREATE TABLE retention_demo (
-> backup_id INT PRIMARY KEY,
-> backup_kind VARCHAR(12) NOT NULL,
-> parent_id INT NULL,
-> policy_until DATETIME NOT NULL,
-> lock_until DATETIME NULL,
-> legal_hold BOOLEAN NOT NULL,
-> integrity_ok BOOLEAN NOT NULL
-> ) ENGINE=InnoDB;
Query OK, 0 rows affected (0.00 sec)
mysql> INSERT INTO retention_demo VALUES
-> (1, 'FULL', NULL, '2026-09-08 00:00:00', NULL, 0, 1),
-> (2, 'INCREMENTAL', 1, '2026-09-27 00:00:00', NULL, 0, 1),
-> (3, 'INCREMENTAL', 2, '2026-10-29 00:00:00', NULL, 0, 1),
-> (4, 'FULL', NULL, '2026-08-08 00:00:00', NULL, 0, 1),
-> (5, 'FULL', NULL, '2026-08-22 00:00:00', '2026-11-01 00:00:00', 0, 1),
-> (6, 'FULL', NULL, '2026-08-27 00:00:00', NULL, 1, 1),
-> (7, 'FULL', NULL, '2026-09-01 00:00:00', NULL, 0, 0),
-> (8, 'FULL', NULL, '2026-11-01 00:00:00', NULL, 0, 1);
Query OK, 8 rows affected (0.01 sec)
Records: 8 Duplicates: 0 Warnings: 0
아래 재귀 CTE는 먼저 직접 보존·보류해야 할 항목을 정하고, 그 항목이 요구하는 부모를 거슬러 올라간다. 잠금이나 검증 보류 때문에 남긴 증분이 있다면 그 부모도 보존 대상에 들어가야 하므로, 기간 내 항목만 출발점으로 삼지 않는다.
SET @as_of = CAST('2026-10-06 00:00:00' AS DATETIME);
WITH RECURSIVE required_backups AS (
SELECT backup_id, parent_id
FROM retention_demo
WHERE policy_until > @as_of
OR lock_until > @as_of
OR legal_hold = 1
OR integrity_ok = 0
UNION ALL
SELECT p.backup_id, p.parent_id
FROM retention_demo AS p
JOIN required_backups AS r ON p.backup_id = r.parent_id
)
SELECT b.backup_id, b.backup_kind,
CASE
WHEN b.legal_hold = 1 THEN 'KEEP_HOLD'
WHEN b.lock_until > @as_of THEN 'KEEP_LOCK'
WHEN b.integrity_ok = 0 THEN 'REVIEW'
WHEN b.policy_until > @as_of THEN 'KEEP_POLICY'
WHEN EXISTS (
SELECT 1 FROM required_backups AS r
WHERE r.backup_id = b.backup_id
) THEN 'KEEP_DEPENDENCY'
ELSE 'DELETE_CANDIDATE'
END AS decision
FROM retention_demo AS b
ORDER BY b.backup_id;
실행 결과(MySQL 8.0.x):
mysql> SET @as_of = CAST('2026-10-06 00:00:00' AS DATETIME);
Query OK, 0 rows affected (0.00 sec)
mysql> WITH RECURSIVE required_backups AS (
-> SELECT backup_id, parent_id
-> FROM retention_demo
-> WHERE policy_until > @as_of
-> OR lock_until > @as_of
-> OR legal_hold = 1
-> OR integrity_ok = 0
-> UNION ALL
-> SELECT p.backup_id, p.parent_id
-> FROM retention_demo AS p
-> JOIN required_backups AS r ON p.backup_id = r.parent_id
-> )
-> SELECT b.backup_id, b.backup_kind,
-> CASE
-> WHEN b.legal_hold = 1 THEN 'KEEP_HOLD'
-> WHEN b.lock_until > @as_of THEN 'KEEP_LOCK'
-> WHEN b.integrity_ok = 0 THEN 'REVIEW'
-> WHEN b.policy_until > @as_of THEN 'KEEP_POLICY'
-> WHEN EXISTS (
-> SELECT 1 FROM required_backups AS r
-> WHERE r.backup_id = b.backup_id
-> ) THEN 'KEEP_DEPENDENCY'
-> ELSE 'DELETE_CANDIDATE'
-> END AS decision
-> FROM retention_demo AS b
-> ORDER BY b.backup_id;
+-----------+-------------+------------------+
| backup_id | backup_kind | decision |
+-----------+-------------+------------------+
| 1 | FULL | KEEP_DEPENDENCY |
| 2 | INCREMENTAL | KEEP_DEPENDENCY |
| 3 | INCREMENTAL | KEEP_POLICY |
| 4 | FULL | DELETE_CANDIDATE |
| 5 | FULL | KEEP_LOCK |
| 6 | FULL | KEEP_HOLD |
| 7 | FULL | REVIEW |
| 8 | FULL | KEEP_POLICY |
+-----------+-------------+------------------+
8 rows in set (0.00 sec)
판정의 핵심은 1번과 2번이다. 자체 기간이 만료되었지만 3번을 복원하는 데 필요하므로 KEEP_DEPENDENCY가 된다. 4번만 DELETE_CANDIDATE이며, 5·6번은 각 보호 조건 때문에 남고 7번은 조사 대상이다. 상태는 대표 사유 하나만 표시하며, 실제 감사 기록에는 중첩된 사유를 모두 남기는 편이 좋다.
이 결과를 바로 DELETE나 저장소 삭제 API에 연결해서는 안 된다. 예제에는 하나의 부모만 표현했으며 실제 PITR의 다중 binlog 의존성, 객체 version ID, 실패한 사본, 누락된 부모, 순환 참조를 모델링하지 않았다. 재귀 한도 초과나 목록 불완전은 삭제 허용이 아니라 작업 중단 사유다. 백업 목록의 integrity_ok=1 역시 특정 검증 기록을 요약할 뿐, 현재 모든 복구 경로의 성공을 보증하지 않는다.
운영 도구는 여러 의존성을 표현하는 별도 연결 테이블, manifest 대조, 저장소 상태 조회를 사용해야 한다. 또한 다음 순서로 경합을 통제한다.
- 최신 수집 상태를 반영한 목록 스냅샷과 정책 버전을 고정한다.
- 필요한 복구 지점에서 시작해 모든 의존성을 확장한다.
- 후보 목록을 생성하되 미완료 업로드, 검증 실패, hold, 잠금을 제외한다.
- 복원 시험과 승인 후 실제 삭제 직전에 정책·의존성·객체 버전을 다시 확인한다.
- 새 백업이 삭제 후보를 부모로 등록하지 못하도록 조정하고, 승인된 버전만 삭제한다.
- 결과와 실패 이유를 기록하고 남은 복구 가능 기간을 다시 계산한다.
시간이 지났다는 이유만으로 자동 승인해서는 안 된다. 특히 최근 정상 백업이 실패한 날에는 예정된 삭제를 보류하는 보호 규칙이 필요하다.
5. 비용 최적화는 보존 기간 축소보다 복원 경로 단순화부터 시작한다
저장 비용의 크기는 원본 DB 크기만으로 결정되지 않는다. 실제 저장한 전체·증분·로그의 크기, 변경률, 보존 중복, 독립 사본 수, 압축, 최소 과금 기간, API 요청, 인출, 전송 비용을 분리해야 한다.
다음 계산은 독립 전체 백업을 반복 저장하는 자체 관리 저장소의 가정 입력이다. 압축 후 전체 백업 하나를 200GiB, 일일 binlog를 20GiB, 로그 보존을 14일, 독립 사본을 2개로 둔다. 전체 백업 보유 개수만 14개와 3개로 비교한다. 실제 요금표, 운영 측정치, Aurora 증분 저장량 모델이 아니다.
WITH plans AS (
SELECT 'daily_full' AS plan_name, 14 AS full_count
UNION ALL
SELECT 'sparse_full', 3
)
SELECT plan_name,
full_count,
CAST(full_count * 200 AS DECIMAL(12,0)) AS full_gib,
CAST(14 * 20 AS DECIMAL(12,0)) AS binlog_gib,
CAST((full_count * 200 + 14 * 20) * 2 AS DECIMAL(12,0)) AS stored_gib
FROM plans
ORDER BY full_count DESC;
실행 결과(MySQL 8.0.x):
mysql> WITH plans AS (
-> SELECT 'daily_full' AS plan_name, 14 AS full_count
-> UNION ALL
-> SELECT 'sparse_full', 3
-> )
-> SELECT plan_name,
-> full_count,
-> CAST(full_count * 200 AS DECIMAL(12,0)) AS full_gib,
-> CAST(14 * 20 AS DECIMAL(12,0)) AS binlog_gib,
-> CAST((full_count * 200 + 14 * 20) * 2 AS DECIMAL(12,0)) AS stored_gib
-> FROM plans
-> ORDER BY full_count DESC;
+-------------+------------+----------+------------+------------+
| plan_name | full_count | full_gib | binlog_gib | stored_gib |
+-------------+------------+----------+------------+------------+
| daily_full | 14 | 2800 | 280 | 6160 |
| sparse_full | 3 | 600 | 280 | 1760 |
+-------------+------------+----------+------------+------------+
2 rows in set (0.00 sec)
표의 저장량 차이는 전체 백업 반복 저장량에서 나온다. 하지만 전체 백업 간격을 늘리면 복원 시 로그 적용 구간이 길어질 수 있다. 가장 오래된 복구 목표에 필요한 기준 백업과 로그가 실제로 이어지는지, 계산에서 생략한 경계 이전 로그가 얼마나 필요한지 먼저 확인해야 한다. 저장량 계산이 작아졌다는 사실만으로 같은 복구 범위와 RTO를 달성한다고 결론 내릴 수 없다.
실무에서는 다음 순서가 안전하다.
- 사용하지 않는 시험용 복사본과 소유자 없는 장기 백업을 먼저 식별한다. 삭제는 복구 의존성과 보존 예외를 확인한 후 수행한다.
- 압축 효과를 실제 데이터로 측정하되, 복원 시 해제 CPU·메모리·처리 시간을 함께 측정한다.
- 최근 복구에 필요한 기준 백업과 로그는 빠른 접근 계층에 두고, 오래된 독립 복구 지점은 인출 지연을 수용할 때만 저비용 계층으로 이동한다.
- 증분 체인이 너무 길면 새로운 독립 기준 백업으로 재기준화하는 방식을 검토한다. 도구가 지원하는 방식으로 복원을 시험하기 전에는 기존 체인을 삭제하지 않는다.
- 객체 버전·미완료 업로드·별도 계정과 리전의 사본까지 비용 목록에 포함한다. 불변 잠금 중인 객체는 lifecycle 만료 규칙이 있어도 즉시 영구 삭제되지 않을 수 있다.
- 예상 사고 빈도만으로 인출 비용을 무시하지 않는다. 정기 복원 훈련도 비용 모델에 포함한다.
실습에서 사용한 목록은 다음과 같이 정리한다. 이것은 시험 테이블 삭제일 뿐 실제 백업 삭제가 아니다.
DROP TABLE retention_demo;
실행 결과(MySQL 8.0.x):
mysql> DROP TABLE retention_demo;
Query OK, 0 rows affected (0.00 sec)
6. Aurora MySQL에서는 네이티브 보존과 외부 불변 정책을 구분한다
Aurora의 자동 백업은 연속·증분 방식이며 보존 기간을 1~35일로 설정한다. 장기 보존이 필요하면 수동 DB cluster snapshot 등을 별도로 관리한다. 수동 스냅샷이 자체적으로 만료되지 않는다는 성질은 삭제 불가능하거나 비용이 없다는 뜻이 아니다.
또한 “Aurora 자동 백업이 S3에 저장된다”는 설명을 사용자가 해당 내부 객체에 자신의 S3 Object Lock을 직접 적용할 수 있다는 뜻으로 읽어서는 안 된다. AWS Backup을 사용할 경우에는 해당 리소스·리전·백업 방식의 지원 범위를 확인하고, vault의 실제 복구 지점이 의도한 잠금 및 lifecycle 아래 있는지 별도로 검증한다.
Aurora 백업 비용은 자동 백업, 수동 스냅샷, 복사본의 종류와 보존 범위에 따라 달라진다. 공식 문서는 자동 백업의 증분 저장량과 클러스터 볼륨 크기에 연동한 무료 사용량, 보존 기간 안의 스냅샷과 그 밖의 스냅샷, 복사본을 구분한다. 따라서 DB 크기 × 스냅샷 개수만으로 청구액을 확정하지 않는다. 실제 청구와 백업 저장량 지표, 리전별 요금, 삭제된 클러스터의 잔존 백업 비용을 대조한다.
Aurora의 복구 가능 기간은 설정값만 아니라 실제 earliest/latest restorable time으로 확인한다. 별도 클러스터로 복원한 뒤 파라미터, 사용자와 권한, 애플리케이션 연결, 데이터 검증까지 수행해야 한다. 네이티브 PITR을 사용자 관리 binlog 재생과 같은 절차로 설명하거나, 로컬 MySQL 목록 조회를 Aurora 복원 시험으로 대체해서는 안 된다.
7. 자주 발생하는 실패와 판정 기준
| 잘못된 판단 | 실제 위험 | 필요한 확인 |
|---|---|---|
| 오래된 전체 백업은 최근 증분과 무관하다 | 기준 백업 손실로 증분 전체가 무용해짐 | 부모·LSN·로그 좌표 연결 |
| 잠금 기간과 보존 기간은 같은 값이다 | 잠금 종료 뒤 필요한 복구본을 조기 삭제 | 복구 정책과 저장소 삭제 제한을 각각 평가 |
| 객체가 없다고 보이면 삭제된 것이다 | delete marker 뒤에 잠긴 버전이 남아 있음 | version ID별 조회와 복원 가능성 |
| 불변 백업이면 키 관리가 필요 없다 | 데이터는 남아도 복호화 불가 | 키 수명·권한·복구 계정 시험 |
| 월간 백업이 있으므로 매일 PITR이 된다 | 월간 지점 사이의 로그가 없어 목표 시점 복원 불가 | 복구 지점과 연속 복구 구간을 구분 |
| 전체 행 수가 맞으면 백업이 정상이다 | 값 변경, 객체 누락, 권한 누락을 놓침 | 내용 대조·객체 검증·업무 기능 점검 |
| 비용을 줄이려면 오래된 파일부터 지우면 된다 | 저렴한 로그 하나의 삭제로 비싼 전체 백업까지 쓸 수 없게 됨 | 복구 경로를 기준으로 후보 생성 |
8. 보관 정책 승인 체크리스트
정리
보존 기간은 출발점이며 삭제 승인 조건의 전부가 아니다. 복구 의존성으로 필요한 묶음을 먼저 정하고, 불변 잠금·법적 보존·검증 상태를 대조한 뒤, 복구 약속을 훼손하지 않는 항목만 삭제해야 한다. 비용 최적화도 같은 원칙 아래에서 접근 계층과 체인 길이를 조정하는 문제다.
이 원칙을 복구 검증 자동화와 연결하면 “백업이 몇 개 남았는가” 대신 “어느 시점까지 어떤 절차와 시간으로 복구할 수 있는가”를 운영 지표로 삼을 수 있다. 이후 스키마 변경이나 데이터 이관을 설계할 때도 변경 전 복구 지점의 보존 조건과 삭제 승인 기준을 같은 방식으로 적용할 수 있다.