Post

[Modern Table Format] Day 2: Apache Paimon - 스트리밍 처리에 특화된 LSM-tree 기반 테이블 포맷

[Modern Table Format] Day 2: Apache Paimon - 스트리밍 처리에 특화된 LSM-tree 기반 테이블 포맷

서론: 스트리밍 업데이트는 Iceberg의 약한 고리였다

분석 쿼리 중심에서는 Iceberg가 매우 강력하다. 하지만 초당 수천 건의 upsert/delete가 들어오면, file rewrite 기반 모델은 빠르게 비싸진다.

Paimon은 여기서 출발한다.

  • 쓰기 경로: LSM-tree 스타일로 append + compaction
  • 읽기 경로: merge-on-read 기본
  • 엔진 결합: Flink 스트리밍과 높은 결합도

즉, Paimon은 “쿼리 엔진 친화적 포맷”보다 “지속적 변경 데이터 친화적 포맷”에 가깝다.

1. Paimon 내부 구조: Sorted Run + Leveling

Paimon 테이블은 key 기준 정렬된 파일 묶음(run)을 레벨별로 관리한다.

1
2
3
L0: run-a, run-b, run-c        # 최근 flush, 중복 키 많음
L1: run-d, run-e               # 부분 병합
L2: run-f                      # 큰 정리 구간

1.1 쓰기 경로

  1. 스트림 레코드 수신 (insert/update/delete)
  2. 메모리 버퍼 정렬
  3. flush 시 새 run 파일 생성 (주로 L0)
  4. 백그라운드 compaction으로 상위 레벨 병합

이 구조 덕분에 writer는 큰 파일 재작성 없이 지속 ingest를 유지한다.

2. Primary Key 테이블의 의미

Paimon의 핵심 가치는 Primary Key table에서 드러난다.

1
2
3
4
5
6
7
8
9
10
11
12
CREATE TABLE ods_order (
  order_id BIGINT,
  user_id BIGINT,
  amount DECIMAL(18,2),
  status STRING,
  ts TIMESTAMP(3),
  PRIMARY KEY (order_id) NOT ENFORCED
) WITH (
  'bucket' = '16',
  'changelog-producer' = 'input',
  'merge-engine' = 'deduplicate'
);

NOT ENFORCED는 DB 제약 강제가 아니라, 스토리지 merge semantics의 키로 쓰인다는 의미다.

2.1 merge-engine 선택

merge-engine동작적합한 데이터
deduplicate최신 레코드 1건 유지CDC upsert
partial-update컬럼 단위 병합sparse update
aggregationkey별 집계실시간 metric

엔진 선택이 곧 데이터 정확도 모델을 결정한다.

3. Write Amplification: 어디서 줄고 어디서 늘어나는가

Paimon은 즉시 rewrite를 피하므로 단기 write 비용은 낮다. 대신 compaction 단계에서 비용을 후불로 낸다.

1
2
WA_ingest  < Iceberg(빈번한 rewrite)
WA_compact > Iceberg(배치 append only)

3.1 관측 포인트

  • L0 파일 수가 빠르게 증가하면 read amplification이 급상승
  • compaction backlog가 쌓이면 지연과 비용이 함께 증가
  • bucket 설계가 틀리면 hot partition이 생겨 특정 task만 과부하

운영에서는 “쓰기 성능”보다 compaction debt를 먼저 본다.

4. Flink와 결합한 실전 파이프라인

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
-- CDC 소스
CREATE TABLE cdc_orders (
  order_id BIGINT,
  user_id BIGINT,
  amount DECIMAL(18,2),
  status STRING,
  ts TIMESTAMP(3),
  PRIMARY KEY (order_id) NOT ENFORCED
) WITH (
  'connector' = 'mysql-cdc',
  'hostname' = 'mysql',
  'database-name' = 'shop',
  'table-name' = 'orders'
);

-- Paimon 싱크
INSERT INTO ods_order
SELECT * FROM cdc_orders;

이 구성의 장점은 CDC를 별도 merge job 없이 바로 lakehouse 테이블 상태로 유지할 수 있다는 점이다.

5. Iceberg와의 기술적 경계

항목IcebergPaimon
핵심 강점배치/분석 안정성스트리밍 upsert/delete
메타데이터 모델snapshot + manifestLSM run + compaction
write pathappend + commitflush + level compaction
read cost 특성planning 중심merge-on-read 중심
엔진 친화성Spark/Trino 범용Flink 최적화

정리하면, Paimon은 “분석 파일 포맷”이라기보다 “스트리밍 상태 테이블”에 더 가깝다.

다음 단계

Day 3에서는 Iceberg와 Paimon 모두에서 중요한 공통 주제인 삭제 처리를 다룬다. 특히 Deletion VectorMerge-on-Read가 쓰기 증폭을 어떻게 줄이는지 수식과 함께 분석한다.


This post is licensed under CC BY 4.0 by the author.