학습 목표
data lake·warehouse·lakehouse의 차이와 선택 기준을 설명할 수 있다.
medallion (bronze · silver · gold) 계층을 설계할 수 있다.
Delta Lake·Apache Iceberg 같은 open table format이 parquet 위에 주는 ACID를 설명할 수 있다.
5·6편 Spark·7편 warehouse와 lakehouse 경계를 맞출 수 있다.
문제 상황
- S3에 parquet 수천 개 —
dt=2026-08-01폴더만 지웠는데 다른 job이 깨진 스냅샷 읽음 - Snowflake에 raw·mart 둘 다 — 스토리지 비용 폭증, Spark는 export 다시
- 동시 write 두 job — 같은 경로에 overwrite — 행 반쯤 섞인 파일
- 5편
gold/user_day_revenue— schema 컬럼 추가 시 과거 partition 전부 재작성 - 6편 foreachBatch merge — 직접 짜기 복잡 — table format 없음
- 7편 KPI 정본 — warehouse mart vs lake gold 이중 — 어느 쪽이 진짜인지
이번 편은 object storage 위에 warehouse급 테이블을 얹는 lakehouse다. 스키마·품질은 9편.
1. Data lake vs warehouse vs lakehouse
| Data lake | Data warehouse | Lakehouse | |
|---|---|---|---|
| 저장 | object storage 파일 | 관리형 컬럼 스토어 | object storage + table format |
| 스키마 | schema on read | schema on write | 진화 가능한 테이블 스키마 |
| ACID | 없음 (파일 단위) | 강함 | 트랜잭션 로그로 파일에 부여 |
| 엔진 | Spark·Python 자유 | SQL BI 최적 | Spark·SQL·ML 동일 데이터 |
| 비용 | 저렴·거버넌스 약 | 쿼리·저장 비쌈 | 저장 저렴 + 선택적 compute |

data lake — s3://raw/events/*.json (files only)
warehouse — analytics.mart_revenue (managed table)
lakehouse — s3://lake/gold/revenue/ (Delta or Iceberg table)
- data lake — 4편 Kafka → S3 적재의 자연스러운 종착 — raw 보존
- warehouse — 7편 ELT·dbt·BI — SQL·권한 성숙
- lakehouse — 한 벌의 데이터로 Spark (5·6편)와 SQL 공유 — 이중 복제 감소
- 완전 대체 아님 — warehouse는 lakehouse 위 external table·federation으로 공존 흔함
2. Medallion architecture
bronze → silver → gold — 품질·스키마 엄격도가 올라가는 계층.

| 층 | 역할 | 7편 대응 | 예 |
|---|---|---|---|
| Bronze | raw ingest, append | staging raw | Kafka Avro, CDC JSON |
| Silver | 정제·dedupe·join | intermediate | stg_orders 정제 |
| Gold | mart·KPI·feature | marts | user_day_revenue |
bronze/orders/ ──► silver/orders_clean/ ──► gold/revenue_daily/
append only business rules BI · ML consume
- bronze — 가공 최소 — replay·감사 — PII 원본 주의
- silver — 여러 gold가 쓰는 로직 한 곳 — 7편 intermediate
- gold — metric 정본 — warehouse sync 또는 gold가 정본
- partition —
dt·hour— 5편 배치 slice·incremental 공통 - table format — bronze도 Delta 가능 — append·time travel 이득
3. Open table format
parquet만 쓰면 디렉터리 = 테이블 — 동시 write·schema 변경·삭제가 원자적이지 않다.

| 기능 | plain parquet | Delta · Iceberg |
|---|---|---|
| ACID write | ✗ | ✓ commit 단위 |
| Time travel | ✗ (수동 스냅샷) | ✓ 버전·timestamp |
| Schema evolution | 수동 | add·rename 지원 |
| MERGE / UPSERT | 직접 구현 | 내장 (엔진별) |
| Streaming sink | 위험 | 6편 merge 단순화 |
s3://lake/silver/orders/
_delta_log/ ← transaction metadata
part-00000.parquet ← immutable data files
part-00001.parquet
- 데이터 파일 — 여전히 columnar (parquet) — 압축·predicate pushdown 유지
- 메타데이터 — 어떤 파일이 현재 스냅샷인지 — reader는 log만 따라감
- 작은 파일 문제 — compaction (OPTIMIZE · rewrite) — 운영 필수
- catalog — Glue · Unity · Hive Metastore — 테이블 이름 → storage 경로
4. Object storage 위의 ACID
S3·ADLS는 파일 PUT만 — DB식 트랜잭션 없음. table format이 commit 프로토콜로 보완.

| 속성 | lakehouse에서의 의미 |
|---|---|
| Atomicity | commit 성공 or 전부 무효 — 반쯤 쓴 파일 노출 안 함 |
| Consistency | 스냅샷 하나 — 모든 reader 동일 버전 |
| Isolation | writer commit 전 — reader는 이전 스냅샷 |
| Durability | object storage 내구성 + log 순서 |
writer: new parquet files ──► commit v3 to log ──► readers see v3
(not visible until commit succeeds)
- Optimistic concurrency — 동시 writer — 충돌 시 재시도
- 5편
mode("overwrite")partition — table format replaceWhere·merge로 대체 - 6편 streaming — foreachBatch + MERGE — idempotent sink
- time travel —
VERSION AS OF·TIMESTAMP AS OF— 디버깅·감사·재현 - 10편 — backfill 시 버전 관리·rollback
5. Delta Lake vs Apache Iceberg
둘 다 open table format — 엔진·생태계·운영 차이로 고른다.

| Delta Lake | Apache Iceberg | |
|---|---|---|
| 메타데이터 | _delta_log (JSON) |
manifest · metadata tree |
| 강점 | Spark·Databricks 통합 | 엔진 중립 (Trino·Flink) |
| MERGE | Spark SQL 성숙 | Spark·Flink·다엔진 |
| 파티션 | 명시 partitionBy |
hidden partitioning |
| 카탈로그 | Unity · Hive | REST (Glue · Nessie) |
| 선택 힌트 | Spark 중심 스택 | 다엔진·벤더 회피 |
- 둘 다 parquet 데이터 — 마이그레이션·dual write 도구 존재 (상황별)
- Spark 5·6편 —
format("delta")·format("iceberg")— readStream·batch 동일 - 7편 dbt — warehouse native vs lakehouse external — dbt-spark·metric 단일화 논의
- 벤더 — Databricks Delta 기본, AWS Iceberg 밀어 — lock-in vs 호환 트레이드오프
# code/delta_batch.example.py (발췌)
daily.write.format("delta").mode("overwrite").option(
"replaceWhere", f"dt = '{dt}'"
).partitionBy("dt").save("s3://lake/gold/user_day_revenue")
# code/iceberg_merge.example.py (발췌) — 6편 streaming upsert
spark.sql(f"""
MERGE INTO lake.gold.order_errors t
USING batch b ON t.order_id = b.order_id AND t.window_start = b.window_start
WHEN MATCHED THEN UPDATE SET *
WHEN NOT MATCHED THEN INSERT *
""")
6. Spark와 lakehouse 연결
5·6편 process 출력을 table로 승격 — 파일 폴더 관리에서 해방.
| 시나리오 | 패턴 |
|---|---|
| 일 배치 gold | 5편 job → Delta overwrite replaceWhere dt |
| 스트림 sink | 6편 writeStream.format("delta") + checkpoint |
| CDC ingest | bronze append → silver MERGE |
| ML feature | gold Delta — time travel로 학습 스냅샷 고정 |
| BI | Trino·Spark SQL 같은 gold — warehouse sync 선택 |
# code/lakehouse.conf.yaml (발췌)
lake:
catalog: glue
format: delta
layers:
bronze: s3://data-lake/bronze
silver: s3://data-lake/silver
gold: s3://data-lake/gold
gold_tables:
- name: user_day_revenue
partition: dt
source_job: spark-batch-user-day-revenue
- readStream + Delta — schema evolution — 9편 검증
- shuffle·partition — 5편 튜닝 그대로 — storage만 table
- Z-order·liquid clustering (Delta) — 파일 레이아웃 — 쿼리 가속
- warehouse — Snowflake Iceberg external · BigQuery BigLake — gold 공유 경로
7. Lakehouse vs warehouse 경계
| 질문 | lakehouse | warehouse |
|---|---|---|
| 정본 KPI | gold Delta/Iceberg | mart table |
| SQL BI | Trino·Athena·Spark SQL | 네이티브 warehouse |
| 비용 | storage 저렴, compute 분리 | 통합 요금 |
| 거버넌스 | catalog·9편 품질 | built-in RBAC |
- 하이브리드 — gold in lake → nightly sync → warehouse mart (7편 ELT)
- lakehouse only — BI도 lake 직접 — warehouse 축소
- 중복 피하기 — 한 metric 한 물리 테이블 — 문서·lineage
- PII — bronze 암호화·column mask — lake 권한 세분화
8. 설계 체크리스트
| # | 질문 |
|---|---|
| 1 | bronze/silver/gold 경계와 7편 staging/marts 매핑이 명확한가 |
| 2 | parquet 폴더를 table format으로 승격할 우선순위는 |
| 3 | Delta vs Iceberg — 엔진·카탈로그·벤더와 **맞는가 |
| 4 | 동시 write·streaming sink에 MERGE·idempotency가 있는가 |
| 5 | compaction·small files 운영 주기가 있는가 |
| 6 | KPI 정본 — lake gold vs warehouse — 하나로 **정했는가 |
- migration — copy-on-write 큰 테이블 — shadow table 검증 후 cutover
- partition 설계 — cardinality·retention — Database 파티션 개념 유사
- 9편 — schema evolution 정책·breaking change 테스트
- 10편 — backfill·실패 복구 — version rollback
정리
- Lakehouse — 저렴한 object storage + open table format + Spark/SQL
- Medallion — bronze → silver → gold — 7편 layering과 대응
- Delta·Iceberg — parquet 위 ACID·time travel·MERGE
- 5·6편 Spark — batch·streaming 출력을 테이블로 관리
- warehouse와 공존·동기화 — 정본 한 곳만 정하기
다음에 다룰 것
- 스키마·품질·계보
- schema evolution, data quality check, lineage
해당 내용은 Delta Lake documentation, Apache Iceberg documentation, Kleppmann — Designing Data-Intensive Applications (Ch 10) 를 기반으로 합니다.
'Data & AI' 카테고리의 다른 글
| ETL vs ELT (0) | 2026.07.15 |
|---|---|
| Spark Structured Streaming (0) | 2026.07.13 |
| Spark 배치 처리 (0) | 2026.07.09 |
| Kafka 기초 (0) | 2026.07.05 |
| Batch vs Stream (0) | 2026.07.03 |