Parquet·ORC와 Snappy·Zlib로 분석 데이터 압축 설계하기
Parquet·ORC 컬럼형 포맷과 Snappy·Zlib 코덱의 구조, 성능 특성, Spark·Hive 운영 설정을 정리한다.
2026-08-14 · 최초 발행 2025-10-14
분석 쿼리의 병목은 저장 형식과 코덱 선택에서 갈린다
대규모 분석 워크로드에서는 저장 공간을 줄이면서도 쿼리 스캔을 빠르게 끝내야 한다. Parquet과 ORC는 컬럼별 인코딩과 압축을 적용하는 컬럼 지향 저장 포맷이며, 필요한 컬럼만 읽고 프레디케이트 푸시다운을 적용할 수 있다. Snappy와 Zlib은 이 포맷에 결합되는 범용 무손실 압축 알고리즘이다.
Snappy는 빠른 압축과 해제를 목표로 하고, Zlib은 높은 압축률을 우선한다. 결국 선택 기준은 I/O 바운드 쿼리의 스캔 바이트를 얼마나 줄일지, 그리고 CPU 압축 비용과 저장 비용 사이에서 어느 쪽을 더 중시할지에 있다.
Parquet과 ORC가 데이터를 건너뛰는 방식
Parquet은 Row Group, Column Chunk, Page로 구성된다. 최소·최대값과 NULL 카운트 같은 통계, 딕셔너리를 포함해 필요한 데이터 범위를 좁히는 데 사용한다.
ORC는 Stripe, Row Index, Bloom Filter 구조를 사용한다. 인덱스와 메타데이터가 풍부해 스킵 스캔 최적화에 유리하며, Hive ACID 거래 테이블과 결합하면 Delta와 Compaction 기반의 트랜잭션을 지원한다.
두 포맷 모두 스키마를 내장하고 컬럼 추가와 nullable 변경에 대한 하위 호환을 지원한다. 컬럼 단위 읽기, 프레디케이트 푸시다운, 딕셔너리·RLE·비트팩 인코딩을 함께 사용해 스캔 바이트를 줄인다.
Snappy와 Zlib의 비용 구조
Snappy는 수백 MB/sGB/s 수준의 빠른 압축·해제를 지향하며, 압축률은 대략 1.52.5배다. CPU 오버헤드가 낮아 실시간 또는 인터랙티브 쿼리에 적합하다.
Zlib은 압축과 해제가 더 느리고, 특히 해제는 개선되었으나 상대적으로 낮은 성능을 보인다. 대신 압축률은 대략 2.5~5배로 높다. 장기 보관이나 스토리지 비용을 우선하는 워크로드에서 선택할 수 있지만 CPU 오버헤드는 더 커진다.
Parquet과 ORC는 모두 Snappy와 Zlib을 지원한다. 엔진별 기본값은 다를 수 있으며 Spark-Parquet은 Snappy, Hive-ORC는 Zlib 경향이 있으나 버전별 차이가 존재한다.
포맷과 코덱 조합을 워크로드에 맞추기
| 조합 | 성능(스캔/해제) | 확장성(클러스터 효율) | 일관성/트랜잭션 | 안정성(오류/복구) | 운영 편의 |
|---|---|---|---|---|---|
| Parquet + Snappy | 대화형·ETL에 우수, 지연 최소 | CPU 여유 확보, 동시성 유리 | 파일 단위 원자 커밋(원자적 rename) | 코덱 부재 시 무손실 fallback 불가, 재시도 용이 | Spark/Trino 기본 친화 |
| Parquet + Zlib | 스토리지 절감 우수, 스캔 CPU 부담 | CPU 바운드 위험, 배치에 적합 | 동일 | 압축 해제 실패 시 태스크 재시도 필요 | 장기 보관·저비용 저장에 적합 |
| ORC + Snappy | 읽기 빠름, 벡터화+인덱스 시 강점 | 자원 효율 양호 | Hive ACID 미사용 시 Parquet과 유사 | Bloom Filter로 스킵스캔 안정 | Presto/Trino·Hive 혼합환경 적합 |
| ORC + Zlib | 최고 수준 압축률, 배치 리포트에 최적 | 높은 CPU 사용, 규모 확장 시 비용 상승 | Hive ACID와 결합 시 트랜잭션/락 지원 | Delta/Compaction로 정합성 강화 | 레거시 Hive 웨어하우스에 적합 |
압축률과 속도는 데이터 분포, 카디널리티, 엔진 버전에 따라 달라진다.
쓰기와 읽기에서 확인할 정합성 경로
프레디케이트 푸시다운은 통계와 인덱스를 바탕으로 Row Group 또는 Stripe를 건너뛰며 스캔 바이트를 줄인다. 벡터라이즈드 리더는 컬럼 벡터 단위로 디코딩과 연산을 수행해 CPU 캐시 효율을 높이고 JVM 오브젝트 할당을 줄인다.
코덱이 없는 환경에서는 런타임 예외가 발생한다. 클러스터 이미지에는 네이티브 라이브러리를 포함하고, 실패 시 재시도와 대체 저장소 경로 정책을 적용한다. 커밋 정합성은 HDFS/S3a의 원자적 rename 또는 Manifest 기반 커밋으로 다루며, Hive ACID는 Lock, Delta, Compaction으로 스냅샷 정합성을 보장한다.
파일 크기와 파티션 설계가 남기는 차이
파일 크기는 128~512MB를 목표로 하고, 소파일은 Compaction으로 병합한다. 고카디널리티 파티션은 메타데이터 오버헤드를 키우므로 균형이 필요하다.
시간 기반 파티션을 기본으로 두고 필요한 경우에만 고카디널리티 키를 추가한다. ORC에서는 Bloom Filter, Parquet에서는 통계를 활성화하고 최소·최대값이 누락되지 않는 설정을 검토한다.
워크로드별로 선택하는 저장 조합
인터랙티브 분석과 대시보드, 애드혹 쿼리에는 Parquet+Snappy가 맞는다. 해제 CPU 사용량이 낮고 필터 스캔이 빨라 사용자 체감 지연을 줄일 수 있다.
배치 리포팅과 장기 보관에는 ORC+Zlib 또는 Parquet+Zlib를 고려한다. 높은 압축률로 저장 비용을 낮추고, CPU 부담은 야간 배치로 흡수하는 방식이다.
Hive ACID 트랜잭션 테이블은 ORC가 적합하다. Delta와 Compaction, Lock 기반 일관성을 제공하며 Update, Delete, Merge를 지원한다. 여러 엔진에서 함께 쓰는 데이터 레이크 형식이라면 Spark, Trino/Presto, Flink, Pandas/Arrow와의 호환성이 넓은 Parquet이 기본 선택지가 될 수 있다.
Snappy 대비 Zlib을 사용하면 저장 비용을 2050% 추가 절감할 수 있으며, 데이터 특성에 따라 1060% 범위가 될 수 있다. 해제 CPU 병목 해소를 가정하면 동일 하드웨어에서 Snappy는 1.33.0배 빠른 응답이 가능하다. 컬럼 선택과 푸시다운을 적용하면 협소 선택·선별 쿼리 기준 스캔 바이트는 6095% 감소한다.
Spark와 Hive 설정에 반영하기
전제: Spark 3.4+, Hive 3.x, Hadoop 3.x, JDK 11
Spark DataFrame 저장:
# PySpark
df.write.mode("overwrite") \
.option("compression", "snappy") \
.parquet("s3a://bucket/path/parquet_snappy/")
spark.conf.set("spark.sql.parquet.compression.codec", "zstd") # 예: 다른 코덱
df.write.mode("append").format("orc") \
.option("orc.compress", "ZLIB") \
.save("hdfs:///warehouse/orc_zlib/")
Spark 읽기 최적화:
spark.conf.set("spark.sql.parquet.filterPushdown", "true")
spark.conf.set("spark.sql.orc.filterPushdown", "true")
spark.conf.set("spark.sql.inMemoryColumnarStorage.compressed", "true")
Hive 설정:
-- ORC 기본 압축을 ZLIB으로
SET hive.exec.orc.default.compress=ZLIB;
-- Vectorized Reader
SET hive.vectorized.execution.enabled=true;
SET hive.vectorized.execution.reduce.enabled=true;
-- ACID 테이블 예시
SET hive.txn.manager=org.apache.hadoop.hive.ql.lockmgr.DbTxnManager;
CREATE TABLE t_acid (id bigint, v string)
STORED AS ORC
TBLPROPERTIES ('transactional'='true');
런타임 이미지에는 libsnappy와 zlib 네이티브 라이브러리를 포함한다. S3와 오브젝트 스토리지를 사용할 때는 Manifest 또는 Direct committer 같은 커밋터 유형을 검토해 원자성을 확보한다. 스키마 진화는 하위 호환 가능한 추가를 중심으로 관리하고, 스냅샷별 메타데이터 버전도 함께 관리한다.