JSONL vs Parquet: 적합한 데이터 형식 선택하기
JSONL(JSON Lines)과 Apache Parquet의 종합 비교입니다. 압축, 쿼리 성능, 스키마 적용, 생태계 지원에서의 트레이드오프를 이해하고 데이터 워크로드에 적합한 형식을 선택하세요.
최종 업데이트: 2026년 2월
JSONL이란?
JSONL(JSON Lines)은 각 줄이 개행 문자로 구분된 단일, 독립된 JSON 객체를 포함하는 텍스트 기반 데이터 형식입니다. 보편적인 JSON 형식의 자연스러운 확장으로, 스트리밍 및 로그 스타일 데이터를 위해 특별히 설계되었습니다. 모든 줄이 독립적인 JSON 문서이므로 기존 데이터를 다시 쓰지 않고 파일에 추가할 수 있으며, 최소한의 메모리 오버헤드로 줄 단위로 처리할 수 있습니다.
JSONL은 머신러닝 학습 데이터(OpenAI 파인튜닝, Hugging Face 데이터셋), 애플리케이션 로그, 이벤트 스트림, 데이터가 점진적으로 도착하는 모든 시나리오의 표준 교환 형식이 되었습니다. 사람이 읽을 수 있는 특성 덕분에 텍스트 편집기나 grep, head, jq와 같은 명령줄 도구로 쉽게 검사할 수 있습니다.
{"id": 1, "name": "Alice", "role": "engineer", "salary": 95000}{"id": 2, "name": "Bob", "role": "designer", "salary": 88000}{"id": 3, "name": "Charlie", "role": "manager", "salary": 105000}
Parquet란?
Apache Parquet는 대규모 데이터셋에서 효율적인 분석 쿼리를 위해 설계된 컬럼 기반 바이너리 저장 형식입니다. JSONL처럼 행 단위로 데이터를 저장하는 대신, Parquet는 컬럼별로 값을 구성합니다. 이는 수백만 행에서 단일 필드를 읽을 때 모든 완전한 레코드가 아닌 관련 컬럼만 스캔하면 됨을 의미합니다. 이 컬럼 레이아웃은 컬럼 내의 값이 타입과 분포에서 유사한 경향이 있으므로 공격적인 압축을 가능하게 합니다.
Parquet는 Apache Hadoop 생태계 내에서 만들어졌으며, 현재 AWS S3, Google Cloud Storage, Azure Blob Storage에 구축된 데이터 레이크의 사실상 저장 형식입니다. Apache Spark, Apache Hive, Presto, DuckDB, Snowflake, BigQuery, 그리고 사실상 모든 현대 분석 엔진과 깊이 통합되어 있습니다. Parquet 파일은 메타데이터에 엄격한 스키마를 내장하므로 소비자는 외부 문서 없이도 항상 데이터의 정확한 타입과 구조를 알 수 있습니다.
import pyarrow.parquet as pqimport pandas as pd# Write a DataFrame to Parquetdf = pd.DataFrame({'id': [1, 2, 3],'name': ['Alice', 'Bob', 'Charlie'],'role': ['engineer', 'designer', 'manager'],'salary': [95000, 88000, 105000]})df.to_parquet('employees.parquet')# Read specific columns (columnar advantage)df = pq.read_table('employees.parquet', columns=['name', 'salary']).to_pandas()
JSONL vs Parquet: 나란히 비교
다음 표는 프로젝트의 데이터 형식을 선택할 때 가장 중요한 차원에서 JSONL과 Parquet의 주요 차이점을 요약합니다.
| 특성 | JSONL | Parquet |
|---|---|---|
| 데이터 레이아웃 | 행 지향, 텍스트 기반. 각 줄은 완전한 JSON 객체. | 컬럼 지향, 바이너리. 값이 로우 그룹과 함께 컬럼별로 저장. |
| 인코딩 | UTF-8 일반 텍스트. 사람이 읽을 수 있고, 모든 텍스트 편집기에서 편집 가능. | 딕셔너리, RLE, 비트 패킹 인코딩이 포함된 바이너리. 사람이 읽을 수 없음. |
| 압축 | 선택적 외부 압축(gzip, zstd). 필드 이름이 매 행마다 반복. | 내장 컬럼 압축(Snappy, Zstd, Gzip). 2-10배 더 작은 파일. |
| 쿼리 성능 | 모든 쿼리에 전체 파일 스캔 필요. 컬럼 프루닝이나 프레디케이트 푸시다운 없음. | 컬럼 프루닝과 프레디케이트 푸시다운으로 관련 없는 데이터를 건너뜀. 분석 쿼리에 수십 배 더 빠름. |
| 스키마 | 스키마 프리. 각 줄이 다른 필드와 타입을 가질 수 있음. 유연하지만 오류 발생 가능. | 파일 메타데이터에 내장된 엄격한 타입 스키마. 읽기와 쓰기 시 적용. |
| 스트리밍 / 추가 | 우수함. 파일 끝에 새 줄을 추가. 실시간 수집에 이상적. | 부족함. 데이터를 추가하려면 다시 쓰거나 새 파일 파티션을 생성해야 함. |
| 사람이 읽을 수 있음 | 네. cat, head, grep, jq 또는 모든 텍스트 편집기로 검사 가능. | 아니오. 검사하려면 전문 도구(parquet-tools, PyArrow, DuckDB)가 필요. |
| 생태계 | 보편적. JSON 파서가 있는 모든 프로그래밍 언어에서 지원. | 분석 중심. Spark, Hive, Presto, DuckDB, Snowflake, BigQuery와 깊은 통합. |
성능 벤치마크
JSONL과 Parquet 사이의 성능 격차는 규모에서 극적으로 벌어집니다. 아래는 20개 컬럼(문자열, 정수, 부동소수점, 타임스탬프 혼합)의 1천만 행 데이터셋에 대한 대표적인 벤치마크입니다.
파일 크기 (압축)
전체 테이블 스캔
쓰기 속도
단일 컬럼 쿼리
벤치마크는 16 GB RAM을 갖춘 M2 MacBook Pro에서 Python(pandas + PyArrow)으로 측정되었습니다. 실제 결과는 하드웨어, 데이터 분포, 압축 코덱에 따라 다릅니다.
JSONL vs Parquet 사용 시기
- 실시간 로그 수집 및 이벤트 스트리밍
- OpenAI, Anthropic, Hugging Face를 위한 ML 학습 데이터
- 마이크로서비스와 API 간의 데이터 교환
- 레코드별로 스키마가 다른 반정형 데이터
- 사람이 읽을 수 있는 것이 중요한 빠른 프로토타이핑과 디버깅
- 레코드가 지속적으로 도착하는 추가 전용 데이터
- 분석 쿼리가 필요 없는 소규모에서 중규모 데이터셋(1 GB 미만)
- S3, GCS 또는 Azure Blob의 데이터 레이크 저장소
- Spark, Presto, DuckDB 또는 Snowflake을 사용한 분석 쿼리
- 수십억 행에 대한 컬럼 집계(SUM, AVG, COUNT)
- 엄격한 스키마 적용 및 데이터 거버넌스 요구 사항
- 저장 비용이 중요한 장기 보관(2-10배 더 작은 파일)
- 특정 컬럼을 읽는 피처 스토어 및 ML 피처 파이프라인
- 쿼리 성능이 중요한 1 GB 이상의 데이터셋
하이브리드 아키텍처: JSONL 수집, Parquet 저장
프로덕션 데이터 플랫폼에서 JSONL과 Parquet는 상호 배타적이지 않습니다. 일반적이고 효과적인 패턴은 데이터 수집에 JSONL을, 장기 저장 및 분석에 Parquet를 사용하는 것입니다. 이 하이브리드 접근 방식은 두 형식의 장점을 결합합니다: 실시간 데이터 캡처를 위한 JSONL의 단순성과 다운스트림 쿼리를 위한 Parquet의 효율성.
파이프라인은 세 단계로 작동합니다. 첫째, JSONL이 빠르고 잠금 없는 추가를 지원하므로 원시 이벤트나 레코드가 도착하는 대로 JSONL 파일에 추가됩니다. 둘째, 주기적 배치 작업(매시간, 매일 또는 파일 크기에 따라 트리거)이 축적된 JSONL 파일을 읽고, 데이터를 검증하고 변환하며, Parquet 형식으로 변환합니다. 셋째, 결과 Parquet 파일은 효율적인 쿼리를 위해 날짜, 지역 또는 기타 차원으로 파티션된 데이터 레이크에 저장됩니다.
1. JSONL로 수집
원시 이벤트, 로그, API 응답을 JSONL 파일로 수집합니다. 빠른 추가, 스키마 불필요, 실시간 디버깅이 용이합니다.
2. 변환 & 검증
주기적으로 JSONL 배치를 읽고, 스키마 검증을 적용하고, 데이터를 정리 및 정규화하고, 잘못된 형식의 레코드를 처리합니다.
3. Parquet로 저장
검증된 데이터를 파티션된 Parquet 파일로 데이터 레이크에 씁니다. Spark, DuckDB 또는 모든 분석 엔진으로 쿼리합니다.
import jsonimport pandas as pdimport pyarrow as paimport pyarrow.parquet as pqfrom pathlib import Pathfrom datetime import datetimedef jsonl_to_parquet(jsonl_dir: str, parquet_dir: str):"""Convert accumulated JSONL files to partitioned Parquet."""records = []for jsonl_file in Path(jsonl_dir).glob('*.jsonl'):with open(jsonl_file, 'r') as f:for line in f:line = line.strip()if line:records.append(json.loads(line))if not records:returndf = pd.DataFrame(records)# Add partition columndf['date'] = datetime.now().strftime('%Y-%m-%d')table = pa.Table.from_pandas(df)pq.write_to_dataset(table,root_path=parquet_dir,partition_cols=['date'],compression='zstd')print(f'Converted {len(records)} records to Parquet')jsonl_to_parquet('raw_events/', 'data_lake/')
무료 JSONL 도구 사용해 보기
JSONL 파일로 작업하고 계신가요? 무료 브라우저 기반 도구로 JSONL 데이터를 즉시 보고, 검증하고, 변환하세요. 설치나 업로드가 필요 없습니다.