Blog
iceberglakehousewhitepaperdata-platformtable-format

Apache Iceberg 백서 — 차세대 Lakehouse 테이블 포맷의 구조와 도입 전략

Apache Iceberg의 메타데이터 구조, 운영 모델, 멀티-엔진 호환성, 도입 전략을 데이터 아키텍트와 플랫폼 리더의 관점에서 정리한 백서. Hive·Delta Lake·Hudi와의 비교부터 마이그레이션 패턴, 운영 자동화, 2026년 전망까지 종합적으로 다룹니다.

Data Dynamics2026年5月20日49 min read
This post is not yet translated. The original Korean version is shown below.

본 백서가 다루는 범위

Apache Iceberg를 "왜 도입해야 하는가"와 "어떻게 운영해야 하는가"의 두 축으로 정리합니다. 데이터 아키텍트·플랫폼 리드·CDO가 멀티-엔진 Lakehouse 환경에서 테이블 포맷을 선택·도입할 때 참조할 수 있도록, 사양(spec) 설명에 머무르지 않고 운영 자동화, 카탈로그 토폴로지, 마이그레이션 패턴까지 실무 관점에서 다룹니다.


1. Executive Summary

1.1 한 문장 요약

Apache Iceberg는 개체 스토리지 위에 데이터베이스 수준의 트랜잭션과 진화(evolution) 의미론을 부여하는 개방형 테이블 포맷이며, 2026년 현재 멀티-엔진 Lakehouse의 사실상 표준으로 자리잡고 있다.

1.2 핵심 결론

  • Lakehouse가 "단일 엔진의 ACID 레이어"에서 "멀티-엔진의 공유 테이블"로 이동하면서, Iceberg의 엔진 중립적 사양REST Catalog 표준의 가치가 결정적으로 부각됐다.
  • Iceberg는 "스토리지 포맷"이 아니라 "메타데이터 구조" 다. Parquet/ORC/Avro 같은 파일 포맷 위에 스냅샷 기반 격리, 숨겨진 파티셔닝, 스키마·파티션 진화, 시간 여행, 브랜치/태그를 얹는 사양이다.
  • **단일 엔진 환경(예: Databricks-only)**에서는 Delta Lake가 여전히 합리적 선택이지만, 2개 이상 엔진을 동시에 사용하거나 장기 보존·법적 정정·실험 격리가 중요한 워크로드라면 Iceberg가 명확한 우위에 있다.
  • 운영 비용은 무시할 수 없다. 컴팩션, 스냅샷 만료, 고아 파일 정리, 카탈로그 운영을 자동화하지 않으면 Iceberg는 빠르게 "메타데이터 늪"이 된다. 이 백서는 운영 자동화의 표준 패턴을 함께 제시한다.
  • Iceberg V3와 REST Catalog 표준의 정착으로, 향후 3년 내에 **카탈로그 계층이 Lakehouse의 진정한 통제점(control plane)**이 될 것이다.

1.3 누구에게 어떤 결정에 도움이 되는가

독자본 백서에서 얻을 수 있는 것
데이터 플랫폼 아키텍트메타데이터 계층 구조, 카탈로그 토폴로지, 엔진 호환성 매트릭스
데이터 엔지니어링 리드운영 자동화 패턴, 컴팩션·정리 작업 표준, 모니터링 지표
CDO / 데이터 임원도입 의사결정 트리, 마이그레이션 위험·기간 추정, 비용 구조
ML / 분석 리드시간 여행, 브랜치/태그를 활용한 실험·재현성 패턴

2. 배경: 왜 또 새로운 테이블 포맷인가

2.1 Hive 시대의 구조적 한계

2010년대 중반까지 Hadoop·Spark 생태계의 사실상 표준은 Hive Metastore(HMS) + 디렉터리 파티셔닝이었다. 이 방식은 단순했지만, 규모가 커지면서 구조적 한계가 누적됐다.

  • 디렉터리 = 파티션 = Query Predicate. WHERE event_date = '2026-05-20' 같은 Predicate가 디렉터리 경로(/event_date=2026-05-20/)와 정확히 일치해야 Partition Pruning이 동작했다. 컬럼 이름이 바뀌거나, 사용자가 WHERE ts > ...처럼 표현식을 쓰면 Pruning이 무력화됐다.
  • 파티션 진화 불가. "일별 파티션을 시간별로 바꾸자"는 의사결정이 곧 테이블 재작성(rewrite)을 의미했다. 운영 중인 페타바이트급 테이블에서는 사실상 불가능했다.
  • 스키마 진화는 외부 규약. 컬럼 추가/이름변경은 Hive가 어느 정도 지원했지만, 컬럼 ID가 없는 위치 기반 매핑 때문에 컬럼 재배치/이름변경이 위험했다.
  • 원자성 부재. 디렉터리 이동(rename)으로 "원자적 publish"를 흉내냈으나, S3 같은 객체 스토리지에서는 rename이 비원자 복사로 구현되어 부분 가시성·중복 문제가 발생했다.
  • 읽기-쓰기 동시성 부재. 동일 파티션을 다른 잡이 쓰는 동안 읽으면, 부분 파일이 보이거나 ListBucket 결과가 일관되지 않았다.

2.2 클라우드·객체 스토리지로의 이동이 만든 결정타

S3·ADLS·GCS는 HDFS와 두 가지 결정적인 차이를 만들었다.

  1. List는 비싸고 일관성이 약하다. Hive는 s3 list를 수만 번 호출해 파일을 식별하는 구조였는데, S3 list는 prefix가 수십만 키를 가지면 분 단위 비용이 발생한다.
  2. Rename은 사실상 copy + delete. HDFS의 디렉터리 rename은 메타데이터 연산이었지만, S3에서는 객체 단위 복사다. 잡 중간 실패 시 "절반만 쓰인" 상태가 보이게 된다.

요약하면, Hive는 "파일 시스템이 강한 일관성과 빠른 rename을 제공한다"는 전제로 설계됐고, 클라우드는 그 전제를 무너뜨렸다.

2.3 새 포맷들의 등장 — Iceberg, Delta Lake, Hudi

이 시기에 세 개의 포맷이 거의 동시에 등장했다.

포맷시작 시점·주체설계 출발점
Apache Iceberg2017, Netflix"디렉터리 list 없이도 어떤 파일이 테이블의 일부인지 알 수 있어야 한다"
Delta Lake2017, Databricks"Spark의 트랜잭션 로그를 외부로 분리하여 ACID를 부여한다"
Apache Hudi2016, Uber"스트리밍·upsert 워크로드에 최적화된 증분 처리"

세 포맷 모두 메타데이터 계층으로 문제를 해결한다는 공통점이 있지만, 그 메타데이터의 구조와 운영 모델이 다르고, 그것이 곧 사용 가능한 워크로드의 차이를 만든다.

2.4 Iceberg가 받은 평가의 변화

  • 2018~2020: "Netflix 내부 프로젝트". 사용 사례는 흥미롭지만 도입 사례 제한적.
  • 2020~2022: Apache Top-Level 승격(2020), AWS Athena/EMR, Snowflake, Trino, Flink가 차례로 지원 추가.
  • 2023~2024: REST Catalog 사양 v1이 합의되고, Snowflake Polaris·Databricks Unity가 Iceberg를 직접 다루기 시작하면서 "멀티-엔진의 공유 포맷" 역할이 정착.
  • 2025~2026: Iceberg V3(Variant type, Geospatial, default values, deletion vectors)가 도입되며 사양이 더 풍부해지고, REST Catalog가 사실상 카탈로그 표준으로 굳어짐.

3. Iceberg 아키텍처 심층

3.1 세 계층 모델

Iceberg는 어떤 엔진에서 읽더라도 동일한 답을 보장하기 위해, 테이블 상태를 다음 세 계층으로 분리한다.

Iceberg 3계층 모델 — Catalog가 metadata.json 포인터를 들고, Metadata layer가 스냅샷·매니페스트 트리를 보유하며, Data layer에 실제 Parquet/ORC 파일이 있다

이 분리가 가져오는 결과는 명확하다.

  • 읽기 = 디렉터리 list가 없다. 항상 metadata.json → manifest list → manifest → data file의 트리만 따라간다. 따라서 list 비용·일관성 문제에서 자유롭다.
  • 쓰기 = 새 metadata.json을 만들고 카탈로그에서 포인터를 원자적으로 바꾸는 것. 옛 데이터 파일과 옛 metadata.json은 그대로 남아 있어, 다른 리더는 깨지지 않는다.
  • 데이터 파일 자체에는 "테이블이 어떤 모양이어야 한다"는 정보가 없다. 컬럼 이름·타입·파티션 등 모든 정보는 metadata 계층에 있다. 따라서 스키마·파티션 진화를 데이터 재작성 없이 수행할 수 있다.

3.2 metadata.json의 실제 내용

대략 다음과 같은 구조다(V2 기준, 단순화).

{
  "format-version": 2,
  "table-uuid": "5f8a...e9",
  "location": "s3://bucket/warehouse/db/events",
  "last-updated-ms": 1747804800000,
  "last-column-id": 12,
  "schemas": [
    {
      "schema-id": 0,
      "fields": [
        { "id": 1, "name": "event_id",   "required": true,  "type": "long" },
        { "id": 2, "name": "user_id",    "required": false, "type": "long" },
        { "id": 3, "name": "event_ts",   "required": true,  "type": "timestamptz" },
        { "id": 4, "name": "event_type", "required": true,  "type": "string" }
      ]
    }
  ],
  "current-schema-id": 0,
  "partition-specs": [
    {
      "spec-id": 0,
      "fields": [
        { "name": "event_day", "source-id": 3, "transform": "day", "field-id": 1000 }
      ]
    }
  ],
  "default-spec-id": 0,
  "sort-orders": [ ... ],
  "current-snapshot-id": 8123412345678901234,
  "snapshots": [
    {
      "snapshot-id": 8123412345678901234,
      "timestamp-ms": 1747804790000,
      "summary": {
        "operation": "append",
        "added-data-files": "3",
        "added-records": "1450000"
      },
      "manifest-list": "s3://.../snap-8123-1-abc.avro",
      "schema-id": 0
    }
  ],
  "refs": {
    "main":  { "snapshot-id": 8123..., "type": "branch" },
    "wap-2026-05-20": { "snapshot-id": 8123..., "type": "tag" }
  }
}

핵심 관찰:

  • fields 안의 id 가 컬럼의 진짜 식별자다. 이름이 바뀌어도 ID는 그대로 유지된다.
  • partition-specs는 배열이다. 즉 한 테이블이 시간에 따라 다른 파티션 사양을 가질 수 있다.
  • snapshots는 누적된다. 만료(expire) 전까지는 시간 여행을 위해 모두 보존된다.
  • refs는 Git 같은 브랜치/태그 참조다. main 외에 사용자가 정의한 브랜치/태그도 모두 동등하게 다뤄진다.

3.3 Manifest list / Manifest의 역할 분담

쿼리 시 파일을 빠르게 Pruning하기 위해, 데이터 파일에 대한 정보는 두 단계로 모인다.

manifest list와 manifest의 역할 분담 — manifest list는 매니페스트 요약을, manifest는 개별 데이터·삭제 파일의 통계를 담는다

Query Pruning 흐름 (WHERE event_day = '2026-05-20' AND user_id = 42)

  1. 카탈로그에서 현재 metadata.json 위치를 얻는다.
  2. metadata.json → 현재 스냅샷의 manifest list를 읽는다.
  3. manifest list의 각 row(=manifest 파일)에 대해, 요약된 파티션 범위로 1차 Pruning. event_day = '2026-05-20'을 포함하지 않는 manifest는 건너뛴다.
  4. 살아남은 manifest만 읽는다. 그 안의 각 data file의 user_id lower/upper bound로 2차 Pruning.
  5. 남은 데이터 파일만 실제로 연다.

이 구조의 효과:

  • 수십만 개의 데이터 파일을 가진 테이블에서도 쿼리당 수십~수백 개의 파일만 검토한다.
  • 디렉터리 list가 필요 없어, S3 list 비용·일관성에 의존하지 않는다.
  • 통계(lower/upper/null)가 manifest에 응축되어 있어, Parquet footer를 모두 열지 않아도 된다.

3.4 Hidden Partitioning(숨겨진 파티셔닝)

Hive 시대 가장 큰 페인포인트 중 하나가 "파티션 표현식과 Query Predicate가 일치해야 한다" 였다. Iceberg는 이를 메타데이터에 변환(transform)을 등록하는 방식으로 해결한다.

-- DDL: event_ts를 일 단위로 파티셔닝 (단, 데이터에는 event_ts만 저장)
CREATE TABLE events (
  event_id BIGINT,
  user_id  BIGINT,
  event_ts TIMESTAMP,
  event_type STRING
)
USING iceberg
PARTITIONED BY (days(event_ts));
 
-- 쿼리: 파티션 컬럼을 알 필요가 없다
SELECT count(*)
FROM events
WHERE event_ts >= TIMESTAMP '2026-05-20 00:00:00'
  AND event_ts <  TIMESTAMP '2026-05-21 00:00:00';
  • 데이터에는 event_ts만 저장되고, 파티션 키 event_day는 메타데이터에만 존재한다.
  • Query Predicate가 event_ts에 걸려도, 엔진은 partition spec의 transform(days(event_ts))을 이해해 자동으로 Partition Pruning을 수행한다.
  • 사용자가 별도로 event_day = ... 같은 조건을 적을 필요가 없다. "파티션 키"가 사용자에게서 숨겨진다.

지원되는 transform: identity, bucket(N, col), truncate(W, col), year, month, day, hour, void.

3.5 Schema Evolution

Iceberg는 컬럼에 영구 ID를 부여하기 때문에, 다음 변경을 데이터 재작성 없이 수행한다.

연산안전성비고
컬럼 추가안전기존 row는 NULL 또는 default
컬럼 삭제안전ID가 메타데이터에서만 사라짐, 데이터 파일은 그대로
컬럼 이름변경안전ID 유지, 이름만 metadata.json에서 갱신
컬럼 재배치안전메타데이터의 필드 순서만 변경
타입 확장일부 안전int → long, float → double, decimal precision 증가 등
타입 축소불가long → int 같은 손실 변환은 금지
nullable → required조건부모든 기존 행이 not null임을 검증해야 함

이는 Parquet의 위치 기반 매핑이 아닌, Iceberg의 field-id 기반 매핑이 가능하게 한다. 데이터 파일에 컬럼 ID가 함께 기록되므로, 메타데이터에서 이름이 바뀌어도 일관된 컬럼을 찾을 수 있다.

3.6 Partition Evolution

Iceberg에서 파티션 사양은 시간에 따라 추가될 수 있다. 예를 들어 "처음에는 일별, 트래픽이 늘면서 시간별로" 같은 운영 패턴이 가능하다.

-- 처음: 일별 파티션
ALTER TABLE events SET TBLPROPERTIES (...);
-- partition spec id = 0 : (day(event_ts))
 
-- 운영 중에 시간별로 변경
ALTER TABLE events
  REPLACE PARTITION FIELD event_ts WITH hours(event_ts);
-- partition spec id = 1 : (hour(event_ts))

운영상 주의점:

  • 과거 데이터는 옛 partition spec으로 남아 있고, 새 쓰기만 새 spec을 따른다.
  • 따라서 동일 테이블 안에 두 가지 partition spec이 공존한다. 쿼리는 두 spec 모두에 대해 정확하게 동작하지만, Pruning 효율은 spec별로 다르다.
  • 필요하면 rewrite_data_files로 옛 데이터를 새 spec에 맞춰 재작성할 수 있다(데이터 이동 비용 발생).

3.7 V1 vs V2 vs V3 — 사양의 진화

항목V1V2V3 (2025~)
표준화 시점2018~2021~2025+
Row-level Delete불가 (CoW만)Position / Equality delete fileDeletion vectors (Puffin)
시퀀스 번호없음있음 (정합성 위해 필수)유지
컬럼 default value없음없음있음
Variant 타입없음없음있음 (반구조화)
Geospatial 타입없음없음있음
Row Lineage없음없음있음 (CDC 친화)

V2가 만든 변화 — Row-level Delete:

  • V1에서는 한 행을 지우려면 그 행이 속한 파일 전체를 다시 써야 했다(Copy-on-Write, CoW).
  • V2는 두 종류의 delete file을 도입해 "옛 파일 + 삭제 표시"로 표현할 수 있게 했다(Merge-on-Read, MoR).
    • Position delete: (파일경로, 행 위치) 형태. CDC·MERGE 워크로드에 유리.
    • Equality delete: (컬럼=값) 형태. 키 기반 삭제에 유리.
  • 읽을 때 엔진은 delete를 메모리에서 적용한다. 자주 컴팩션해 주지 않으면 읽기가 느려진다.

V3가 만든 변화:

  • Deletion Vectors(Puffin 포맷) — V2의 position delete를 더 효율적으로 표현. Roaring bitmap을 사용해 메모리·디스크 사용량이 줄어든다.
  • Variant 타입 — JSON 같은 반구조화 데이터를 일관된 인코딩으로 저장하고, 엔진들이 같은 방식으로 해석한다.
  • Row Lineage — 각 행에 안정적인 ID를 부여해 CDC·머신러닝 재현성에 활용.

3.8 Copy-on-Write vs Merge-on-Read

V2 이후 가장 중요한 운영 결정은 테이블 단위로 CoW와 MoR 중 무엇을 쓸지이다.

측면Copy-on-Write (CoW)Merge-on-Read (MoR)
UPDATE/DELETE 시 동작영향받는 파일을 새로 씀옛 파일 유지 + delete file 추가
쓰기 비용높음 (대형 파일 재작성)낮음 (작은 delete 파일만 쓰기)
읽기 비용낮음 (delete 적용 없음)높음 (delete를 메모리 적용)
압축·정렬 상태즉시 유지점진적으로 악화, 컴팩션 필요
적합 워크로드분석 위주, 정정이 드문 테이블CDC, GDPR 정정, 빈번한 upsert

운영 권고:

  • 분석 중심 테이블(예: 일별 집계, 별표 스키마 팩트)는 CoW 권장.
  • CDC·MERGE 패턴(예: 실시간 사용자 상태 테이블)은 MoR + 주기적 컴팩션 권장.
  • 테이블 속성으로 명시적으로 지정한다:
    ALTER TABLE events SET TBLPROPERTIES (
      'write.delete.mode'='merge-on-read',
      'write.update.mode'='merge-on-read',
      'write.merge.mode' ='merge-on-read'
    );

3.9 Time Travel, Branch, Tag

Iceberg의 스냅샷 모델은 자연스럽게 Git 같은 데이터 버전 관리로 확장된다.

-- 시간 여행 (특정 시각)
SELECT * FROM events FOR SYSTEM_TIME AS OF '2026-05-20 09:00:00';
 
-- 스냅샷 ID로 직접 지정
SELECT * FROM events VERSION AS OF 8123412345678901234;
 
-- 브랜치 생성 (Write-Audit-Publish 패턴)
ALTER TABLE events CREATE BRANCH `wap-2026-05-20`;
-- 새 브랜치에서 변경 후 검증
INSERT INTO events.`wap-2026-05-20` SELECT ...;
-- 검증 통과 시 main으로 fast-forward
ALTER TABLE events FAST FORWARD `main` TO `wap-2026-05-20`;
 
-- 태그 (영구 보존 지점)
ALTER TABLE events CREATE TAG `q1-2026-close`
  AS OF VERSION 8123412345678901234
  RETAIN 365 DAYS;

활용 패턴:

  • Write-Audit-Publish (WAP) — 새 데이터를 일단 브랜치에 쓰고, 품질 검증(예: dbt test, Great Expectations)이 통과한 뒤에 main으로 병합. 검증 실패 시 브랜치만 폐기하면 끝이라, "잘못된 데이터가 잠시라도 main에 노출되는" 위험을 막는다.
  • ML 실험 격리 — 모델 학습용 스냅샷을 태그로 고정(예: model-v3-train). 6개월 뒤에도 동일한 데이터로 재학습 가능.
  • 법적 정정·감사 — 정정 직전 상태를 태그로 보존, 감사인에게 "정정 전·후"를 모두 보여줄 수 있다.

4. 운영 관점의 Iceberg

4.1 유지보수 작업 표준 셋

Iceberg를 운영한다는 것은 곧 다음 네 가지 유지보수 작업을 자동화한다는 의미다.

작업무엇을 하는가빈도 권장
rewrite_data_files작은 파일을 큰 파일로 합치고, 정렬 순서를 적용일~주 단위
rewrite_manifestsmanifest를 재구성해 Pruning 효율 회복주~월 단위
expire_snapshots오래된 스냅샷과 그것만 참조하던 파일을 정리일 단위
remove_orphan_files어떤 메타데이터도 참조하지 않는 데이터·메타 파일 정리주~월 단위

이 네 작업을 빠뜨리면 어떤 일이 일어나는가:

  • 작은 파일 폭증 — 스트리밍 잡이 10초마다 커밋하면 하루 8,640개 파일. 한 달이면 26만 개. 쿼리당 manifest를 수천 개씩 읽어야 한다.
  • 메타데이터 폭증 — 스냅샷이 수만 개 쌓이면 metadata.json 자체가 수십 MB가 되고, 모든 쓰기가 그것을 통째로 다시 쓰기 때문에 커밋이 느려진다.
  • 저장 비용 폭증 — expire가 안 되면, 한 행을 1억 번 업데이트한 테이블의 실제 저장량은 원본의 수십 배가 된다.

4.2 컴팩션 설계

-- Spark SQL: 기본 컴팩션
CALL system.rewrite_data_files(
  table => 'db.events',
  options => map(
    'min-input-files',     '5',
    'target-file-size-bytes','536870912', -- 512 MiB
    'rewrite-all',         'false'
  )
);
 
-- 정렬 추가
CALL system.rewrite_data_files(
  table => 'db.events',
  strategy => 'sort',
  sort_order => 'event_ts ASC, user_id ASC'
);

설계 원칙:

  • target-file-size = 256~1024 MiB 사이. 너무 작으면 list/open 비용, 너무 크면 셔플·메모리 부담.
  • 정렬 키는 가장 자주 Pruning에 쓰이는 컬럼으로. lower/upper bound 효율이 극대화된다.
  • MoR 테이블은 delete file 적용까지 한 번에 처리되므로, 정기 컴팩션이 쿼리 성능 유지의 핵심.
  • 잡 크기 제어 — 한 번에 모든 파일을 다시 쓰지 말고, 파티션 또는 시간 범위 기반으로 점진 컴팩션. where 옵션으로 범위를 좁힌다.

4.3 스냅샷 만료와 정리

-- 7일 이전 스냅샷 만료, 최소 5개는 보존
CALL system.expire_snapshots(
  table => 'db.events',
  older_than => TIMESTAMP '2026-05-13 00:00:00',
  retain_last => 5
);
 
-- 어떤 스냅샷도 참조하지 않는 고아 파일 정리 (3일 이상 묵은 것)
CALL system.remove_orphan_files(
  table => 'db.events',
  older_than => TIMESTAMP '2026-05-17 00:00:00'
);

운영 권고:

  • older_than은 보수적으로 — 진행 중인 장기 잡(예: 6시간짜리 백필)이 옛 스냅샷을 참조하고 있을 수 있다.
  • remove_orphan_files는 신중히 — 잘못 호출하면 다른 잡이 동시에 쓴 파일을 지울 수 있다. 드라이런(dry_run => true)으로 먼저 검증한 뒤 실행한다.
  • 시간 여행 SLA를 결정 — "30일 이전 시점은 복원하지 않는다"는 정책을 명시하면, 만료 기준이 명확해진다.

4.4 카탈로그 선택

Iceberg는 카탈로그를 추상화하지만, 실제로 어떤 카탈로그를 쓸지가 운영 모델을 좌우한다.

카탈로그적합 시나리오한계
Hive Metastore (HMS)기존 Hive 자산 위에서 점진 도입멀티-엔진 환경에서 일관성·권한 모델 약함
AWS GlueAWS 단일 클라우드, Athena/EMR/Redshift 통합AWS 외부에서는 사용 불편
REST Catalog멀티-엔진·멀티-클라우드, 표준 사양 기반자체 호스팅·운영 부담, 백엔드 구현체 선택 필요
Project NessieGit 같은 데이터 버저닝(브랜치/머지)권한·SaaS 옵션 제한
Snowflake PolarisSnowflake 중심 환경의 멀티-엔진 공유Snowflake 종속도 일부 잔존
Databricks Unity CatalogDatabricks 중심 환경, UC가 Iceberg를 일급으로 다룸UC 외부 엔진은 별도 REST 어댑터 필요

권장 패턴: 신규 멀티-엔진 환경이라면 REST Catalog 사양을 따르는 백엔드(예: Apache Polaris, Tabular OSS, Lakekeeper, Apache Gravitino, Unity Catalog OSS)를 두고, Spark·Trino·Flink·BigQuery·Snowflake 모두 그것을 통해 접근한다.

REST Catalog 토폴로지 — Spark·Trino·Flink·Snowflake·BigQuery 모두 단일 REST 카탈로그를 통해 같은 Object Storage 위의 테이블에 접근한다

4.5 쓰기 모드와 분배 튜닝

ALTER TABLE events SET TBLPROPERTIES (
  'write.distribution-mode'  = 'hash',          -- 'none' | 'hash' | 'range'
  'write.target-file-size-bytes' = '536870912', -- 512 MiB
  'write.parquet.compression-codec' = 'zstd',
  'write.parquet.row-group-size-bytes' = '134217728',
  'commit.retry.num-retries' = '8',
  'commit.retry.min-wait-ms' = '500'
);

핵심 파라미터:

  • write.distribution-mode
    • none — 입력 분포 그대로. 작은 파일이 많이 생긴다.
    • hash — 파티션 컬럼 해시로 분배. 일반적 권장. 파티션당 파일 수가 일정해진다.
    • range — 정렬된 분포. 시간순 로그 같은 워크로드에 유리.
  • commit.retry.* — 다중 작성자 환경에서 낙관적 잠금(optimistic concurrency control) 실패 시 재시도 정책. 충돌이 잦으면 늘려두는 것이 안전.

4.6 모니터링 지표

Iceberg 테이블이 건강한지 보려면 다음 지표를 정기적으로 봐야 한다.

지표의미적신호
파티션당 평균 파일 수컴팩션 효과100개 초과
평균 파일 크기컴팩션·쓰기 분배32 MiB 미만
스냅샷 누적 수만료 정책 작동 여부1,000 초과
metadata.json 크기메타 폭증 신호8 MiB 초과
manifest 평균 크기·수Pruning 효율manifest 수 5,000 초과
평균 커밋 지연카탈로그·동시성 문제p95가 5 s 초과
delete file/data file 비율MoR 압축 필요5% 초과 시 컴팩션 권장

이 값을 주기적으로 카탈로그·메타데이터에서 추출해 대시보드에 올리는 것이 운영의 표준이다. Iceberg의 시스템 테이블(db.events.files, db.events.snapshots, db.events.manifests)을 그대로 사용할 수 있다.

-- 파일 통계
SELECT
  partition,
  count(*)              AS file_count,
  avg(file_size_in_bytes) AS avg_size,
  sum(file_size_in_bytes) AS total_size
FROM db.events.files
GROUP BY partition
ORDER BY file_count DESC;
 
-- 스냅샷 누적
SELECT count(*) FROM db.events.snapshots;

4.7 운영 자동화의 기본 형태

성숙한 Iceberg 운영팀이 갖춰야 할 자동화 잡 세트:

  1. 일별 컴팩션 잡 — 어제 파티션에 대해 rewrite_data_files (작은 파일이 임계치를 넘는 파티션만).
  2. 일별 만료 잡 — N일 이전 스냅샷 만료, 일정 개수는 항상 보존.
  3. 주별 manifest 재작성 잡rewrite_manifests.
  4. 월별 고아 정리 잡remove_orphan_files(드라이런 → 검증 → 실행).
  5. 테이블 건강도 리포트 잡 — 위 모니터링 지표를 추출해 대시보드·알림으로 송출.

이 잡들은 모두 멱등적이어야 하며, 실패해도 안전하게 재시도할 수 있어야 한다. 대형 환경에서는 이 자동화를 별도의 "테이블 관리 서비스"로 분리해 카탈로그와 함께 운영하는 것이 표준화되어 있다.


5. 엔진 호환성

5.1 핵심 엔진별 지원 현황 (2026년 시점)

엔진읽기쓰기DML시간여행브랜치/태그V2 (MoR)V3REST Catalog
Apache Spark진행중
Trino부분
Apache Flink✓ (스트리밍)일부일부진행중
Snowflake제한진행중✓ (Polaris)
Databricks (Unity)진행중✓ (UC OSS)
BigQuery일부일부일부진행중✓ (BigLake)
AWS Athena일부진행중✓ (Glue)
ClickHouse실험적부분
DuckDB실험적부분
PyIceberg일부진행중

위 표는 2026년 5월 기준 일반적 지원 수준 요약이며, 실제 채택 시에는 해당 엔진의 최신 릴리스 노트와 Iceberg 사양 호환 표를 함께 확인할 것을 권한다.

5.2 엔진별 권장 역할

  • Spark — 백필·대형 ETL·테이블 유지보수의 표준. system.* 프로시저가 가장 완성도 높음.
  • Trino — 인터랙티브 분석·BI 백엔드. 짧은 쿼리에 강점, MoR 적용도 안정적.
  • Flink — 스트리밍 적재. exactly-once 커밋과 V2 delete write에 강점.
  • Snowflake / Databricks — 사내 사용자 셀프 서비스·BI. 카탈로그를 통한 공유 테이블 패턴.
  • BigQuery / Athena — 보고서·임시 분석. 별도 인프라 운영 없이 쿼리만 필요할 때.
  • PyIceberg — 가벼운 ETL, ML 학습 파이프라인, 로컬·노트북에서의 검증.

5.3 REST Catalog의 의미

REST Catalog 표준이 정착한 2024~2025년 이후, **"엔진과 카탈로그를 분리해 자유롭게 조합한다"**가 현실이 됐다.

여러 엔진이 REST Catalog를 통해 같은 단일 진실 원천(테이블)에 접근하는 구조

이 의미는 결정적이다.

  • 엔진 종속을 끊는다. 한 엔진에서 다른 엔진으로 옮길 때 데이터 마이그레이션이 필요 없다.
  • 권한·감사·정책을 한 곳에 모은다. 카탈로그가 진정한 통제점(control plane)이 된다.
  • 새 엔진의 도입 비용이 낮아진다. REST 사양을 구현한 모든 엔진은 즉시 같은 테이블을 다룰 수 있다.

6. 다른 포맷과의 비교

6.1 Iceberg vs Delta Lake vs Hudi — 핵심 차이

항목IcebergDelta LakeHudi
출발점멀티-엔진, 메타데이터 중심Spark·Databricks 중심, 트랜잭션 로그스트리밍 upsert·증분 처리
메타데이터 모델스냅샷 + manifest 트리트랜잭션 로그(JSON) + 체크포인트타임라인(.hoodie) + 메타
카탈로그 추상화일급 (REST 사양)부수적 (Unity가 점차 채움)외부 의존
Hidden Partitioning제한적 (Generated Column)일부
Partition Evolution제한적일부
Schema Evolution안전(ID 기반)안전(이름 기반)안전
Row-level DeleteV2 delete files / V3 vectorsDeletion VectorsSoft delete + 컴팩션
시간여행
브랜치/태그✓ (Git 같은 의미)제한적 (Time travel만)제한적
멀티-엔진 성숙도가장 높음Databricks 중심, 외부 엔진 향상 중Spark/Flink 중심
스트리밍 워크로드가능, 점점 강해짐가능가장 성숙
표준 사양 공개사양 v3까지 공개·합의사양 공개되나 Databricks 주도공개

6.2 의사결정 트리

Iceberg vs Delta Lake vs Hudi 의사결정 트리 — 단일 엔진 여부, 멀티 엔진 여부, CDC 비중, 장기 보존·실험 격리 요구, Hive 자산 마이그레이션 여부의 다섯 가지 질문으로 포맷을 선택한다

6.3 Delta-Iceberg 호환 옵션

2024년 이후 두 진영 모두 상호운용을 추구하면서 다음 옵션들이 등장했다.

  • Delta UniForm — Delta 테이블 옆에 Iceberg 메타데이터를 함께 생성해, Iceberg 리더가 Delta 테이블을 읽을 수 있게 한다. 단방향(Delta → Iceberg 읽기).
  • Apache XTable (구 OneTable) — 세 포맷(Iceberg/Delta/Hudi) 사이의 메타데이터를 변환한다. 데이터는 공유하고, 메타데이터만 각 포맷으로 표현.
  • Iceberg REST를 Delta가 노출 — Unity Catalog OSS가 Iceberg REST 사양으로 Delta 테이블을 노출하는 방향으로 가고 있다.

호환 옵션은 편리하지만, **"네이티브 사양 그대로"**가 항상 가장 안정적이다. 호환 모드의 알려진 한계(예: V2 delete 호환 미지원 구간)는 도입 전에 명확히 검토해야 한다.


7. 도입 전략과 마이그레이션 패턴

7.1 어떤 워크로드부터 도입할 것인가

도입 우선순위 권고:

  1. 장기 보존·법적 정정 대상 데이터 — 시간여행과 브랜치/태그 가치가 즉시 발현.
  2. 멀티-엔진 공유가 필요한 핵심 팩트 테이블 — 한 번 표준화하면 사내 분석 인프라 전체에 파급.
  3. 새로 시작하는 도메인의 마트 — 가장 적은 리스크로 운영 경험 축적.
  4. 기존 Hive 핵심 테이블 — 가장 큰 이득이 있지만 마이그레이션 부담도 크다. 위 1~3에서 운영 노하우를 확보한 뒤 진입.

7.2 Hive → Iceberg 마이그레이션 옵션

세 가지 표준 패턴이 있다.

(a) migrate — 제자리 교체

CALL system.migrate('hive_db.events');
-- Hive 테이블의 metadata를 Iceberg metadata로 교체.
-- 데이터 파일은 그대로 유지. 가장 빠른 옵션.
  • 장점: 데이터 이동 없음, 분 단위로 끝남.
  • 단점: 옛 Hive 디렉터리 구조(파티션 키 표현)가 그대로 남아 hidden partitioning의 이점을 일부 못 받음. 옛 파일에 컬럼 ID가 부여되며, 일부 엔진은 첫 쿼리에서 추가 비용 발생.

(b) snapshot — 그림자 테이블

CALL system.snapshot('hive_db.events', 'iceberg_db.events_v2');
-- Hive 테이블을 그대로 두고, 같은 데이터 파일을 참조하는 Iceberg 테이블을 생성.
-- 검증·비교 기간 동안 양쪽에 쓰기를 병행할 수 있다.
  • 장점: 운영 중 안전한 비교·롤백 가능.
  • 단점: 두 메타데이터를 동시에 유지해야 하는 기간이 생김.

(c) CTAS — 풀 재작성

CREATE TABLE iceberg_db.events
USING iceberg
PARTITIONED BY (days(event_ts))
TBLPROPERTIES ('write.distribution-mode'='hash')
AS SELECT * FROM hive_db.events;
  • 장점: 새 파티션·정렬·압축 코덱·파일 크기 정책을 처음부터 적용. 가장 깨끗한 상태.
  • 단점: 데이터를 다시 쓴다. 페타바이트급은 시간·비용이 크다.

권장: 핵심 테이블·장기 운영 테이블은 (c), 단기 비교가 필요한 경우 (b), 빠른 도입이 우선이면 (a).

7.3 Delta → Iceberg

옵션:

  1. UniForm 사용 — Delta는 그대로 두고 Iceberg 메타데이터를 추가 생성. 읽기만 필요할 때 가장 저렴.
  2. XTable로 양방향 메타데이터 변환 — 데이터는 공유, 메타데이터는 양쪽 포맷 모두로 노출.
  3. CTAS로 풀 재작성 — Iceberg 네이티브 운영을 시작할 준비가 됐다면 권장.

운영 권고: Delta 위에서 운영 중인 핵심 워크로드는 즉시 옮기지 말고, 새 도메인이나 그림자 테이블로 Iceberg 운영 경험을 6~12개월 쌓은 뒤 단계적으로 이전한다.

7.4 단계별 도입 체크리스트

0단계 — 사전 평가 (2~4주)

  • 사내 엔진·카탈로그·스토리지 현황 인벤토리
  • 후보 워크로드 3개 선정 (도입 우선순위 기준에 따름)
  • 카탈로그 선택 결정 (REST / Glue / Unity / Polaris 등)
  • 운영 자동화 잡 계획 수립

1단계 — PoC (4~8주)

  • 후보 테이블 1개에 대해 snapshot 또는 CTAS로 Iceberg 버전 생성
  • 두 엔진(예: Spark + Trino)으로 동일 결과 검증
  • 컴팩션·만료·고아 정리 잡 실행, 모니터링 지표 수집
  • WAP 패턴, 시간여행 사례 1건 실제 적용

2단계 — 운영 자동화 (4~8주)

  • 위 §4.7의 자동화 잡 5종 전사 표준 정의 및 배포
  • 카탈로그·권한·감사 모델 정착
  • 모니터링 대시보드·알림 임계값 합의
  • 운영 Runbook 문서화 (실패 시나리오 포함)

3단계 — 확장 (3~6개월)

  • 도입 우선순위에 따라 핵심 테이블 마이그레이션
  • 사내 데이터 카탈로그·BI·ML 파이프라인을 새 카탈로그에 연결
  • Iceberg V3 도입 여부 결정 (변동성·성숙도 평가)

7.5 마이그레이션 시 흔한 실수

  • 카탈로그 결정 미루기 — "일단 데이터부터 옮기자"는 접근은 곧 카탈로그가 운영의 병목이 된다. 1순위로 결정한다.
  • 운영 자동화 늦추기 — PoC에서 잘 돌던 것이 6개월 후 메타데이터 폭증으로 멈춘다. 운영 자동화는 PoC와 동시에 만든다.
  • CoW vs MoR 일괄 결정 — 테이블별 워크로드 특성을 무시하고 한 가지로 통일하면, CDC 테이블이 느려지거나 분석 테이블이 정렬을 잃는다. 테이블 단위로 결정한다.
  • 시간여행 SLA 미정의 — "언제까지의 데이터를 복원할 수 있는가"를 정하지 않으면 만료 정책이 보수적이 되어 비용이 계속 증가한다.
  • 컴팩션 잡의 셔플 폭주 — 한 잡이 너무 큰 범위를 컴팩션하면 클러스터를 마비시킨다. 범위·시간을 잘게 쪼개고, 잡 단위 자원 한도를 명시한다.

8. 2026년 시점 전망

8.1 사양 진화

  • V3의 보편화 — Variant·Geospatial·Deletion Vectors가 2026년 후반부터 주요 엔진에서 GA로 자리잡을 것으로 보인다. CDC·실시간 분석 워크로드에서 V3의 이득이 가장 크다.
  • Row Lineage의 부상 — 행 단위 안정 ID는 CDC·feature store·재현 가능한 ML 학습에 직접적 의미가 있다. 이는 데이터 거버넌스·계보(lineage) 도구와 결합되며 새로운 운영 패턴을 만들 것이다.
  • Materialized View의 표준화 — Iceberg 위의 MV·집계 캐시가 사양 수준에서 합의되면서, 분석 워크로드 비용 구조가 다시 바뀔 가능성이 크다.

8.2 카탈로그 진영의 합종연횡

  • Polaris(공개)·Unity OSS·Lakekeeper·Apache Gravitino 등이 REST 사양을 공통 표준으로 두고 경쟁한다. 표준 사양이 있기 때문에, 어떤 백엔드를 쓰든 사용자는 동일한 인터페이스를 본다.
  • 상용 서비스 vs OSS의 균형 — 카탈로그를 SaaS로 쓸지, 직접 운영할지가 향후 3년의 핵심 결정이 된다. 권한·감사·메타데이터 관리의 깊이가 비용을 좌우한다.

8.3 엔진 측의 변화

  • AI/ML 워크로드와의 통합 — Iceberg의 브랜치/태그·시간여행은 학습 데이터 재현, 모델·데이터 버전의 동기화에 활용된다. 2026년 이후 feature store·MLOps 도구가 Iceberg를 일급으로 다루는 흐름이 강해진다.
  • OLAP 엔진의 직접 지원 확대 — ClickHouse·StarRocks·DuckDB 등 OLAP 엔진의 Iceberg 직접 쓰기 지원이 빠르게 성숙 중이다.

8.4 데이터 거버넌스의 통제점 이동

Iceberg·REST Catalog 조합은 거버넌스의 통제점을 "엔진"에서 "카탈로그"로 이동시킨다. 데이터 마스킹·행 단위 필터·감사 로그가 카탈로그 레벨에서 결정되면, 어떤 엔진에서 접근해도 동일한 정책이 적용된다. 이는 멀티-엔진 환경의 컴플라이언스를 사실상 처음으로 일관되게 만든다.


9. 결론과 권고

9.1 핵심 메시지

  • Iceberg는 단순한 테이블 포맷이 아니라, 개체 스토리지 위의 데이터베이스 의미론을 제공하는 메타데이터 사양이다.
  • 그 가치는 단일 엔진 환경에서는 부분적으로만 드러나며, 멀티-엔진·장기 운영·정정·실험 격리 워크로드에서 결정적이다.
  • 2026년 현재 REST Catalog 표준 + V3 사양의 조합으로, Iceberg는 사실상 멀티-엔진 Lakehouse의 표준 포맷이 됐다.
  • 그러나 운영 자동화 없이 Iceberg를 도입하면 곧 메타데이터 운영 비용이 도입 효과를 상쇄한다. 컴팩션·만료·고아 정리·모니터링은 사양 이해와 동등하게 중요하다.

9.2 도입 권고

시나리오권고
신규 멀티-엔진 데이터 플랫폼 구축Iceberg + REST Catalog를 처음부터 표준으로 채택
기존 Databricks 단일 환경 + 외부 엔진 도입 검토Delta UniForm 또는 점진적 Iceberg 도입
Hive 기반 레거시 마이그레이션우선순위 테이블부터 단계적 도입, CTAS 권장
실시간 CDC·upsert 중심Iceberg V2/V3 (MoR) 또는 Hudi와 비교 검토
ML·실험 재현성 중요Iceberg 브랜치/태그·시간여행 활용

9.3 Data Dynamics의 지원 영역

본 백서를 작성한 Data Dynamics는 다음 영역에서 Iceberg 도입을 지원합니다.

  • Lakehouse 아키텍처 설계 및 검토 — 카탈로그·엔진·스토리지 토폴로지 권고
  • 마이그레이션 실행 — Hive·Delta로부터의 단계적 이전, PoC부터 운영 자동화까지
  • 운영 자동화 표준화 — 컴팩션·만료·정리 작업의 멱등 잡 설계, 모니터링 대시보드
  • 카탈로그 운영 — REST Catalog 백엔드(Polaris, Unity OSS, Lakekeeper) 선정·운영
  • 엔진 통합 — Spark·Trino·Flink·Snowflake·Databricks·BigQuery 간 일관성 검증

도입 전 진단·기술 워크숍이 필요한 경우 문의로 연락 주시면, 사내 환경에 맞춘 도입 로드맵을 함께 정리해 드립니다.


10. 참고 자료


본 백서는 2026년 5월 기준 정보를 바탕으로 작성되었습니다. Iceberg 사양과 엔진 호환 상태는 빠르게 진화하므로, 도입 시점의 최신 릴리스 노트와 사양 호환 표를 함께 확인할 것을 권합니다.