LabHub
はじめる
배우기 러닝패스 코스

レイクハウスのテーブル形式 — Apache Iceberg をメタデータで理解する

誤って消した地域を元に戻し、翌日のデータはブランチで確認してから公開する

LabHub 에서 이어서 보기

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

목표

사흘 치 커밋 뒤에 한 지역을 통째로 지우는 사고를 내고, 타임트래블로 사고 전 상태를 읽고, 태그로 그 시점에 이름을 붙이고, 롤백으로 되돌린다. 이어서 다음 날 자료를 main 이 아닌 브랜치에 먼저 쓰고 검토한 뒤 main 을 앞당겨 발행한다.

왜 중요한가

Iceberg 의 모든 커밋은 옛 스냅샷을 지우지 않고 새 스냅샷을 더한다. 그래서 '어제 상태' 는 백업에서 꺼내는 것이 아니라 그 스냅샷의 파일 목록을 읽는 것이고, 되돌리기는 파일을 복사하는 것이 아니라 main 이라는 포인터를 옛 스냅샷으로 옮기는 것이다. 몇 초면 끝난다. 다만 옛 스냅샷은 영원하지 않다. 스냅샷 만료가 돌면 기준보다 오래된 것은 지워지고, ID 만 적어 둔 시점은 사라진다. 태그는 스냅샷에 이름을 붙이고 보존 기간을 따로 주어 만료로부터 지킨다. 브랜치는 반대 방향의 도구다. 새 자료를 main 이 아닌 곳에 먼저 커밋해 두고, 검사가 통과하면 main 을 그 스냅샷으로 앞당긴다. 읽는 사람은 검사 전의 자료를 한 번도 보지 않는다(write-audit-publish).

단계

  1. /root/ice/tt/days.py(앱 ice-tt-days)로 lake.tt.orders(format-version 2)를 만들고 2026-03-01·02·03 을 하루에 한 커밋씩 넣으세요.
  2. /root/ice/tt/accident.py(앱 ice-tt-accident)로 DELETE FROM lake.tt.orders WHERE region = 'busan' 을 돌리세요(일부러 내는 사고입니다).
  3. /root/ice/tt/travel.py(앱 ice-tt-travel)로 세 번째 커밋(사고 직전) 스냅샷을 찾아 그때의 행 수·부산 행 수와 지금의 부산 행 수를 /root/ice/tt/out/travel.json 에 쓰세요.
  4. /root/ice/tt/tag.py(앱 ice-tt-tag)로 그 스냅샷에 태그 before_accidentRETAIN 7 DAYS 로 붙이세요.
  5. /root/ice/tt/rollback.py(앱 ice-tt-rollback)로 rollback_to_snapshot 을 불러 main 을 그 스냅샷으로 되돌리세요.
  6. /root/ice/tt/branch.py(앱 ice-tt-branch)로 브랜치 fix 를 만들고 2026-03-04 를 그 브랜치에만 쓰세요.
  7. /root/ice/tt/publish.py(앱 ice-tt-publish)로 fast_forward 를 불러 main 을 fix 로 앞당기세요.
  8. /root/ice/tt/report.md## 타임트래블 ## 롤백과 태그 ## 브랜치 세 절을 쓰세요.

참고

사흘, 커밋 셋

/root/ice/tt/days.py 를 앱 이름 ice-tt-days 로 만들어 lake.tt.orders(열 여섯 개, 'format-version' = '2')를 만들고 2026-03-01·03-02·03-03 을 하루에 append() 한 번씩 넣으세요.

스냅샷 셋이 부모로 이어집니다. 채점기는 처음 세 스냅샷이 차례로 그날의 행 수를 더한 append 인지 봅니다. 여러 번 돌려 스냅샷이 늘었다면 DROP TABLE lake.tt.orders PURGE 뒤 다시 하세요.

사고 — 한 지역이 통째로 사라진다

/root/ice/tt/accident.py 를 앱 이름 ice-tt-accident 로 만들어 DELETE FROM lake.tt.orders WHERE region = 'busan' 을 돌리세요.

DELETE 도 커밋이라 네 번째 스냅샷이 생깁니다. 부산 행이 든 파일은 부산을 뺀 새 파일로 바뀌어 목록에 들어가고, 옛 파일은 목록에서만 빠질 뿐 디스크에는 그대로 있습니다. 채점기는 네 번째 스냅샷이 세 번째를 부모로 두고 부산 행이 없는지 봅니다.

타임트래블 — 사고 직전을 읽는다

/root/ice/tt/travel.py 를 앱 이름 ice-tt-travel 로 만들어 lake.tt.orders.snapshots 에서 세 번째 커밋의 스냅샷 ID 를 찾고, VERSION AS OF 로 그때의 전체 행 수와 부산 행 수를, 지금 표에서 부산 행 수를 세어 /root/ice/tt/out/travel.json{"snapshot_id", "rows_before", "busan_before", "busan_after"} 로 쓰세요.

VERSION AS OF 는 그 스냅샷의 매니페스트 리스트를 읽을 뿐입니다. 사고 전 파일이 아직 디스크에 있으니 그대로 읽힙니다. 스냅샷 ID 는 19자리 정수라 손으로 옮기지 말고 스크립트에서 읽어 쓰세요.

태그 — 시점에 이름과 보존 기간을

/root/ice/tt/tag.py 를 앱 이름 ice-tt-tag 로 만들어 3단계의 스냅샷에 ALTER TABLE lake.tt.orders CREATE TAG before_accident AS OF VERSION <ID> RETAIN 7 DAYS 로 태그를 붙이세요.

태그는 metadata 의 refs 에 이름·스냅샷 ID·max-ref-age-ms 로 들어갑니다. RETAIN 7 DAYS 는 604,800,000ms 입니다. 태그가 가리키는 스냅샷은 만료 대상에서 빠집니다. 채점기는 refs 의 세 값을 봅니다.

롤백 — 포인터만 옮긴다

/root/ice/tt/rollback.py 를 앱 이름 ice-tt-rollback 으로 만들어 태그 before_accident 가 가리키는 스냅샷으로 CALL lake.system.rollback_to_snapshot('lake.tt.orders', <ID>) 를 부르세요.

롤백은 새 스냅샷을 만들지 않고 main 이 가리키는 스냅샷만 바꿉니다. 사고 스냅샷은 snapshots 목록에 그대로 남고, main 이 지나온 길(snapshot-log)에 '사고 → 사고 직전' 이 기록됩니다. 채점기는 그 기록과 사고 스냅샷이 남아 있는지를 봅니다.

브랜치에 먼저 쓴다

/root/ice/tt/branch.py 를 앱 이름 ice-tt-branch 로 만들어 ALTER TABLE lake.tt.orders CREATE BRANCH fix 뒤 2026-03-04 파일을 writeTo("lake.tt.orders.branch_fix").append()fix 에만 쓰세요.

브랜치는 만들 때의 main(되돌린 스냅샷)에서 갈라집니다. fix 에 커밋하면 fix 만 앞으로 가고 main 은 그대로라, 읽는 사람들은 3월 4일 자료를 아직 보지 않습니다. 채점기는 fix 의 머리가 되돌린 스냅샷을 부모로 두고 3월 4일 행 수를 더했는지 봅니다.

발행 — main 을 앞당긴다

/root/ice/tt/publish.py 를 앱 이름 ice-tt-publish 로 만들어 CALL lake.system.fast_forward('lake.tt.orders', 'main', 'fix') 를 부르세요.

fast_forward 는 main 이 fix 의 조상일 때만 됩니다(그 사이 main 에 다른 커밋이 끼었다면 거절). 새 스냅샷 없이 main 포인터만 fix 의 머리로 옮깁니다. 채점기는 main 과 fix 가 같은 스냅샷을 가리키는지, main 에 부산과 3월 4일이 모두 있는지 봅니다.

되돌리기 절차를 한 장으로

/root/ice/tt/report.md## 타임트래블 ## 롤백과 태그 ## 브랜치 세 절을 쓰세요. 첫 절에는 3단계의 busan_before 를 숫자로 넣으세요.

새벽에 같은 사고가 났을 때 당직자가 따라 할 순서로 적어 보세요. 만료가 도는 표라면 무엇을 먼저 해야 하는지도.