본문 바로가기
빅데이터(Big Data)

실시간 업데이트가 가능한 데이터 레이크하우스의 표준, Apache Hudi 분석

by forward error correction Circle 2026. 5. 13.
반응형

Ⅰ. Apache Hudi 기술이란?

 전통적인 데이터 레이크(HDFS, S3 등 객체 스토리지)는 Parquet, ORC와 같은 컬럼형 파일을 단순히 쌓아두는 구조로 설계되었습니다.
이러한 구조는 대규모 배치 분석에는 강하지만, 다음과 같은 명확한 한계를 가지고 있습니다.

 ⅰ. Update / Delete 의 어려움 → 한 건의 행을 수정하려면 파일 전체를 다시 써야 함 (Immutable File System)
 ⅱ. 실시간성 부재 → 변경 데이터(CDC)를 반영하려면 매번 전체 테이블을 재작성해야 함
 ⅲ. 트랜잭션 부재 → 동시에 쓰기/읽기가 일어나면 데이터 정합성을 보장할 수 없음
 ⅳ. 작은 파일 문제(Small File Problem) → 스트리밍 적재 시 수많은 작은 파일이 생성되어 쿼리 성능 저하
 ⅴ. 증분 처리 불가 → "어제 이후 변경된 데이터만" 가져오려면 별도의 타임스탬프 컬럼과 복잡한 쿼리가 필요

 Apache Hudi(Hadoop Upserts Deletes and Incrementals)는 Uber에서 2016년 개발하여 2019년 Apache 최상위 프로젝트로 승격된 오픈 데이터 레이크하우스 플랫폼입니다.
S3, HDFS, GCS 등 기존 객체 스토리지 위에서 ACID 트랜잭션, Upsert/Delete, 증분 쿼리, 시간 여행(Time Travel), 스키마 진화를 지원하여, 데이터 레이크를 데이터 웨어하우스처럼 다룰 수 있게 해주는 기술입니다.

Ⅱ. Apache Hudi 기술 특징

구분 설명
ACID 트랜잭션 MVCC(Multi-Version Concurrency Control) 기반으로 동시 쓰기/읽기 환경에서도 데이터 일관성을 보장합니다.
Upsert / Delete Primary Key 기준으로 행 단위 업데이트와 삭제가 가능합니다. CDC(Change Data Capture) 적재에 최적화되어 있습니다.
증분 쿼리(Incremental Query) "특정 커밋 이후 변경된 데이터만" 가져올 수 있어, ETL 파이프라인의 비용과 지연시간을 획기적으로 줄입니다.
Time Travel 과거 시점의 테이블 상태를 그대로 조회 가능. 감사(Audit), 디버깅, 머신러닝 재현성 확보에 활용됩니다.
스키마 진화 컬럼 추가/이름 변경/타입 변경을 기존 데이터 재작성 없이 지원합니다.
자동 파일 관리 Compaction, Clustering, Cleaning을 통해 작은 파일 문제를 자동으로 해결하여 쿼리 성능을 유지합니다.
다중 엔진 호환 Spark, Flink, Presto, Trino, Hive, Athena, Redshift Spectrum 등 거의 모든 분석 엔진과 연동됩니다.


Ⅲ. Apache Hudi 기술 동작방식

 Hudi는 객체 스토리지 위에 "테이블"이라는 논리적 단위를 만들고, 그 안에 데이터 파일과 메타데이터(Timeline)를 함께 관리합니다.

 ⅰ. 핵심 구성 요소

구성 요소 역할
Timeline 테이블에 일어난 모든 작업(Commit, Clean, Compaction, Rollback 등)을 시간 순으로 기록한 메타데이터 로그. .hoodie/ 디렉터리에 저장됩니다.
File Group / File Slice 데이터를 저장하는 물리 단위. 하나의 파티션은 여러 File Group으로 나뉘고, 각 File Group은 시간 순으로 여러 File Slice를 가집니다.
Index 레코드 키 → File Group 매핑을 빠르게 찾기 위한 인덱스. Bloom, Simple, HBase, Bucket, Record-Level Index를 지원합니다.
Base File 컬럼형 형식(Parquet/ORC)으로 저장된 본 데이터 파일.
Log File 행 단위 변경분(Delta)을 Avro 형식으로 빠르게 추가 기록하는 파일. MoR 테이블에서만 사용됩니다.
Table Service Compaction, Clustering, Cleaning, Archival 등 백그라운드 자동 최적화 작업.


 ⅱ. 데이터 흐름

  1) Writer가 새로운 레코드를 보냄(Insert/Update/Delete)
  2) Index를 통해 해당 레코드 키가 속한 File Group을 식별
  3) 테이블 타입(CoW/MoR)에 따라 Base File을 다시 쓰거나 Log File에 추가
  4) Timeline에 새로운 Commit 인스턴트(instant)를 기록
  5) Reader는 Timeline을 보고 가장 최신 일관된 스냅샷을 조회

Ⅳ. Apache Hudi 기술 구성 및 흐름도

 Hudi의 가장 중요한 설계 결정은 테이블 타입(Table Type)입니다. 동일한 데이터라도 어떤 타입을 선택하느냐에 따라 쓰기/읽기 트레이드오프가 완전히 달라집니다.

구분 Copy on Write (CoW) Merge on Read (MoR)
저장 방식 변경 발생 시 Parquet 파일을 전체 재작성 변경분은 Avro Log File에 추가, Base File은 그대로 유지
쓰기 비용 높음 (파일 전체 재작성) 낮음 (append-only)
읽기 비용 낮음 (Parquet 직접 스캔) 높음 (Base + Log Merge 필요)
적재 지연 분 단위 초 단위 (실시간)
적합 워크로드 읽기 빈도 > 쓰기 빈도 (BI, 대시보드) 쓰기 빈도 > 읽기 빈도 (CDC, IoT 스트리밍)


 [ 단계별 처리 흐름 (MoR 기준) ]

단계 처리 내용 세부 설명
1) Ingest Kafka/CDC 소스에서 변경 이벤트 수신 DeltaStreamer 또는 Spark/Flink Structured Streaming Job이 마이크로 배치로 데이터를 끌어옵니다.
2) Tag Index 조회로 레코드 위치 식별 레코드 키가 기존 어떤 File Group에 있는지 인덱스로 찾아 Insert/Update를 분리합니다.
3) Write Log File에 변경분 append Base Parquet은 건드리지 않고, 행 기반 Avro Log에 변경분을 빠르게 기록합니다.
4) Commit Timeline에 deltacommit 기록 Atomic하게 인스턴트(instant)를 추가하여, 이 시점부터 Reader가 새 데이터를 볼 수 있습니다.
5) Compaction Log + Base를 Parquet으로 병합 백그라운드에서 주기적으로 수행. 읽기 성능이 떨어지기 전에 자동 최적화합니다.
6) Clean 오래된 파일 정리 설정된 보존 정책(commits/hours)을 넘긴 구버전 파일을 삭제하여 스토리지 비용을 관리합니다.
7) Read Snapshot / Incremental / Read-Optimized 쿼리 종류에 따라 (1)최신 병합 결과, (2)특정 커밋 이후 변경분, (3)Base Parquet만 빠르게 조회 중 선택합니다.

Ⅴ. Apache Hudi 기술 설치 방법

 Hudi는 자체 데몬을 띄우는 방식이 아니라, Spark / Flink 등 컴퓨트 엔진에 라이브러리(JAR)로 탑재되는 형태입니다. 별도의 Hudi 서버를 설치할 필요는 없습니다.

 ⅰ. Spark 환경에서 Hudi 사용 (가장 일반적)

# Spark 3.5 + Hudi 0.15 기준 (Scala 2.12)
spark-shell \
  --packages org.apache.hudi:hudi-spark3.5-bundle_2.12:0.15.0 \
  --conf 'spark.serializer=org.apache.spark.serializer.KryoSerializer' \
  --conf 'spark.sql.catalog.spark_catalog=org.apache.spark.sql.hudi.catalog.HoodieCatalog' \
  --conf 'spark.sql.extensions=org.apache.spark.sql.hudi.HoodieSparkSessionExtension'

 ⅱ. Flink 환경에서 Hudi 사용

# Flink 1.18 lib 디렉터리에 번들 JAR 배치
wget https://repo1.maven.org/maven2/org/apache/hudi/hudi-flink1.18-bundle/0.15.0/hudi-flink1.18-bundle-0.15.0.jar \
  -O $FLINK_HOME/lib/hudi-flink1.18-bundle-0.15.0.jar

 ⅲ. Python(PySpark) 환경

pip install pyspark==3.5.0
# 실행 시 패키지를 함께 지정
pyspark --packages org.apache.hudi:hudi-spark3.5-bundle_2.12:0.15.0

 ⅳ. 클라우드 매니지드 옵션
   - AWS EMR / Glue : Hudi가 기본 탑재되어 있어 별도 설치 불필요
   - Databricks : 자체 OSS Spark 런타임에서 Hudi 사용 가능
   - GCP Dataproc : 초기화 액션으로 Hudi 패키지 자동 설치 가능

Ⅵ. Apache Hudi 기술 사용 방법

 ⅰ. PySpark로 Hudi 테이블 생성 & Upsert

from pyspark.sql import SparkSession

spark = SparkSession.builder.appName("hudi-demo").getOrCreate()

hudi_options = {
    'hoodie.table.name': 'orders',
    'hoodie.datasource.write.recordkey.field': 'order_id',
    'hoodie.datasource.write.partitionpath.field': 'order_date',
    'hoodie.datasource.write.precombine.field': 'updated_at',
    'hoodie.datasource.write.operation': 'upsert',
    'hoodie.datasource.write.table.type': 'MERGE_ON_READ',
    'hoodie.upsert.shuffle.parallelism': 4,
    'hoodie.insert.shuffle.parallelism': 4,
}

# 최초 적재
df.write.format("hudi") \
    .options(**hudi_options) \
    .mode("overwrite") \
    .save("s3://my-lake/orders/")

# 변경분 Upsert
delta_df.write.format("hudi") \
    .options(**hudi_options) \
    .mode("append") \
    .save("s3://my-lake/orders/")

 ⅱ. Spark SQL로 사용 (DDL/DML)

CREATE TABLE orders (
    order_id   STRING,
    customer   STRING,
    amount     DECIMAL(18,2),
    updated_at TIMESTAMP,
    order_date STRING
) USING hudi
TBLPROPERTIES (
    type = 'mor',
    primaryKey = 'order_id',
    preCombineField = 'updated_at'
)
PARTITIONED BY (order_date);

MERGE INTO orders t
USING staging_orders s
ON t.order_id = s.order_id
WHEN MATCHED THEN UPDATE SET *
WHEN NOT MATCHED THEN INSERT *;

 ⅲ. 증분 쿼리 / 시간 여행

# 특정 커밋 이후 변경된 데이터만 조회 (Incremental)
spark.read.format("hudi") \
    .option("hoodie.datasource.query.type", "incremental") \
    .option("hoodie.datasource.read.begin.instanttime", "20260420090000") \
    .load("s3://my-lake/orders/").show()

# 특정 시점의 스냅샷 조회 (Time Travel)
SELECT * FROM orders TIMESTAMP AS OF '2026-04-20 09:00:00';

 ⅳ. 운영 시 고려사항

항목 권장 사항
Record Key 설계 카디널리티가 높고 불변인 컬럼을 선택해야 합니다. 비즈니스 키와 결합하지 마세요.
파티션 키 설계 날짜 기반(연/월/일)이 일반적이나, 너무 잘게 나누면 작은 파일이 폭증합니다.
Index 선택 대용량 + 랜덤 키 → Bucket Index, 범위 검색 → Bloom, 0.14+ → Record-Level Index 권장
Compaction 전략 MoR은 inline 또는 async 중 선택. 실시간성이 중요하면 async + 별도 컴팩션 잡으로 분리하세요.
Cleaning 정책 Time Travel 요구 기간만큼만 보존하여 스토리지 비용을 관리합니다 (기본 10 commits 보존).
Hive Sync Glue/Hive Metastore와 자동 동기화하여 Athena, Trino, Presto에서 즉시 쿼리 가능하도록 설정합니다.
모니터링 Hudi Metrics를 Prometheus/Grafana로 노출하고, Timeline 누적 크기와 Compaction 지연을 핵심 지표로 둡니다.

Ⅶ. Apache Hudi 자주 쓰는 명령어 / 사례

 Hudi는 운영 편의를 위해 hudi-cli라는 인터랙티브 셸과 Spark 기반 유틸리티 잡(HoodieDeltaStreamer)을 제공합니다.

 ⅰ. hudi-cli 자주 쓰는 명령

명령어 용도
connect --path s3://my-lake/orders/ Hudi 테이블에 접속
commits show Timeline의 모든 커밋 이력 조회
stats filesizes 파일 크기 분포 확인 (작은 파일 문제 진단)
compactions show all 예약/완료된 Compaction 작업 확인
compaction schedule 새로운 Compaction 작업 예약
compaction run --compactionInstant {ts} 예약된 Compaction 실행
cleans run 오래된 파일 정리(Clean) 수동 실행
commit rollback --commit {ts} 잘못된 커밋을 안전하게 롤백
savepoint create --commit {ts} 중요 시점을 보존하여 Cleaner가 지우지 못하게 보호


 ⅱ. HoodieDeltaStreamer 활용 사례 (Kafka → S3 CDC 적재)

spark-submit \
  --class org.apache.hudi.utilities.streamer.HoodieStreamer \
  --packages org.apache.hudi:hudi-utilities-bundle_2.12:0.15.0 \
  --master yarn --deploy-mode cluster \
  /path/to/hudi-utilities-bundle.jar \
  --table-type MERGE_ON_READ \
  --source-class org.apache.hudi.utilities.sources.DebeziumSource \
  --target-base-path s3://my-lake/orders/ \
  --target-table orders \
  --op UPSERT \
  --continuous \
  --min-sync-interval-seconds 30

 ⅲ. 실제 활용 사례
   - Uber : 수백 PB의 데이터 레이크를 Hudi로 운영, 30분 → 분 단위로 데이터 신선도 향상
   - Walmart : 매장 재고/주문 CDC를 실시간으로 분석 레이크에 반영
   - Robinhood : 거래 데이터를 분 단위로 적재하여 리스크 분석에 활용
   - ByteDance : 추천 모델용 Feature Store 백엔드로 사용

Ⅷ. Apache Hudi 기술 활용방안

 ⅰ. 대안 기술 비교 (Lakehouse Format Trinity)

구분 Apache Hudi Apache Iceberg Delta Lake
최초 개발 Uber (2016) Netflix (2018) Databricks (2019)
핵심 강점 Upsert/CDC 실시간 적재, Record-Level Index 대규모 스키마/파티션 진화, 멀티엔진 중립성 Spark/Databricks 생태계 통합, 단순함
테이블 타입 CoW / MoR 선택 가능 CoW (MoR은 v3에서 도입 중) CoW (Deletion Vector로 보완)
실시간 적재 최우선 설계 목표 (초~분) 분~시간 단위 분 단위
증분 쿼리 기본 지원 (Incremental Pull) CDF로 부분 지원 CDF 지원
주된 사용처 CDC, IoT, 스트리밍 적재 대형 분석 테이블, 멀티엔진 환경 Databricks 중심 데이터 플랫폼


 ⅱ. Hudi가 적합한 시나리오
   1) 운영 DB → 분석 레이크로의 실시간 CDC 미러링 (Debezium + Kafka + Hudi MoR)
   2) GDPR/CCPA 대응 — 특정 사용자 데이터의 행 단위 삭제(Right to be Forgotten)
   3) IoT/이벤트 데이터의 Late Arriving Data 처리 (지연 도착 이벤트 정합성 보정)
   4) 머신러닝용 Feature Store의 백엔드 (시간 여행으로 학습/서빙 시점 일치)
   5) Slowly Changing Dimension(SCD Type 2) 패턴 구현

 ⅲ. 언제 Hudi를 쓰면 안 되는가

상황 이유 / 더 나은 대안
단순 Append-only 로그 적재 Upsert 인덱스 오버헤드만 발생. 그냥 Parquet + Glue Crawler로 충분합니다.
초저지연(밀리초) OLTP Hudi는 분석용 Lakehouse입니다. PostgreSQL, MySQL 등 OLTP DB가 적합합니다.
초고속 OLAP 대시보드 읽기 응답 50ms 이하가 필요하다면 ClickHouse, Apache Doris, StarRocks가 더 나은 선택입니다.
파일 수가 적고 변경이 거의 없는 정적 데이터셋 메타데이터/Timeline 관리 비용만 늘어납니다. 단순 Parquet 테이블이 적합합니다.
멀티엔진 표준화가 최우선이고 실시간성은 부차적 Apache Iceberg가 더 넓은 엔진 호환성과 단순한 메타데이터 모델을 제공합니다.
Databricks를 전면적으로 사용 Delta Lake가 Databricks 런타임 최적화 측면에서 가장 자연스럽습니다.


 [ 핵심 요약 ]
 Apache Hudi는 "데이터 레이크에서도 트랜잭션과 실시간 업데이트가 필요하다"는 문제를 정면으로 해결한 기술입니다.
특히 Upsert/Delete가 빈번한 CDC 워크로드에서 Iceberg, Delta Lake보다 명확한 우위를 가지며, CoW와 MoR이라는 두 개의 테이블 타입을 통해 읽기/쓰기 성능 트레이드오프를 워크로드에 맞게 조절할 수 있는 유연성이 가장 큰 강점입니다.
다만, 단순 분석용 정적 테이블이나 초저지연 OLAP 환경에서는 오히려 오버스펙이 될 수 있으므로, "이 데이터는 정말 행 단위로 변경되는가?"라는 질문에 Yes일 때 도입하는 것이 가장 합리적인 선택입니다.

반응형