LLM WikiAccess-protected knowledge portal

WIKI

Apache Iceberg 1.11: 삭제 벡터·REST 카탈로그 서버 사이드 플래닝·Variant 타입으로 완성된 V3

V3 table format은 왜 필요했는가 Apache Iceberg는 V1/V2 table format으로 ACID 트랜잭션, snapshot isolation, partition evolution을 데이터 레이크에 가져왔다. 그러나 V2 이후에도 남아 있던 세 가지 운영 부담이 있었다. 첫째, 행 삭제의 비용 V2에서 행 삭제는 positional delete file이나 equality delete file로 구현된다.

경로human/study/content/database-frontier/06-apache-iceberg-1-11-deletion-vectors-rest-catalog-variant.md
카테고리Study
태그#catalog #deletion #infra #mysql #rest #study #variant #vectors

V3 table format은 왜 필요했는가

Apache Iceberg는 V1/V2 table format으로 ACID 트랜잭션, snapshot isolation, partition evolution을 데이터 레이크에 가져왔다. 그러나 V2 이후에도 남아 있던 세 가지 운영 부담이 있었다.

첫째, 행 삭제의 비용: V2에서 행 삭제는 positional delete file이나 equality delete file로 구현된다. 이 파일들은 파편화되고 개수가 늘어날수록 읽기 시 merge 비용이 커진다.

둘째, 카탈로그 클라이언트의 metadata 직접 접근: 모든 쿼리 엔진이 직접 object storage를 뒤져 manifest와 data file 목록을 탐색했다. 테이블이 크고 파티션이 많을수록 planning 시간이 길어졌다.

셋째, 반정형 데이터 표현의 한계: JSON 컬럼을 string으로 저장하면 predicate pushdown이 불가능하고, 별도 nested struct로 표현하면 schema evolution이 제한됐다.

2026년 5월 19일 출시된 Apache Iceberg 1.11.0은 이 세 문제 모두에 대한 생산 준비 완료(production-ready) 구현을 담았다. 삭제 벡터(deletion vectors), REST 카탈로그 서버 사이드 scan planning, Variant 타입이 V3 table spec의 핵심이다.

이 장은 2026년 7월 15일 기준으로 작성했다. Iceberg 1.11.0은 2026-05-19에 출시됐다. 90일 recency 기준을 충족한다. 삭제 벡터와 Variant 타입은 V3 table format에서만 사용 가능하다. V3 테이블을 새로 만드는 경우와 기존 V1/V2 테이블을 유지하는 경우를 구분해 읽는다.


1.11.0에서 바뀐 V3 핵심 경계

기능1.11 이전 상태1.11에서운영자가 얻는 것
행 삭제positional/equality delete filedeletion vector (Puffin)삭제가 많아도 읽기 overhead 고정
카탈로그 scan planning엔진이 직접 manifest 탐색REST 카탈로그 server-side plan드라이버가 object storage를 읽지 않음
반정형 데이터string/map으로 저장네이티브 Variant 타입predicate pushdown, shredding 최적화
암호화외부 도구 의존테이블 수준 envelope encryptionKMS 연동, 열 단위 보호
파일 포맷 API엔진별 구현 분산통합 File Format APIParquet·ORC·Avro 일관된 read/write
Java 지원Java 11 포함Java 17+ 필수최신 JDK 기능 활용, Java 11 제거

V3 테이블의 핵심 구조

Apache Iceberg 1.11 V3: 삭제 벡터·서버 사이드 플래닝·Variant 쿼리 엔진 Spark 4.1 / Flink 2.1 Trino / DuckDB / ... Java 17+ 필수 (1.11부터) REST Catalog (서버 사이드 플래닝) POST /tables/{t}/plan FileScanTask 반환 대용량: plan-id 폴링 POST /tasks 병렬 요청 Object Storage metadata/ snapshot/ manifests data files (Parquet/ORC/Avro) 엔진이 직접 탐색하지 않음 (server-side plan) V3 Table Metadata Snapshot manifest list 포인터 Manifest File data + delete file 목록 Puffin File deletion vector 저장소 삭제 벡터 (Deletion Vector) Puffin 파일에 저장, data file 1개 ↔ deletion vector 1개 (1:1) Roaring Bitmap 32-bit 위치: 단일 bitmap 64-bit 위치: key → sub-bitmap 읽기 시 동작 bitmap mask를 읽기에 적용 삭제 파일 open 불필요 V2 positional delete: 파일 파편화 증가 → merge 비용 증가 / V3 DV: overhead 고정 V3 추가 기능 Variant 타입 (반정형 데이터) 이진 인코딩: predicate pushdown 직접 적용 shredding: 자주 쓰는 nested path → 자동 서브컬럼 JSON string 대비 쿼리 성능·압축률 향상 테이블 암호화 (Envelope Encryption) 데이터 암호화 키(DEK) + 키 암호화 키(KEK) 이중 구조 Google KMS 연동 지원 (1.11.0 기준) 열 단위 암호화 지원 File Format API (통합 read/write API) Parquet · ORC · Avro 일관된 인터페이스
Apache Iceberg 1.11 V3 table 아키텍처: 삭제 벡터·REST 카탈로그·Variant

삭제 벡터: Roaring bitmap으로 행 삭제를 압축하는 방법

V2까지의 Iceberg는 행을 삭제할 때 positional delete file을 만들어 "이 data file의 이 위치에 있는 행은 삭제됐다"고 기록했다. 쿼리 시 엔진은 data file과 delete file을 모두 열어 merge해야 했다. 삭제 연산이 누적되면 delete file도 늘어나 읽기 비용이 선형으로 증가했다.

V3의 deletion vector는 이 구조를 바꾼다.

저장 구조: data file 하나마다 deletion vector 하나가 1:1로 대응한다. deletion vector는 Roaring bitmap으로 삭제된 행의 ordinal position을 압축 저장한다. Puffin 파일 포맷에 담겨 metadata 영역에 보관된다.

비트맵 세부 구조: Iceberg V3 spec은 64-bit 위치를 지원한다. 대부분의 행이 32-bit 범위에 있을 때는 단일 32-bit Roaring bitmap을 쓴다. 64-bit 위치가 필요하면 상위 32-bit를 key로, 하위 32-bit를 해당 key의 32-bit bitmap에 저장하는 계층 구조를 쓴다.

읽기 시 동작: 엔진은 data file을 읽기 전에 해당 deletion vector bitmap을 로드한다. bitmap에 표시된 행을 mask한 채로 data를 스캔한다. 별도 delete file을 열거나 merge하지 않는다.

이 구조가 주는 운영상 이점은 명확하다. 삭제가 얼마나 쌓여도 data file당 bitmap 하나만 읽으면 된다. V2의 positional delete file처럼 삭제 이력이 여러 파일에 파편화되지 않는다.

주의: deletion vector는 V3 table에서만 사용 가능하다. V1/V2 테이블을 V3로 업그레이드하지 않으면 기존 positional delete file 방식을 유지한다.


REST 카탈로그 서버 사이드 scan planning

기존에는 Spark/Trino 같은 엔진이 직접 카탈로그에서 snapshot을 가져온 뒤 manifest list → manifest file → data file 경로를 object storage에서 직접 탐색했다. 테이블이 크고 파티션이 많을수록 드라이버 노드가 수많은 object storage 요청을 보내야 했다.

1.11의 server-side scan planning은 이 작업을 REST 카탈로그 서버로 이전한다.

엔진 측: /v1/{prefix}/namespaces/{namespace}/tables/{table}/plan 엔드포인트에 POST 요청을 보낸다. 요청 본문에 scan 조건(snapshot, filter 등)을 포함한다.

카탈로그 서버 측: manifest 탐색을 서버에서 수행하고 최적화된 FileScanTask 객체 목록을 반환한다.

규모에 따른 처리 방식:

규모카탈로그 응답엔진 동작
소규모즉시 FileScanTask 목록 반환한 번의 응답으로 완료
대규모plan-id 반환폴링하여 준비 확인
초대규모plan-id + 병렬 /tasks 엔드포인트병렬 POST로 분할 수신

운영자 관점에서 얻는 이점은 두 가지다. 첫째, 드라이버가 object storage를 직접 탐색하지 않으므로 드라이버 메모리 압박과 S3/GCS API 호출 수가 줄어든다. 둘째, 카탈로그 서버가 scan plan을 캐시하고 최적화할 수 있어 반복 쿼리 성능이 향상된다.

제약: 서버 사이드 scan planning을 활용하려면 카탈로그 서버(REST Catalog 구현체)가 이 API를 구현해야 한다. 오픈소스 REST Catalog 구현체마다 지원 여부가 다르다. 1.11.0 기준으로 Iceberg 자체 REST Catalog 구현은 이 API를 지원하지만, Polaris나 Unity Catalog 같은 외부 카탈로그는 별도 확인이 필요하다.


Variant 타입: 반정형 데이터를 이진 인코딩으로 저장한다

로그 이벤트, JSON API 응답, 사용자 activity 같은 데이터는 구조가 일정하지 않다. 지금까지는 이런 데이터를 string 열로 저장하거나 예측 가능한 부분을 별도 struct로 분리해야 했다.

string 저장의 문제: 쿼리 시마다 JSON을 파싱하고 predicate pushdown이 불가능하다.

V3의 Variant 타입은 이 데이터를 위한 네이티브 이진 인코딩이다.

Predicate pushdown: Variant 값 안의 특정 path를 직접 필터링할 수 있다. 엔진이 raw 이진 구조에서 바로 조건을 평가하므로 전체 값을 역직렬화하지 않아도 된다.

Shredding: Variant 데이터에서 자주 접근하는 nested path를 자동으로 별도 sub-column으로 추출한다. event.user_idevent.type 같은 경로는 독립 컬럼처럼 읽을 수 있어 전체 Variant blob을 읽지 않아도 된다.

-- V3 Variant 컬럼 쿼리 예시
SELECT event_data['user_id'], COUNT(*)
FROM logs
WHERE event_data['event_type'] = 'purchase'
  AND event_data['amount'] > 100.0
GROUP BY 1;

이 쿼리는 shredding이 설정된 경우 event_typeamount sub-column만 읽어 전체 JSON blob scan을 건너뛸 수 있다.


테이블 암호화와 File Format API

테이블 암호화: 1.11.0은 envelope encryption을 내장한다. DEK(Data Encryption Key)로 데이터를 암호화하고 KEK(Key Encryption Key)로 DEK를 다시 암호화한다. KEK는 외부 KMS에서 관리한다. 1.11.0 기준으로 Google Cloud KMS 연동을 지원하며, 열 단위 암호화도 가능하다. KMS 접근 권한이 없으면 해당 테이블을 읽거나 쓸 수 없으므로 KMS 가용성이 테이블 SLA에 직접 영향을 준다.

File Format API: V1/V2에서는 엔진마다 Parquet, ORC, Avro를 읽고 쓰는 코드가 제각각이었다. 1.11.0은 이를 통합하는 FileFormat API를 finalize했다. 새 엔진이나 파일 포맷을 추가할 때 일관된 인터페이스를 따르면 된다.

Partition Statistics Scan API: optimizer가 partition별 통계(행 수, null 비율 등)를 query planning 전에 읽는 새 API를 추가했다. CBO(Cost-Based Optimizer)가 partition pruning 결정에 더 정확한 정보를 사용할 수 있게 된다.


Java 17 최소 요구사항과 엔진 호환성

Breaking change: Iceberg 1.11.0은 Java 11 지원을 완전히 제거한다. core library와 모든 엔진 커넥터가 Java 17 또는 Java 21을 요구한다. JDK 11을 쓰는 Spark, Flink, Trino 클러스터라면 반드시 JDK 업그레이드 계획을 먼저 세워야 한다.

신규 엔진 지원:

Spark 3.x나 Flink 1.x를 사용하는 기존 클러스터는 엔진 업그레이드 없이 Iceberg 1.11.0 커넥터를 그대로 쓸 수 없다. Iceberg 1.11.0이 지원하는 Spark와 Flink 버전 매트릭스를 릴리스 노트에서 확인한다.


V3 테이블 마이그레이션 고려사항

즉시 업그레이드 추천 조건
DELETE/UPDATE가 많아 positional delete file이 파편화되고 읽기 성능이 저하된 테이블.
반정형 JSON 데이터를 string으로 저장해 전체 파싱 비용이 큰 테이블.
Spark 4.1 또는 Flink 2.1로 이미 마이그레이션했거나 계획 중인 환경.
사전 확인 필수 항목
JDK 버전: 클러스터 전체가 Java 17+인지 확인한다. JDK 11은 더 이상 지원되지 않는다.
엔진 호환성: Spark 3.x/Flink 1.x는 Iceberg 1.11.0 커넥터를 바로 쓸 수 없다. 지원 매트릭스를 확인한다.
REST Catalog: server-side scan planning을 쓰려면 카탈로그 구현체가 /plan API를 지원하는지 확인한다.
KMS 연동: 테이블 암호화를 켜면 KMS 가용성이 테이블 읽기 SLA에 직접 포함된다.
마이그레이션을 미뤄야 하는 조건
Spark 3.x 또는 Flink 1.x를 유지해야 하는 계약 또는 기술 의존성이 있다.
Java 17로 업그레이드하지 못하는 레거시 JVM 의존 라이브러리가 있다.
V3로 업그레이드한 테이블은 V1/V2 엔진에서 읽을 수 없으므로 다운그레이드 경로가 없다.
운영 rollback 기준
V3 테이블을 rollback하려면 기존 V1/V2 snapshot으로 돌아가야 한다. 데이터 이전이 아닌 스냅샷 포인터 복구만으로 충분하다.
server-side planning 장애 시 기존 client-side manifest 탐색 방식으로 전환하는 엔진 옵션을 확인한다.
KMS 가용성 저하 시 암호화 테이블 접근 불가를 대비한 읽기 불가 처리 runbook을 작성한다.
Iceberg V3 업그레이드 판단표

1.11 업그레이드 체크리스트

테스트 환경에서 먼저 확인해야 할 사항:

  1. JDK 버전을 17 또는 21로 업그레이드하고 기존 워크로드가 정상 실행되는지 확인한다.
  2. Spark/Flink 버전과 Iceberg 1.11.0 커넥터 호환성 매트릭스를 확인한다.
  3. V3로 전환할 테이블을 선정하고, 읽기/쓰기 smoke test를 진행한다.
  4. deletion vector 기능 활성화 후 기존 positional delete file이 있는 테이블의 읽기 성능 변화를 측정한다.
  5. REST Catalog 구현체의 /plan API 지원 여부와 응답 latency를 확인한다.
  6. 암호화를 도입한다면 KMS 연동과 접근 권한을 검증한다.

점진적 마이그레이션 전략:

V1/V2 테이블과 V3 테이블은 같은 카탈로그에서 공존할 수 있다. 신규 테이블은 V3로 만들고 기존 테이블은 읽기 성능 문제가 실제로 발생한 경우에만 단계적으로 V3로 업그레이드한다.


정리

Apache Iceberg 1.11.0은 V3 table format을 프로덕션 준비 완료 상태로 만든 릴리스다.

삭제 벡터: data file 1개당 Roaring bitmap 하나로 삭제 이력을 압축 저장한다. V2의 positional delete file 파편화 문제를 해소하고 삭제가 많은 테이블의 읽기 overhead를 고정 비용으로 바꾼다.

서버 사이드 scan planning: 엔진이 object storage를 직접 탐색하는 대신 REST 카탈로그 서버에 /plan 요청을 보내고 FileScanTask를 받는다. 드라이버 메모리 압박과 API 호출 비용을 줄인다.

Variant 타입: 반정형 데이터를 이진 인코딩으로 저장해 predicate pushdown과 shredding 최적화를 가능하게 한다. JSON string 저장보다 쿼리 성능과 압축률이 높다.

세 기능 모두 V3 table에서만 사용 가능하다. V3 업그레이드 전에 Java 17 최소 요구사항엔진 호환성 매트릭스를 반드시 확인한다. V3로 업그레이드한 테이블은 V1/V2 엔진에서 읽을 수 없으므로 다운그레이드 경로를 미리 설계한다.

References