1820 words
9 minutes
[Iceberg]Open Table format 개요

01. Overview#

  • 오픈 테이블 포맷(Open Table Format) 동작 방식 간단히 정리
  • S3, GCS와 같은 저렴한 객체 스토리지 위에서 어떻게 RDBMS 수준의 데이터 변경(UPDATE/DELETE)과 ACID 트랜잭션이 가능한지

02. 객체 스토리지(S3)의 불변성 문제#

  • 전통적인 RDBMS는 블록 스토리지 기반이므로 특정 행(Row)만 찾아가서 덮어쓰는(UPDATE) 작업이 자연스러움.
  • S3의 한계 (Immutability): 객체 스토리지는 태생적으로 ‘불변(Immutable)’
  • 역설적 상황: 1GB 크기의 Parquet 파일에 저장된 수백만 명의 고객 정보 중, 단 1명의 주소가 변경되었다고 가정. S3에서는 그 한 줄만 수정할 수 없음. 1GB 파일을 통째로 읽어 주소를 수정한 뒤, 새로운 1GB 파일로 전체를 다시 써야 함.
  • 데이터가 수백 TB 쌓이는 환경에서 다수의 사용자가 동시에 데이터를 수정하거나 삭제하면, 데이터 정합성이 깨지고 파이프라인이 붕괴

03. Metadat Layer#

  • Apache Iceberg, Delta Lake, Apache Hudi는 이 불변성의 한계를 극복하기 위해 스토리지와 컴퓨팅 엔진 사이에 **‘메타데이터 레이어(Metadata Layer)‘**를 강제 삽입
  • 핵심 아이디어는 “데이터 파일 자체를 수정하는 것이 아니라, 어떤 파일이 유효한지 가리키는 장부(메타데이터)를 건드리는 것”

데이터 변경 및 조회 프로세스#

  1. 신규 데이터 쓰기: Spark가 S3에 변경된 데이터를 담은 ‘새로운 Parquet 파일’을 추가함. (기존 원본 파일은 건드리지 않음)
  2. 트랜잭션 로그 기록: 쓰기 작업이 완료되면, 엔진이 새로운 메타데이터 파일(JSON/Avro 형태)을 생성.
  3. 포인터 전환 (Commit): 메타데이터에 *“구버전 파일 A는 무시하고, 신버전 파일 B를 유효한 테이블 데이터로 취급하라”*는 스냅샷(Snapshot) 정보를 기록.
  4. 데이터 조회 (Read): 사용자가 쿼리를 실행하면 엔진은 무조건 최신 메타데이터부터 읽음. 메타데이터가 지시하는 ‘현재 유효한 파일 목록’만 S3에서 스캔하므로 완벽한 트랜잭션 격리(Isolation)가 성립.

Delta Lake 데이터 병합(Merge) 예제#

from delta.tables import DeltaTable
# 메타데이터 레이어를 통해 S3 위에서도 RDBMS의 UPSERT(MERGE) 연산 지원
deltaTable = DeltaTable.forPath(spark, "s3://silver-data/users")
deltaTable.alias("target").merge(
source_df.alias("source"),
"target.user_id = source.user_id"
).whenMatchedUpdate(set = { "email": "source.email" } ) \
.whenNotMatchedInsertAll() \
.execute()

04. 데이터 변경 물리 전략: CoW vs MoR#

  • 오픈 테이블 포맷이 데이터를 업데이트할 때 내부적으로 사용하는 두 가지 핵심 전략.
  • 데이터 쓰기/읽기 패턴에 따라 아키텍처 레벨에서 선택

Copy-on-Write (CoW)#

  • 방식: 업데이트 발생 시 해당 레코드가 포함된 데이터 파일 전체를 새로 읽어 수정한 뒤, 새로운 파일로 덮어씀.
  • 적용 환경: 읽기(Read) 성능이 극도로 중요하고, 데이터 변경이 가끔 큰 배치(Batch) 형태로 일어날 때 적합.
  • 단점: 쓰기 증폭(Write Amplification)이 커서 쓰기 비용이 매우 높음.

Merge-on-Read (MoR)#

  • 방식: 변경된 레코드만 작은 로그 파일(Delta/Changelog)에 빠르게 기록.
  • 나중에 쿼리로 데이터를 읽을 때, 베이스 파일과 로그 파일을 실시간으로 병합(Merge)하여 반환.
  • 적용 환경: 쓰기/변경이 매우 빈번한 스트리밍이나 CDC(Change Data Capture) 환경에 적합.
  • 단점: 읽을 때마다 병합 연산이 발생하므로 조회(Read) 성능이 다소 떨어짐.

05. 시스템 유지보수와 트레이드오프#

메타데이터 조작 방식은 필연적으로 **‘쓰레기 파일 생성’**과 **‘파티션 단편화’**라는 관리 비용을 발생시킴.

  • Compaction (최적화): 잦은 업데이트로 인해 S3에 수 KB짜리 작은 파일이 수만 개 생성되면(Small File Problem), 메타데이터 스캔 자체가 병목이 됨. 주기적으로 작은 파일들을 큰 파일로 뭉쳐주는(Compaction) 작업이 필수적임.
  • Vacuuming (가비지 컬렉션): 과거 스냅샷을 유지하면 Time Travel(과거 시점 쿼리)이 가능하지만, 스토리지 비용이 폭발함. 더 이상 참조하지 않는 오래된 데이터 파일과 메타데이터를 주기적으로 물리 삭제(Vacuum)해야 함.

Concept

  • 오픈 테이블 포맷 (Open Table Format) : 객체 스토리지 위에서 대규모 데이터셋에 대한 ACID 트랜잭션, Time Travel, 스키마 진화 기능을 제공하는 메타데이터 관리 규격 (예: Iceberg, Delta Lake).
  • ACID 트랜잭션 : 원자성, 일관성, 격리성, 지속성을 보장하여 다수 사용자의 동시 데이터 접근 시 데이터 무결성을 유지하는 데이터베이스 속성.
  • Time Travel : 메타데이터 스냅샷 기록을 활용하여, 과거의 특정 시점(Timestamp) 기준으로 테이블 상태를 조회하거나 복구할 수 있는 기능.
  • Copy-on-Write (CoW) : 데이터 수정 시 원본 파일을 복사하여 변경 사항을 적용한 새로운 파일을 생성하는 물리적 업데이트 전략.
  • Merge-on-Read (MoR) : 데이터 수정 시 변경분만 별도 로그 파일에 기록하고, 읽기 시점에 원본과 병합하여 보여주는 물리적 업데이트 전략.
  • Compaction (컴팩션) : 쿼리 성능 저하를 막기 위해, 스토리지에 흩어진 수많은 작은 파일(Small Files)들을 읽기 좋은 크기의 큰 파일로 병합하는 최적화 과정.
  • Z-Ordering (Z-오더 커브) : 다차원 데이터를 1차원으로 매핑하여 비슷한 데이터를 물리적으로 가깝게 배치, 쿼리 시 스캔해야 하는 파일 수를 획기적으로 줄여주는 데이터 클러스터링 기법.
  • Data Catalog (Hive Metastore, Nessie) : 클러스터 외부에 존재하며, 여러 컴퓨팅 엔진(Spark, Trino 등)이 동일한 오픈 테이블 포맷 메타데이터를 찾을 수 있도록 돕는 중앙 저장소.


Key_Takeaways

  • 객체 스토리지는 데이터를 덮어쓸 수 없는 불변성을 가지며, 이로 인해 대규모 데이터 업데이트 시 심각한 비효율과 정합성 문제가 발생
  • Iceberg, Delta Lake 같은 오픈 테이블 포맷은 실제 데이터 파일 대신 메타데이터(장부)를 조작하는 방식으로 이 한계를 극복하고 트랜잭션을 구현한다.
  • 데이터 변경 전략은 읽기 성능을 우선하는 Copy-on-Write(CoW)와 쓰기 속도를 우선하는 Merge-on-Read(MoR)로 나뉘며 파이프라인 특성에 맞춰 선택해야 함
  • 이 아키텍처를 유지하려면, 수많은 자잘한 파일을 뭉치고(Compaction) 불필요한 과거 스냅샷을 지우는(Vacuuming) 지속적인 관리 작업이 수반되야 함

[Iceberg]Open Table format 개요
https://yjinheon.netlify.app/posts/02de/spark/de-opentable-opentableformat/
Author
Datamind
Published at
2026-03-02
License
CC BY-NC-SA 4.0