Hive Json Serde의 한계 - Parquet/ORC 포맷

최근 백만건 단위의 데이터를 처리하는 상황을 맞이하면서, 단순한 조건이 포함된 조회부터 성능이 안나오며, 분석 쿼리 조회 시에는 몇분 이상 기다려야하는 상황이 잦았다.

단순히 데이터의 양이 많아져서 발생하는 문제일 수 있지만, 빅 데이터 처리 솔루션들이 천만건 데이터 수준에 지연이 발생하는 건 기술의 문제가 아니라 유즈 케이스가 잘못된 경우 것이라 생각된다. 
해당 포스팅에선 기존 환경의 문제점을 확인하며 개선할 수 있는지에 대해 확인해보려 한다.


기존 환경

  • AWS EMR 환경에서 Hive Metastore를 중심으로 S3에 저장된 데이터를 Hive, Trino, Spark에서 조회/처리
  • Raw Layer 데이터는 모두 `json.gz` 형식으로 저장되어 있으며, JSON Serde를 활용한 External Table 사용
  • Raw Table들은 단일 파티션 테이블이지만, 분석 시 주로 다른 칼럼들을 사용

예시 쿼리:

select *
from 테이블스키마.테이블명
where 1=1
	and "파티션 칼럼" >= '이번달'
	and "분석용 칼럼" = 'typeA'

팀 내부에서는 RAW 데이터 형식(JSON.gz)을 바꾸기 어렵기 때문에, JSON 파일을 직접 읽는 환경을 유지해야 하는 상황이었다. (데이터 저장 형식이 외부 팀에서 관리)

https://docs.aws.amazon.com/ko_kr/athena/latest/ug/hive-json-serde.html

RAW 테이블 DDL이 딱 위와 같다.

 


JSON의 제약

RAW 테이블에서 성능 저하의 가장 큰 문제점은 JsonSerde를 사용하는 것이다.

 

구체적인 원인은 Json Serde의 동작 방식에서 확인할 수 있다. 

JSON Serde는 JSON 객체를 Hive 테이블 칼럼으로 파싱해 주기 때문에 별도의 전처리 없이 조회 가능할 수 있는 장점을 갖는다. (gzip 압축도 알아서 풀어준다.)

위의 장점과 함께 오는 단점으로, Json Serde를 사용하면 모든 Json 데이터를 파싱하여 테이블 구조로 변환하는 과정이 필수적이다. 이 과정은 CPU 사용량이 많고, 데이터의 개수가 많아질수록 배가 된다.

또한, 칼럼 기반 포맷(Parquet, ORC)과 달리 칼럼 선택 여부와 상관 없이 전체 JSON 레코드를 파싱해야 하므로 I/O와 처리 시간이 칼럼 선택과 상관 없이 많이 소요된다.

 

즉, 파티션 칼럼 외의 칼럼을 기준으로 조회할 경우, 매번 모든 JSON 파일을 스캔하고 스키마 변환 과정이 필요하여 데이터의 양이 많아질 경우 조회 성능이 저하될 수 밖에 없다.

추가로, 데이터 저장 용량에 대한 단점도 존재하는데, Json 파일을 gzip으로 압축하더라도 파일의 크기는 columnar compression을 지원하는 Parquet/ORC보다 상대적으로 커진다.
또한, Json gzip 압축은 파일 자체를 압축하는 방식(row-based)이므로, 후술할 Parquet/ORC의 압축 방식과 대비된다.

따라서, 데이터의 볼륨이 커지는 상황에서는 Json 형식이 아닌 현대화된 Parquet & ORC 포맷으로의 전환이 필수적이다.


Parquet/ORC

https://parquet.apache.org/docs/file-format/

Apache Parquet는 칼럼 기반 저장(Columnar Storage) 포맷이다.
데이터를 칼럼 단위로 저장하여, 조회 시 필요한 칼럼만 읽을 수 있어  I/O · CPU 효율이 높다.
칼럼 단위 압축을 지원하여 파일 크기가 작아 읽기 효율 좋다.
파일 푸터에 스키마, 칼럼 통계 등의 메타 데이터가 포함되어 있어, 분산 처리와 불필요한 I/O 최소화에 유리하다.
Parquet 파일은 내부적으로 row group이라는 블록 단위로 나뉘는데,  row group 단위로 분산 처리가 가능하다.



ORC(Optimized Row Columnar) 또한 칼럼 기반 포맷으로 Parquet와 동일한 이점을 갖는다.
Parquet와의 차이점으론 Hive에 최적화된 포맷으로 Spark, Impala 등의 다른 쿼리 엔진에서의 범용성이 낮다는 차이가 존재한다.
Light-weight indexing 제공하여 특정 칼럼/범위 필터링 시 빠른 접근이 가능하다.

공통적인 단점으론, 
쓰기 성능이 비교적 느리다는 점(칼럼 기반 포맷의 특징)이 있고,
기본적으로 압축되고 파일 내에 메타 데이터가 포함되어있기 때문에, raw 데이터를 바로 조회하는 것이 불가능하다.
JSON과 마찬가지로 row 단위의 변경, 삭제가 어렵다. 하지만 ACID 연산을 지원하는 iceberg 테이블을 사용해 해결할 수 있다.


정리

조회 성능 저하의 궁극적인 원인은 Json 형식으로 저장되는 데이터이다. Hive Table에선 이를 JsonSerde로만 읽을 수 있어 성능 저하가 발생한다.

결국, 이를 해결하기 위해선 JSON 포맷을 읽기 성능이 좋은 Parquet/ORC로 변환하는 작업이 필연적이다.
테이블들이 모두 흩어져 있는 것이 문제인데,, 추후에 이들을 모두 parquet 포맷으로 변환하는 공통 spark job을 만들어볼 수 있을 것 같다.
- 특정 Hive 스키마 하위의 테이블들의 모두 읽어 JsonSerde 테이블들을 필터링하고, 이들에 External Location을 읽어 Parquet로 변환 하는 기능을 구현하면 되지 않을까 싶다.

다만, 이미 Parquet & Iceberg 테이블을 사용하는 프로세스들이 개별적으로 존재해 모든 테이블 데이터를 옮기는건 비용 측면에서도 비효율적수 있으니 추가적인 고민이 필요할 것 같다.


Reference

Json serde 동작 방식

https://www.sparkcodehub.com/hive/serde/json-serde


json.gz vs parquet 압축률 비교
https://blog-tech.tadatada.com/2018-05-23-parquet-and-spark

 

Parquet & ORC 포맷
https://jaegeunbang.github.io/posts/2020/03/09/Parquet,Orc-%EC%A0%95%EB%A6%AC.html
https://docs.aws.amazon.com/ko_kr/athena/latest/ug/columnar-storage.html

728x90
반응형