Blog
iceberglakehousetable-formatdata-platformsparktrino

Apache Iceberg 완벽 가이드 — 차세대 Lakehouse 테이블 포맷의 모든 것

Apache Iceberg의 등장 배경, 메타데이터 아키텍처, 핵심 기능, 카탈로그 종류, 엔진별 사용법, 운영 자동화, 성능 최적화, 실무 도입 전략까지 한 편으로 정리한 종합 가이드.

Data Dynamics2026년 5월 23일20 min read

이 글은 Apache Iceberg를 처음 접하는 데이터 엔지니어부터, 이미 운영 중인 플랫폼에서 Iceberg 도입을 고민 중인 아키텍트까지 모두를 대상으로 한 종합 가이드입니다. Iceberg가 왜 등장했는지, 내부적으로 어떻게 동작하는지, 어떻게 사용하고 운영해야 하는지를 실무 관점에서 정리합니다.


1. Apache Iceberg란?

1.1 등장 배경 — Hive 테이블 포맷의 한계

2010년대 빅데이터 생태계의 사실상 표준은 Hive Metastore + 디렉토리 파티셔닝 이었습니다. 단순하고 직관적인 이 구조는 HDFS 시대에는 잘 작동했지만, 클라우드 객체 스토리지(S3, ADLS, GCS)가 표준이 되면서 한계가 드러났습니다.

Hive 방식의 구조적 문제:

  • 디렉토리 = 파티션 = 쿼리 조건: WHERE event_date='2026-05-23'가 디렉토리 경로와 정확히 일치해야 Partition Pruning이 동작합니다. 사용자가 WHERE ts > ...처럼 표현식을 쓰면 Pruning이 무력화됩니다.
  • 파티션 진화 불가: "일별 파티션을 시간별로 바꾸자"는 결정이 곧 전체 테이블 재작성을 의미합니다.
  • 원자성 부재: S3에서 rename은 copy + delete로 구현되어, 잡 중간 실패 시 부분 가시성 문제가 발생합니다.
  • List 비용: 수십만 파일이 있는 prefix에 대한 S3 list 호출은 비싸고 일관성도 약합니다.
  • 읽기-쓰기 동시성 부재: 동일 파티션을 쓰는 동안 읽으면 부분 파일이 보일 수 있습니다.

이 한계를 해결하기 위해 Netflix에서 2017년에 시작한 프로젝트가 Apache Iceberg 입니다.

1.2 Iceberg의 핵심 가치

Iceberg는 객체 스토리지 위에 데이터베이스 수준의 트랜잭션과 진화(evolution) 의미론 을 부여하는 개방형 테이블 포맷 입니다.

가치설명
ACID 트랜잭션Snapshot 기반의 Serializable Isolation
Hidden Partitioning사용자가 파티션 컬럼을 알 필요 없이 자동 Pruning
Schema/Partition Evolution재작성 없이 스키마와 파티셔닝 변경
Time Travel과거 Snapshot 조회·롤백
Branch / TagGit처럼 테이블에 분기와 태그 부여
엔진 중립적Spark, Trino, Flink, Snowflake, BigQuery 등 다중 엔진 지원

1.3 Lakehouse 아키텍처에서의 위치

┌─────────────────────────────────────────────────┐
│   Spark │ Trino │ Flink │ Snowflake │ BigQuery  │  ← 멀티 엔진
├─────────────────────────────────────────────────┤
│              Iceberg Catalog (REST)             │  ← 통제점
├─────────────────────────────────────────────────┤
│   Iceberg Metadata (Snapshot / Manifest / ...)  │  ← 테이블 포맷
├─────────────────────────────────────────────────┤
│       Parquet / ORC / Avro (Data Files)         │  ← 파일 포맷
├─────────────────────────────────────────────────┤
│         Object Storage (S3 / ADLS / GCS)        │  ← 스토리지
└─────────────────────────────────────────────────┘

Iceberg는 "스토리지 포맷"이 아니라 "메타데이터 구조" 입니다. Parquet 같은 파일 포맷 위에 트랜잭션과 진화 의미론을 얹는 사양(spec)입니다.

1.4 주요 채택 사례

  • Netflix: 원개발사. 수십 페타바이트 규모의 데이터 플랫폼에서 사용.
  • Apple: 내부 데이터 플랫폼의 핵심 포맷.
  • Airbnb, LinkedIn, Stripe, Pinterest, Adobe: 멀티 엔진 환경에서 채택.
  • Snowflake, AWS, Google Cloud, Databricks: 외부 카탈로그·외부 테이블로 Iceberg를 1급 시민으로 지원.

2. Iceberg 아키텍처

2.1 3-Layer 메타데이터 구조

Iceberg는 메타데이터를 3개 계층으로 분리합니다.

Catalog (Hive / REST / Glue / Nessie ...)
    │
    └─▶ metadata.json (현재 스냅샷, 스키마, 파티션 spec)
            │
            └─▶ manifest list (snap-*.avro)
                    │
                    └─▶ manifest file (*.avro)
                            │
                            └─▶ data file (*.parquet)

2.2 디렉토리 구성 예시

warehouse/db/orders/
├── data/
│   ├── 00000-0-...parquet
│   └── 00001-0-...parquet
└── metadata/
    ├── v1.metadata.json
    ├── v2.metadata.json
    ├── snap-3051729675574597004-1-...avro    # manifest list
    └── 0c7a1f8c-...avro                       # manifest file
파일역할
metadata.json테이블의 현재 상태: 스키마, 파티션 spec, sort order, 현재 snapshot 포인터
Manifest List (snap-*.avro)한 Snapshot에 속한 모든 manifest의 목록 + 파티션 통계
Manifest File (*.avro)한 묶음의 데이터 파일 목록 + 컬럼별 통계 (min/max, null count 등)
Data File (*.parquet)실제 데이터

2.3 Snapshot 기반 트랜잭션 모델

모든 쓰기 작업은 새로운 Snapshot 을 생성합니다. Snapshot은 불변(immutable)이며, "그 시점의 테이블 상태"를 완전히 표현합니다.

Snapshot 0 (테이블 생성)
    │
    ├─▶ INSERT  → Snapshot 1
    │
    ├─▶ UPDATE  → Snapshot 2
    │
    └─▶ DELETE  → Snapshot 3 (현재)

쓰기는 Optimistic Concurrency Control(OCC) 로 직렬화됩니다. Commit 시점에 카탈로그가 atomic compare-and-swap으로 current snapshot pointer를 교체합니다. 충돌이 발생하면 retry합니다.

2.4 Predicate Pushdown의 새로운 차원

쿼리 엔진은 manifest의 컬럼 통계를 보고 파일을 열기 전에 필요 없는 파일을 잘라낼 수 있습니다.

쿼리: SELECT * FROM orders WHERE order_date = '2026-05-23'

1. Manifest List 스캔 → 파티션 통계로 manifest 1개로 좁힘
2. Manifest 스캔     → 컬럼 min/max로 data file 5개로 좁힘
3. Data file 5개만 읽음

Hive는 list → 모든 파일 오픈 → footer 읽기 였지만, Iceberg는 manifest 한 번 읽기 → 필요한 파일만 오픈 입니다.


3. Iceberg 핵심 기능

3.1 Schema Evolution

Iceberg는 모든 컬럼에 고유 ID 를 부여합니다. 이름이 아니라 ID로 매핑하므로, 컬럼 이름 변경/재배치도 안전합니다.

연산HiveIceberg
Add columnOKOK
Drop column위험안전
Rename column위험안전
Reorder column위험안전
Type promote (int → long)부분안전
ALTER TABLE orders ADD COLUMN customer_tier STRING;
ALTER TABLE orders RENAME COLUMN amt TO amount;
ALTER TABLE orders ALTER COLUMN amount TYPE BIGINT;

3.2 Hidden Partitioning과 Partition Evolution

Hive에서는 사용자가 WHERE event_date='2026-05-23'처럼 파티션 컬럼을 직접 써야 했습니다. Iceberg는 파티션 변환(transform)을 메타데이터에 저장합니다.

CREATE TABLE orders (
    id BIGINT,
    ts TIMESTAMP,
    amount DECIMAL(10,2)
) USING iceberg
PARTITIONED BY (days(ts));     -- ts에서 일자를 자동 추출
 
-- 사용자는 ts만 알면 됨
SELECT * FROM orders WHERE ts >= '2026-05-23';

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

Partition Evolution: 운영 중에 파티션 전략을 바꿀 수 있습니다.

ALTER TABLE orders DROP PARTITION FIELD days(ts);
ALTER TABLE orders ADD PARTITION FIELD hours(ts);

기존 파일은 그대로 두고, 신규 쓰기부터 새 전략을 적용합니다.

3.3 Time Travel, Tag, Branch

-- Snapshot ID로 조회
SELECT * FROM orders VERSION AS OF 3051729675574597004;
 
-- 타임스탬프로 조회
SELECT * FROM orders TIMESTAMP AS OF '2026-05-20 00:00:00';
 
-- 태그 생성 (영구 보존)
ALTER TABLE orders CREATE TAG `release-2026-Q2`;
 
-- 브랜치 생성 (실험용)
ALTER TABLE orders CREATE BRANCH experimental;

3.4 Row-Level 연산 — CoW vs MoR

모드동작쓰기 비용읽기 비용
Copy-on-Write (CoW)영향받은 파일 전체를 다시 씀높음낮음
Merge-on-Read (MoR)Delete file을 추가, 읽을 때 병합낮음높음

CDC처럼 잦은 UPDATE/DELETE에는 MoR, 분석 위주에는 CoW를 권장합니다.

V2 spec에서 도입된 Delete 종류:

  • Position Delete: "파일 X의 N번째 row를 삭제"
  • Equality Delete: "특정 컬럼이 특정 값인 row를 삭제"

V3에서는 Deletion Vector 가 도입되어 MoR의 효율이 크게 개선됩니다.


4. Iceberg Catalog

4.1 Catalog의 역할

Catalog는 "테이블 이름 → 현재 metadata.json 위치" 매핑을 보관합니다. 쓰기 시 atomic swap을 제공해야 하므로, Iceberg에서 Catalog는 데이터베이스의 트랜잭션 매니저에 해당합니다.

4.2 Catalog 종류

Catalog특징권장 환경
Hive Metastore기존 HMS 재활용Hive 자산이 많은 온프레미스
Hadoop (file-based)카탈로그 서버 없이 파일 락개발/테스트만
REST Catalog엔진 중립 표준 API신규 도입 시 1순위
AWS GlueAWS 통합AWS-native 환경
NessieGit 같은 multi-table branchingData versioning
Snowflake / Polaris관리형Snowflake와 Iceberg 공유
Unity CatalogDatabricks 통합Databricks와 Iceberg 공유
JDBC관계형 DB 사용간단한 메타스토어

4.3 REST Catalog 표준의 의미

REST Catalog는 카탈로그를 언어/엔진 중립 HTTP API 로 정의한 표준입니다. Spark, Trino, Flink, PyIceberg가 모두 동일 API로 접근하므로, 카탈로그 구현체를 자유롭게 교체할 수 있습니다. 2026년 현재 Iceberg 생태계의 사실상 표준은 REST Catalog입니다.


5. Iceberg 사용하기

5.1 Spark

-- Spark 설정 (REST Catalog)
spark.sql.catalog.demo                = org.apache.iceberg.spark.SparkCatalog
spark.sql.catalog.demo.type           = rest
spark.sql.catalog.demo.uri            = http://iceberg-rest:8181
spark.sql.catalog.demo.warehouse      = s3://my-warehouse
CREATE TABLE demo.db.orders (
    id BIGINT,
    customer_id BIGINT,
    ts TIMESTAMP,
    amount DECIMAL(10,2)
) USING iceberg
PARTITIONED BY (days(ts));
 
INSERT INTO demo.db.orders VALUES (1, 100, current_timestamp(), 99.99);
 
MERGE INTO demo.db.orders t
USING updates u
ON t.id = u.id
WHEN MATCHED THEN UPDATE SET amount = u.amount
WHEN NOT MATCHED THEN INSERT *;

5.2 Trino

-- Trino catalog 설정 파일 (iceberg.properties)
connector.name      = iceberg
iceberg.catalog.type = rest
iceberg.rest-catalog.uri = http://iceberg-rest:8181
SELECT * FROM iceberg.db.orders WHERE ts >= DATE '2026-05-01';
 
-- 메타데이터 테이블
SELECT * FROM iceberg.db."orders$snapshots";
SELECT * FROM iceberg.db."orders$files";
SELECT * FROM iceberg.db."orders$partitions";

5.3 Flink로 스트리밍 적재

CREATE TABLE orders_iceberg (
    id BIGINT,
    ts TIMESTAMP(3),
    amount DECIMAL(10,2)
) WITH (
    'connector' = 'iceberg',
    'catalog-type' = 'rest',
    'uri' = 'http://iceberg-rest:8181',
    'warehouse' = 's3://my-warehouse'
);
 
INSERT INTO orders_iceberg
SELECT * FROM kafka_orders;

5.4 PyIceberg

from pyiceberg.catalog import load_catalog
 
catalog = load_catalog(
    "demo",
    **{
        "type": "rest",
        "uri": "http://iceberg-rest:8181",
        "warehouse": "s3://my-warehouse",
    },
)
 
table = catalog.load_table("db.orders")
 
# Pandas로 직접 읽기
df = table.scan(
    row_filter="ts >= '2026-05-01'",
    selected_fields=("id", "amount"),
).to_pandas()

6. 운영과 유지보수

6.1 Compaction — Small File 문제

스트리밍 적재 등으로 작은 파일이 누적되면 쿼리 성능이 급격히 떨어집니다. 정기적으로 컴팩션이 필요합니다.

-- Spark Action
CALL demo.system.rewrite_data_files(
    table => 'db.orders',
    options => map('target-file-size-bytes', '536870912')   -- 512MB
);

6.2 Snapshot Expiration

Snapshot이 계속 쌓이면 메타데이터가 비대해지고 데이터 파일도 GC되지 않습니다.

CALL demo.system.expire_snapshots(
    table => 'db.orders',
    older_than => TIMESTAMP '2026-05-01 00:00:00',
    retain_last => 10
);

6.3 Orphan File 정리

실패한 쓰기 등으로 메타데이터에 참조되지 않는 고아 파일이 생길 수 있습니다.

CALL demo.system.remove_orphan_files(
    table => 'db.orders',
    older_than => TIMESTAMP '2026-05-01 00:00:00'
);

6.4 Metadata Rewrite

Manifest가 너무 많아지면 plan 시간이 늘어납니다.

CALL demo.system.rewrite_manifests(table => 'db.orders');

6.5 운영 자동화 표준 패턴

작업주기도구
rewrite_data_files시간/일 단위Spark Action, Airflow
expire_snapshots일 단위Spark Action
remove_orphan_files주 단위Spark Action
rewrite_manifests필요 시Spark Action
메트릭 수집분 단위Catalog API + Prometheus

운영 자동화 없이는 Iceberg는 빠르게 "메타데이터 늪"이 됩니다.


7. Iceberg Spec 진화 (V1 → V2 → V3)

버전출시핵심 기능
V12019Snapshot, Schema/Partition Evolution, Hidden Partitioning
V22021Row-level Delete (Position/Equality Delete), MoR
V32025+Deletion Vector, Variant 타입, Geospatial, Default values, Row Lineage

V3의 Deletion Vector는 Position Delete 파일 대신 압축 비트맵을 사용하여, MoR 워크로드의 읽기 성능을 대폭 개선합니다.

호환성 주의:

  • 상위 버전 테이블을 하위 버전만 지원하는 엔진은 읽지 못합니다.
  • V2 → V3 업그레이드는 일방향입니다.
  • 모든 클라이언트(Spark, Trino, Flink) 버전을 미리 확인해야 합니다.

8. Delta Lake / Hudi와의 비교

항목IcebergDelta LakeHudi
원개발사NetflixDatabricksUber
트랜잭션 로그Manifest treeJSON logTimeline
Hidden PartitioningOK부분부분
Partition EvolutionOK미지원미지원
Schema Evolution강함강함강함
CoW / MoR둘 다CoW (DV 도입)둘 다
Branch / TagOK미지원미지원
REST Catalog 표준OKUC 종속미지원
단일 엔진 친화보통매우 강함(Databricks)보통
멀티 엔진 친화매우 강함보통 (UniForm)보통

선택 기준:

  • Databricks-only 환경 → Delta Lake
  • 잦은 Upsert + 스트리밍 → Hudi
  • 멀티 엔진, 장기 보존, 진화 의미론 → Iceberg

Delta Lake가 UniForm, Iceberg가 XTable 같은 상호운용 레이어를 도입하면서, 미래에는 포맷 선택이 점점 덜 중요해질 가능성이 큽니다.


9. 성능 최적화 베스트 프랙티스

9.1 파일 크기

너무 작은 파일(<100MB)은 plan 오버헤드, 너무 큰 파일(>2GB)은 병렬성 저하. 보통 256MB~1GB 권장.

ALTER TABLE orders SET TBLPROPERTIES (
  'write.target-file-size-bytes' = '536870912'
);

9.2 파티셔닝 전략

  • 카디널리티가 너무 높은 컬럼으로 파티셔닝하지 마세요 (e.g. user_id).
  • 시간 컬럼은 거의 항상 day 또는 hour transform 사용.
  • 고-카디널리티 컬럼은 bucket(N, col)로 처리.

9.3 Sort Order / Z-Order

쿼리 패턴에 맞춰 정렬하면 manifest pruning 효과가 극대화됩니다.

ALTER TABLE orders WRITE ORDERED BY ts, customer_id;

9.4 Manifest 분할

대형 테이블에서는 manifest를 파티션별로 분할해 plan 비용을 줄입니다. rewrite_manifests Action 활용.

9.5 안티 패턴

  • Snapshot Expiration 미실행 → 메타데이터 폭증
  • 컴팩션 미실행 → 수십만 작은 파일
  • 너무 잦은 commit → manifest 폭증
  • 파티션 컬럼 과다 → list 비용 증가
  • Hadoop Catalog 운영 사용 → commit 충돌, 데이터 손실 위험

10. 실무 도입 가이드

10.1 기존 Hive 테이블 마이그레이션

두 가지 방식이 있습니다.

방식동작비용롤백
Snapshot (snapshot 프로시저)원본 Hive 테이블 유지하면서 Iceberg shadow 생성낮음쉬움
Migrate (migrate 프로시저)원본을 in-place로 Iceberg로 변환낮음어려움
-- 방식 1: 검증용 shadow 생성
CALL demo.system.snapshot('hive_db.orders', 'demo.db.orders');
 
-- 방식 2: 검증 끝나면 완전 전환
CALL demo.system.migrate('hive_db.orders');

10.2 CDC 파이프라인 구축

RDB → Debezium → Kafka → Flink → Iceberg (MoR)
                                      │
                                      └─▶ Compaction (배치)

핵심 포인트:

  • Flink Iceberg sink는 upsert 모드로 Equality Delete 사용
  • 분 단위 commit (너무 자주는 X)
  • 야간 배치로 컴팩션 + snapshot expiration

10.3 거버넌스와 보안

  • AWS Lake Formation: Glue Catalog + Iceberg에 행/열 수준 권한
  • Apache Ranger: Hive/Trino + Iceberg에 정책 기반 인가
  • Unity Catalog: Databricks 환경에서 Iceberg 외부 테이블 통제

10.4 비용 최적화

  • 컴팩션 파일 크기 조정으로 list/get 호출 수 절감
  • Snapshot 보존 기간을 워크로드별로 차등 (시계열 vs 마스터)
  • S3 Intelligent-Tiering으로 오래된 Snapshot 데이터 자동 이동
  • Manifest 캐시(Spark, Trino)로 plan 시간 단축

11. 마무리

11.1 언제 Iceberg를 선택해야 하는가

다음 중 2개 이상 해당된다면 Iceberg가 명확한 우위입니다.

  • 2개 이상의 쿼리 엔진을 동시에 사용한다 (Spark + Trino, Flink + Snowflake 등)
  • 장기 보존 데이터에 대한 시간 여행, 법적 정정이 필요하다
  • 파티션 전략을 향후 변경할 가능성이 있다
  • 실험·재현성을 위한 브랜치/태그가 필요하다
  • 특정 벤더(Databricks 등)에 lock-in되고 싶지 않다

11.2 Iceberg 생태계의 미래

  • REST Catalog 표준화: 카탈로그가 Lakehouse의 진정한 통제점(control plane) 으로 자리잡고 있습니다.
  • V3 확산: Deletion Vector, Variant, Geospatial 지원으로 활용 범위 확대.
  • 상호운용성: XTable, UniForm으로 Iceberg ↔ Delta ↔ Hudi 경계가 흐려집니다.
  • 관리형 카탈로그 경쟁: Snowflake Polaris, Databricks Unity, AWS Glue, Tabular의 후계자들이 시장을 형성합니다.

11.3 학습 리소스

Iceberg는 더 이상 "새로운 옵션"이 아닙니다. 멀티 엔진 Lakehouse의 사실상 표준 이며, 카탈로그 계층이 데이터 플랫폼의 통제점으로 부상하는 흐름의 중심에 있습니다. 도입 자체보다, 운영 자동화와 카탈로그 전략에 더 많은 고민을 투자하시기 바랍니다.