LabHub
Get started
배우기 러닝패스 코스

Lakehouse Table Format — Understanding Apache Iceberg Through Its Metadata

Undo means moving a pointer, not copying files — time travel, rollback, tags and branches

LabHub 에서 이어서 보기

한국어 원문으로 표시합니다.

한 줄 요약

Iceberg 의 커밋은 옛 스냅샷을 지우지 않고 새 스냅샷을 더하므로, 과거를 읽는 것(타임트래블)은 옛 스냅샷의 목록을 읽는 일이고 되돌리기(롤백)는 main 포인터를 옛 스냅샷으로 옮기는 일이다. 태그는 시점에 이름과 보존 기간을 주고, 브랜치는 main 과 따로 자라는 계보를 만든다.

왜 필요한가 — 새벽 세 시의 DELETE

조건을 하나 빠뜨린 DELETE 가 한 지역의 주문을 통째로 지웠다. 전통적인 레이크라면 백업에서 파일을 찾아 복사하고, 그사이 들어온 자료와 섞이지 않게 손으로 맞춰야 한다. 몇 시간이 걸리고, 그동안 대시보드는 틀린 숫자를 보여 준다.

Iceberg 에서는 사고를 낸 DELETE 도 커밋이라 새 스냅샷을 만들었을 뿐이고, 사고 직전 스냅샷과 그 파일들은 그대로 있다. 되돌리는 데 필요한 것은 "main 이 어느 스냅샷을 가리키는가" 를 바꾸는 한 번의 metadata 커밋이다.

어떻게 동작하나 — 과거 읽기와 되돌리기

Spark 의 타임트래블은 두 가지다.

SELECT count(*) FROM lake.demo.events VERSION AS OF 1234567890123456789;  -- 스냅샷 ID·브랜치·태그 이름
SELECT count(*) FROM lake.demo.events TIMESTAMP AS OF '2026-04-01 09:00:00';

그 스냅샷의 매니페스트 리스트를 읽을 뿐이라 비용은 지금 표를 읽는 것과 같다. 조건은 하나다 — 그 스냅샷과 파일이 아직 있어야 한다.

되돌리기에는 프로시저가 여럿 있다.

프로시저 하는 일
rollback_to_snapshot main 을 지금 계보의 옛 스냅샷으로 되돌린다
rollback_to_timestamp 그 시각에 current 였던 스냅샷으로 되돌린다
set_current_snapshot 조상이 아니어도 되는 스냅샷(또는 ref)을 current 로 둔다
cherrypick_snapshot 한 스냅샷의 변경을 지금 상태 위에 새 스냅샷으로 옮긴다(append·동적 덮어쓰기만)
fast_forward 한 브랜치를 다른 브랜치의 최신 스냅샷으로 앞당긴다

롤백은 새 스냅샷을 만들지 않고, 사고 스냅샷을 지우지도 않는다. main 이 지나온 길(snapshot-log)에 '사고 → 사고 직전' 이 한 줄 더해질 뿐이다. 사고 스냅샷을 없애는 것은 나중의 만료 작업이다.

태그와 브랜치 — 이름 붙은 참조

스펙의 snapshot references는 refs 를 metadata 에 둔다. 각 ref 는 스냅샷 ID 와 종류(tag·branch)를 가지고, 보존 정책으로 max-ref-age-ms(ref 자체의 수명), 브랜치라면 min-snapshots-to-keep·max-snapshot-age-ms 를 가진다. main 은 만료되지 않는 브랜치다.

태그는 한 스냅샷에 붙인 이름표다. 19자리 ID 를 외울 필요가 없어지고, 더 중요하게는 만료가 태그가 가리키는 스냅샷을 지우지 않는다. Branching 문서는 감사용으로 주 단위·월 단위 스냅샷에 태그를 걸고 RETAIN 7 DAYS 처럼 보존 기간을 주는 예를 든다. 보존 정책에 따라 만료는 먼저 max-ref-age-ms 가 지난 ref 를 떼어 내고, 남은 ref 가 가리키는 스냅샷은 보존한다.

브랜치는 main 과 따로 자라는 계보다. 새 자료를 main 이 아닌 브랜치에 먼저 커밋하고, 품질 검사가 통과하면 main 을 그 브랜치의 머리로 앞당긴다(fast_forward). 읽는 사람은 main 만 보므로 검사 전 자료를 한 번도 보지 않는다. 문서는 이것을 감사 브랜치(write-audit-publish, WAP)라 부르고, write.wap.enabledspark.wap.branch 로 기존 잡을 고치지 않고 브랜치에 쓰게 하는 방법을 보여 준다. fast_forward 는 main 이 브랜치의 조상일 때만 되므로, 그사이 main 에 다른 커밋이 끼었다면 거절된다.

현장에서 만나는 모습

사고 뒤 되돌리기. 당직자는 SELECT * FROM 표.history 로 main 이 지나온 스냅샷을 보고, 사고 직전 스냅샷을 VERSION AS OF 로 읽어 숫자를 확인한 뒤 rollback_to_snapshot 을 부른다. 몇 초면 끝난다. 사고 원인 조사를 위해 사고 스냅샷은 남겨 둔다.

만료가 먼저 돌았다. 매일 도는 정리 작업이 5일보다 오래된 스냅샷을 지운다면, 일주일 전 상태로 돌아가야 한다는 것을 알았을 때는 이미 늦다. 되돌아가야 할 수 있는 시점(월말 마감, 배포 직전)에는 미리 태그를 건다.

검증되지 않은 자료가 대시보드에 나갔다. 적재 잡이 main 에 바로 쓰면 품질 검사가 실패해도 이미 늦다. 브랜치에 쓰고 검사한 뒤 발행하면 실패한 자료는 브랜치에만 남는다.

실무에서 진짜 중요한 것

다음 실습에서 할 것

사흘 치를 하루 한 커밋씩 넣은 뒤 일부러 한 지역을 지우는 사고를 낸다. VERSION AS OF 로 사고 직전의 행 수를 읽고, 그 스냅샷에 태그를 7일 보존으로 걸고, rollback_to_snapshot 으로 main 을 되돌린다. 그다음 브랜치 fix 를 만들어 다음 날 자료를 브랜치에만 쓰고, fast_forward 로 main 을 앞당겨 발행한다.