왜 타임 트래블이 필요한가요?
데이터를 다루다 보면 실수는 피할 수 없습니다. 잘못된 UPDATE 하나로 수백만 행의 데이터가 변경될 수 있고, 의도치 않은 DELETE로 중요한 데이터가 사라질 수 있습니다.💡 타임 트래블(Time Travel) 은 Delta Lake 테이블의 과거 버전 데이터를 조회하거나 복원 할 수 있는 기능입니다. 모든 변경 사항이 트랜잭션 로그에 기록되어 있기 때문에, 마치 시간을 되돌리듯 이전 상태의 데이터에 접근할 수 있습니다.Google Docs의 “버전 기록”이나 Git의 “커밋 이력”과 비슷한 개념입니다. 각 변경 작업(INSERT, UPDATE, DELETE, MERGE)이 하나의 “버전”으로 기록됩니다.
동작 원리
Delta Lake는 테이블에 변경이 발생할 때마다_delta_log/ 디렉토리에 새로운 JSON 로그 파일을 생성합니다. 각 로그 파일이 하나의 버전(version) 을 나타냅니다.
| 버전 | 로그 파일 | 작업 내용 |
|---|---|---|
| 0 | 00000000000000000000.json | CREATE TABLE |
| 1 | 00000000000000000001.json | INSERT 3건 |
| 2 | 00000000000000000002.json | UPDATE 1건 |
| 3 | 00000000000000000003.json | DELETE 2건 |
변경 이력 확인: DESCRIBE HISTORY
타임 트래블을 사용하기 전에, 먼저 테이블의 변경 이력을 확인하는 것이 좋습니다.| version | timestamp | operation | operationParameters |
|---|---|---|---|
| 3 | 2025-03-20 15:30:00 | DELETE | {"predicate":"id < 100"} |
| 2 | 2025-03-20 14:00:00 | UPDATE | {"predicate":"city = '서울'"} |
| 1 | 2025-03-20 10:00:00 | WRITE | {"mode":"Append"} |
| 0 | 2025-03-19 09:00:00 | CREATE TABLE | {} |
버전 번호로 조회: VERSION AS OF
타임스탬프로 조회: TIMESTAMP AS OF
정확한 버전 번호를 모를 때는 타임스탬프로도 조회할 수 있습니다.💡TIMESTAMP AS OF는 지정한 시각 이전의 가장 최신 버전 을 반환합니다. 예를 들어, 10:00에 INSERT가 있었고 14:00에 UPDATE가 있었다면,TIMESTAMP AS OF '12:00'은 10:00 시점(버전 1)의 데이터를 반환합니다.
테이블 복원: RESTORE TABLE
과거 버전의 데이터를 단순히 조회 하는 것이 아니라, 테이블 자체를 이전 상태로 되돌리고 싶을 때 사용합니다.⚠️ 주의사항: RESTORE는 새로운 버전을 생성하여 과거 상태를 복원합니다. 기존 이력이 삭제되는 것이 아니라, “버전 4: RESTORE to version 1”과 같은 새로운 이력이 추가됩니다. 따라서 RESTORE 이후에도 다시 되돌릴 수 있습니다.
실수 복구 시나리오
타임 트래블 보존 기간
타임 트래블은 트랜잭션 로그 와 데이터 파일 이 모두 존재해야 동작합니다. VACUUM을 실행하면 오래된 데이터 파일이 삭제되므로, 그 이전 버전으로의 타임 트래블이 불가능해집니다.보존 기간 설정
| 설정 | 기본값 | 설명 |
|---|---|---|
delta.logRetentionDuration | 30일 | 트랜잭션 로그(JSON)의 보존 기간 |
delta.deletedFileRetentionDuration | 7일 | VACUUM이 삭제하지 않는 최소 기간 |
💡 logRetentionDuration을 늘려도, VACUUM이 데이터 파일을 삭제하면 해당 버전의 타임 트래블이 불가능합니다. 타임 트래블 기간을 늘리려면 두 설정 모두 함께 조정해야 합니다.
실전 활용 사례
1. 감사(Audit) 및 규정 준수
2. ML 모델 재현성
3. 데이터 품질 디버깅
4. ETL 파이프라인에서 재처리
현장에서 배운 것들: 타임 트래블이 구해준 순간들
실수로 DELETE FROM을 WHERE 없이 실행한 사고 복구 실화
이 이야기는 제가 금융 고객 현장에서 직접 목격한 사건입니다. 금요일 오후 4시, 한 시니어 개발자가 테스트 환경에서 작업한다고 생각하고 다음 쿼리를 실행했습니다.💡 이 사고에서 배운 교훈 3가지:
- 프로덕션 접근은 반드시 Job을 통해서만: 개인 노트북에서 프로덕션 테이블을 직접 수정하는 것을 정책으로 금지해야 합니다
- DELETE/UPDATE 전 항상 SELECT로 영향 범위 확인:
SELECT COUNT(*) FROM ... WHERE ...를 먼저 실행하는 습관- Unity Catalog의 권한 분리: 개발자에게 프로덕션 테이블 DELETE 권한을 주지 않는 것이 근본 해결
타임 트래블이 감사(Audit)에서 활용되는 실제 패턴
금융, 의료, 공공기관에서는 ”** 특정 시점에 데이터가 어떤 상태였는가?**“를 증명해야 하는 규제 요건이 있습니다. 타임 트래블은 이 요건을 기술적으로 완벽하게 충족합니다.패턴 1: 분기말 재무 데이터 스냅샷 증빙
패턴 2: 데이터 변조 감지
패턴 3: 변경 이력 전수 추적 (Change Data Feed 연계)
7일 VACUUM 보존과 비용의 트레이드오프: 실전 가이드
타임 트래블 보존 기간 설정은 비용 vs 안전성 의 트레이드오프입니다. 20년간의 경험에서 나온 가이드라인을 공유합니다.보존 기간별 실전 시나리오
| 보존 기간 | 적합한 상황 | 리스크 | 추가 스토리지 비용 (1TB 테이블, 일 10% 변경 기준) |
|---|---|---|---|
| 7일 (기본) | 일반적인 ETL 테이블, 사고 시 1주일 내 발견 가능 | 7일 전 사고는 복구 불가 | 기준 (추가 ~700GB) |
| 30일 | 월말 결산 데이터, 감사 대비 | 30일 이상 지난 변경은 추적 불가 | ~3TB 추가 |
| 90일 | 금융 규제 대상, 분기 감사 필요 | 스토리지 비용 증가 | ~9TB 추가 |
| 365일 | 연 1회 감사, 법적 보존 의무 | 비용이 매우 높아짐 | ~36TB 추가 |
⚠️ 이것을 안 하면 이런 일이 벌어집니다: 한 고객이 모든 테이블의 보존 기간을 365일로 설정했습니다. 1년 뒤 스토리지 비용이 원래 데이터 크기의 15배 가 되어 있었습니다. 매일 UPDATE가 많은 테이블이었기 때문에, 365일치의 이전 파일이 모두 보존되고 있었던 것입니다. 보존 기간은 테이블의 변경 빈도와 비즈니스 요건을 고려하여 차등 적용 해야 합니다.
타임 트래블이 안 되는 경우: 알아두어야 할 함정들
| 상황 | 원인 | 예방법 |
|---|---|---|
| ”Version X not found” 에러 | VACUUM이 해당 버전의 데이터 파일을 삭제함 | deletedFileRetentionDuration을 필요한 만큼 설정 |
| 복원했는데 스키마가 달라짐 | 과거 버전과 현재 버전의 스키마가 다름 (컬럼 추가/삭제) | RESTORE 전 DESCRIBE로 스키마 확인 |
| RESTORE 후 다운스트림 테이블 불일치 | 상위 테이블만 복원하고 의존 테이블은 그대로 | 리니지를 확인하고 의존 테이블도 함께 재처리 |
| 외부 도구에서 직접 파일 삭제 | S3/ADLS에서 직접 Parquet 파일을 삭제하면 Delta Log와 불일치 | 반드시 Delta Lake API(SQL/Spark)를 통해서만 데이터 조작 |
정리
| 기능 | 명령어 | 설명 |
|---|---|---|
| 이력 확인 | DESCRIBE HISTORY | 테이블의 모든 변경 이력을 조회합니다 |
| 버전으로 조회 | VERSION AS OF n | 특정 버전의 데이터를 조회합니다 |
| 시각으로 조회 | TIMESTAMP AS OF | 특정 시각 기준의 데이터를 조회합니다 |
| 테이블 복원 | RESTORE TABLE | 테이블을 과거 버전으로 되돌립니다 |