Apache Iceberg v3의 Row Lineage·Deletion Vectors·VARIANT 이해하기
Apache Iceberg v3의 Row Lineage, Deletion Vectors, VARIANT 타입이 CDC·삭제·반정형 데이터 처리에 미치는 변화를 정리한다.
2026-08-14 · 최초 발행 2026-05-05
v3가 겨냥한 데이터 레이크의 빈틈
Apache Iceberg는 v1(2018)과 v2(2022)를 거치며 발전했지만, 대규모 데이터 레이크에서 남아 있던 문제가 있었다. 행 단위 변경을 추적하려면 엔진별 CDC 구현이 필요했고, 삭제는 Parquet 파일을 다시 쓰거나 삭제 파일을 계속 쌓는 방식에 기대야 했다. JSON이나 이벤트 로그 같은 반정형 데이터도 문자열 칼럼에 넣거나 스키마를 반복해서 바꿔야 했다.
Apache Iceberg 커뮤니티는 2025년 중반 v3 스펙을 승인했다. Databricks Unity Catalog는 이를 퍼블릭 프리뷰로 먼저 지원한다고 선언했다. v3의 Row Lineage, Deletion Vectors, VARIANT 타입은 각각 변경 추적, 삭제 성능, 반정형 데이터 문제를 다룬다.
메타데이터와 데이터 파일이 만나는 지점
세 기능은 개별 옵션으로만 존재하지 않는다. 메타데이터, 데이터 파일, 쿼리 실행 계층이 연결된 테이블 포맷의 일부로 작동한다.
테이블 메타데이터의 next-row-id는 다음 행에 할당할 전역 고유 ID를 관리한다. 데이터 파일에는 _row_id와 _last_updated_sequence_number라는 숨겨진 메타데이터 필드가 들어가며, Puffin 파일은 데이터 파일의 삭제 벡터 사이드카 역할을 맡는다.
Row Lineage로 행 변경을 포맷에 기록한다
v2까지 행 수준 변경 추적은 쿼리 엔진마다 구현 방식이 달랐다. 이 차이는 서로 다른 엔진을 잇는 CDC 파이프라인에서 호환성 문제로 이어질 수 있었다.
v3는 두 행 메타데이터 필드를 스펙으로 정의한다.
_row_id— 테이블 전체에서 고유한long타입 식별자다. 행이 처음 추가될 때 정해지고, 이후에는 바뀌지 않는다._last_updated_sequence_number— 해당 행을 마지막으로 수정한 스냅샷의 시퀀스 번호다. 행이 업데이트될 때 갱신된다.
이 값은 커밋 성공 후 상속 방식으로 배정된다. 커밋 시퀀스 번호와 시작 Row ID는 스냅샷 확정 전에는 알 수 없기 때문에, 엔진이 즉시 기록하는 대신 메타데이터 상속 메커니즘으로 사후 반영한다.
CDC 소비자가 증분 범위를 정하는 방식
기존 CDC는 타임스탬프 칼럼 또는 별도 변경 로그 테이블을 유지하는 경우가 많았다. v3에서는 _last_updated_sequence_number를 사용해 특정 스냅샷 뒤에 변경된 행을 필터링할 수 있다.
-- 마지막으로 처리한 시퀀스 번호 이후의 변경 행만 추출
SELECT *
FROM orders
WHERE _last_updated_sequence_number > :last_processed_seq
ORDER BY _last_updated_sequence_number;
AWS는 Amazon EMR 7.12·AWS Glue·Amazon SageMaker를 통해 이 기능을 통합 지원한다고 발표했다. Snowflake도 Row Lineage를 바탕으로 한 양방향 CDC 지원을 선언했다.
삭제 파일 누적 대신 비트맵을 붙이는 Deletion Vectors
v2의 행 삭제 방식은 Copy-on-Write(CoW)와 Merge-on-Read(MoR)로 나뉜다. CoW는 삭제할 때 데이터 파일 전체를 다시 쓰므로 쓰기 비용이 크다. MoR는 포지셔널 삭제 파일을 별도로 만들지만, 파일이 누적되면 읽기 성능이 떨어질 수 있다.
v3의 Deletion Vectors는 MoR를 확장한 방식이다. 데이터 파일마다 Puffin 사이드카 파일을 연결하고, 삭제된 행 위치를 Roaring Bitmap에 기록한다.
Puffin은 임의의 바이너리 블롭(blob)과 이를 해석하는 메타데이터를 함께 담도록 설계된 컨테이너 포맷이다. Deletion Vector가 Puffin 블롭으로 저장되면 매니페스트 파일에는 데이터 파일의 참조 경로, Puffin 파일 안의 오프셋, 바이트 길이가 기록된다.
Roaring Bitmap은 내부적으로 64비트 위치를 지원한다. 대부분의 실용 케이스에서는 32비트 청크로 나눠 메모리 효율을 높인다. 하나의 스냅샷에는 데이터 파일당 최대 하나의 Deletion Vector가 존재하며, 새 삭제가 생기면 기존 벡터를 대체한다.
AWS 벤치마크에서는 삭제 연산 시간이 v2 대비 약 55% 단축됐다(3.126초 → 1.407초). 삭제 파일 크기는 Parquet 기반 v2의 1,801바이트에서 Puffin 기반 v3의 475바이트로 약 73.6% 감소했다. 전체 테이블 스캔 속도는 28.5%, 필터 기반 조회는 23% 향상됐다.
반정형 데이터를 칼럼으로 다루는 VARIANT
VARIANT는 JSON, 이벤트 스트림, API 응답 같은 반정형 데이터를 Iceberg 칼럼에 직접 담기 위한 타입이다. STRING으로 직렬화하는 방식과 달리 구조 메타데이터를 함께 인코딩하므로, 중첩 필드 추출과 필터 푸시다운을 효율적으로 처리한다.
Apache Parquet 프로젝트가 VARIANT의 바이너리 인코딩을 정의했으며, Spark·Flink·Trino·Hive는 공통 구현체를 공유한다. Iceberg 스펙은 BSON 등을 포함한 특정 인코딩을 강제하지 않는다. 각 엔진은 중첩 객체 접근에 적합한 바이너리 표현을 선택할 수 있다.
스키마가 자주 바뀌거나 미리 구조를 알 수 없는 이벤트 데이터, IoT 페이로드, 외부 API 응답은 VARIANT를 우선할 수 있다. 새 필드를 스키마 변경 없이 수용할 수 있기 때문이다.
반대로 칼럼 수준 통계, 파티셔닝, 압축 최적화가 필요한 고정 구조 데이터에는 정형 스키마가 여전히 유리하다. Iceberg의 Avro 기반 매니페스트 메타데이터 파일은 v3에서도 계속 사용된다. Snowflake 엔지니어링 블로그는 넓은 nullable 스키마와 비교해 VARIANT 저장이 스토리지 공간을 절감하고 스키마 변경 빈도를 낮춘다고 밝혔다.
Unity Catalog에서 v3 테이블을 설정하는 방법
Databricks Unity Catalog에서는 테이블을 만들거나 업그레이드할 때 속성을 명시해 v3 기능을 설정한다.
-- Iceberg v3 테이블 생성 (모든 v3 기능 활성화)
CREATE TABLE catalog.schema.orders (
order_id BIGINT,
customer_id BIGINT,
status STRING,
event_payload VARIANT,
created_at TIMESTAMP
)
USING ICEBERG
TBLPROPERTIES (
'format-version' = '3',
'write.delete.mode' = 'merge-on-read',
'write.update.mode' = 'merge-on-read',
'write.merge.mode' = 'merge-on-read'
);
-- 기존 v2 테이블을 v3로 업그레이드
ALTER TABLE catalog.schema.orders
SET TBLPROPERTIES ('format-version' = '3');
Row Lineage는 format-version 3 테이블에서 자동 활성화된다. Deletion Vectors는 merge-on-read 모드를 지정해야 하며, VARIANT는 칼럼 타입을 VARIANT로 선언해 사용한다.
엔진 간 상호운용성의 범위
v3는 특정 벤더에 묶이지 않는 상호운용성을 설계 원칙으로 둔다. Databricks Spark, AWS Glue, Snowflake Polaris, Trino가 하나의 v3 테이블을 함께 읽고 쓰는 환경이 구축되고 있다.
| 플랫폼 | Row Lineage | Deletion Vectors | VARIANT | 상태 |
|---|---|---|---|---|
| Databricks Unity Catalog | 지원 | 지원 | 지원 | 퍼블릭 프리뷰 |
| AWS Glue / EMR 7.12 | 지원 | 지원 | 지원 예정 | GA |
| Snowflake | 지원 | 지원 | 지원 | 발표 |
| Apache Spark 4.0+ | 지원 | 지원 | 지원 | GA |
| Trino / Starburst | 지원 | 지원 | 지원 | GA |
| Apache Flink | 지원 | 지원 | 개발 중 | 부분 지원 |
Row Lineage 필드인 _row_id, _last_updated_sequence_number는 Delta Lake의 행 추적 기능과 호환되는 설계로 채택됐다. Deletion Vectors의 이진 인코딩도 Delta Lake와 같은 방식을 사용하도록 맞춰졌다. 두 포맷 사이의 변환 비용을 줄이려는 의도가 반영돼 있다.
CDC 파이프라인에서의 결합 구조
Row Lineage와 Deletion Vectors를 함께 쓰면 CDC가 테이블의 고유한 속성이 된다. 별도 로그 테이블이나 타임스탬프 관리 없이 다음과 같은 파이프라인을 구성할 수 있다.
소스 시스템의 INSERT·UPDATE·DELETE가 Iceberg 테이블에 반영되면, 행은 _row_id로 지속적으로 식별되고 _last_updated_sequence_number에는 최종 변경 시점이 기록된다. 삭제 행은 Deletion Vector에 비트가 설정되므로 물리 파일을 다시 쓰지 않고 논리적으로 제외할 수 있다.
다운스트림 소비자는 마지막 처리 시퀀스 번호를 보관하고 다음 실행 때 그 이후 변경된 행만 읽는다. 이 방식으로 증분 처리가 가능하다.
테이블 포맷이 맡게 된 변경 관리
Iceberg v3는 단순한 기능 추가보다 데이터 레이크의 변경 관리 방식을 포맷 수준으로 옮긴 변화에 가깝다. Row Lineage는 변경 추적을 테이블 스펙에 포함하고, Deletion Vectors는 삭제 비용과 파일 관리를 바꾸며, VARIANT는 반정형 데이터를 칼럼의 구성원으로 다룬다.
Databricks·Snowflake·AWS가 지원 계획을 발표한 배경도 여기에 있다. CDC 파이프라인, 데이터 레이크 아키텍처, 반정형 데이터 처리 방식을 설계할 때 v3 마이그레이션을 검토할 수 있는 시점이다.
Sources
- The Next Era of the Open Lakehouse: Apache Iceberg™ v3 in Public Preview on Databricks
- Apache Iceberg™ v3: Moving the Ecosystem Towards Unification | Databricks Blog
- Advancing the Lakehouse with Apache Iceberg v3 on Databricks
- Accelerate data lake operations with Apache Iceberg V3 deletion vectors and row lineage | AWS
- Unlock the power of Apache Iceberg v3 deletion vectors on Amazon EMR | AWS
- What's new in Apache Iceberg v3? | Google Open Source Blog
- The Apache Iceberg™ Variant Type: Flexible Semistructured Data, Reimagined | Snowflake
- Announcing Apache Iceberg v3 Support on Snowflake
- Working with Iceberg table format specification version 3 - AWS Prescriptive Guidance
- Iceberg v3: Getting Started | Starburst
- Deletion vectors and Puffin files merge in the new v3 Iceberg format | Medium
- Spec - Apache Iceberg™