📚 오늘 공부한 내용
1. Spark 파일 포맷
- 데이터는 디스크에 파일로 저장이 된다. 그렇기 때문에 일에 맞게 최적화가 필요하다.
- 데이터 파일은 크게 세 개로 나뉠 수 있는데 비구조화된 파일, 구조화되긴 했지만 semi-structured된 타입이 존재하고 완전 구조화된 타입인 structured 타입이 존재한다.
- structured 타입은 보통 Binary 타입이다.
- Unstructured
- Semi-structured
- Structured
- Parquet
- Avro
- ORC
- SequenceFile
📌 Parquet
- Spark 기본 파일 포맷
- 트위터와 클라우데라에서 공동 개발
- Row-Wise Storage의 경우 쓰기에 최적화가 되어 있고, Column-Wise Storage는 읽기에 최적화가 되어 있다.
- 데이터 블록 단위로 하나의 Row Group이 만들어지고 이 안에서 Column별로 저장이 되는 Hybrid Storage가 있으며 Parquet가 이 방식을 사용한다.
2. 데이터 프레임 연산자
spark.read.option("header", True).csv(“test.csv”). \
where("gender <> 'F'"). \
select("name", "gender"). \
groupby("gender"). \
count(). \
show()
- Loading이 되는 순간 데이터 프레임은 하나 혹은 그 이상의 파티션으로 구성된다.
- WHERE, SELECT는 셔플링 없이 파티션 내에서 가능하기 때문에 executor에서 돌아가는 작업들이 독립적으로 작업한다.
- GROUPBY 시 다시 셔플링이 발생하며 COUNT는 그렇게 셔플링된 파티션 내에서 실행 가능하다.
- SHOW는 ACTION이라 부르며 데이터 프레임 관련 작업을 실제로 수행하게 하는 것을 말한다. 특정 작업들이 시행될 때 그 앞의 연산들이 실행되게 된다.
- Read와 Collect 역시 Action에 포함된다.
- 그 외에 Where, Select, GroupBy, Count와 같은 것을 Transformation이라고 부른다.
- Narrow Dependencies
- 독립적인 Paritition Level의 작업
- SELECT, FILTER, MAP 등
- Wide Dependencies
- Shuffling이 필요한 작업
- GROUP BY, REDUCE BY, PARTITION BY, REPARTITION, COALESCE 등
2) Action
- JOB을 실행시키는 코드를 말하며 호출 시 실제 코드가 실행된다.
- READ, WRITE, SHOW, COLLECT
- 하나의 JOB은 다수의 Transformation으로 이루어지며 한 STAGE는 Shuffling이 없어야 한다. 만약 Shuffling이 한 번 발생한다면 두 개의 STAGE가 된다.
3) JOBS, STAGES, TASKS
- Job
- 하나 혹은 그 이상의 STAGE로 구성된다.
- Stages는 Shuffling이 발생하는 경우 새로 생긴다.
- Stage
- DAG의 형태로 구성된 TASK들이 존재한다.
- Task
- 가장 작은 실행 유닛으로 executor에 의해 실행된다.
3. Bucketing과 Partitioning
1) Bucketing
- DataFrame을 특정 컬럼 혹은 ID를 기준으로 나눠 테이블로 저장하는 것을 말한다.
- DataFrameWriter의 BucketBy 함수를 사용한다.
- 이때 파라미터로는 Bucket의 수와 기준 ID를 지정해야 한다.
- 데이터의 특성을 잘 알고 최적화를 하기 위해 쓰는 방법이다.
2) Partitioning
- File System Partitioning을 말한다.
- Parition Key를 기반으로 폴더 구조로 물리적으로 나눠서 저장하는 방식으로 Hive에서 많이 사용하는 방법이다.
- 로그 파일은 시간 단위 일 단위로 처리를 많이 하기 때문에 처음부터 데이터를 그 형식으로 저장해 두면 Overhead를 줄일 수 있다. 그래서 데이터 자체를 연도-월-일 기준으로 폴더 구조로 저장한다. 이는 관리에 매우 직관적이고 Spark 관점에서는 데이터를 재정리할 필요도 없어지기 때문에 데이터의 읽기 과정이 최적화된다. (스캐닝을 하지 않아도 되기 때문)
- 데이터의 관리도 쉬워진다. (Retention Policy 적용 시)
- Partition By를 사용한 저장은 Partition Key를 이용해 저장하게 되는데 잘못 선택하면 엄청 나게 많은 파일들이 생성되기 때문에 Cardinality가 낮은 거를 써야 한다.
- Cardinality란 가능한 값의 경우의 수를 말한다.
🔎 어려웠던 내용 & 새로 알게 된 내용
✍ 회고