Spark job에 따른 최적의 Partition 크기, 개수 조정하기

Q·2023년 11월 23일
0

Spark에서 Shuffle이 일어나는 이유, 언제 일어나는 지

1. Shuffle이 일어나는 이유

  • 파티션 사이에서 데이터가 재배치 되어야 할 때
  • 특정 transforamtion 실행 시 다른 파티션에서 정보가 필요하기 때문에 셔플을 함으로써 정보를 찾음

2. shuffle은 언제 일어나는 지

  • join, union, groupBy, sort, coalesce, repartition, aggregate 과 같이 파티션과 관련된 조작이 있을 때
  • 즉, MapReduce의 reduce()에 해당하는 operation을 실행하기전에 물리적인 데이터의 이동이 있어야 하기 때문에 shuffle이 일어난다.
  • ex) 컬럼의 모든 값을 더할 때

shuffle spill(memory)란? shuffle spill(disk)란?

1. shuffle spill이란?

데이터를 직렬화하고 스토리지에 저장, 처리이후에 역직렬화하여 연산 재개하는 행위
data를 shuffle할 때 자원이 충분하지 못할 때 발생
-> partition size는 크지만 연산에 쓰이는 memory가 부족할 때

  • shuffle spill(memory):
    spill될 때 메모리에서 역직렬화된 형태의 데이터 크기
  • shuffle spill(disk):
    spill된 이후 디스크에서 직렬화된 형태의 데이터 크기
  • 역직렬화된 데이터가 직렬화된 데이터보다 공간을 더 많이 차지하므로 spill된 크기도 큼
  • input data가 클 때 spill memory size도 커짐

2. shuffle spill이 성능에 미치는 영향

  • Task가 지연되고, 에러가 발생
  • Hadoop 클러스터의 사용률이 높다면, 연달아 에러가 발생되고 최악의 경우에는 Spark가 강제종료

3. Shuffle spill을 방지 하는 방법

  • 쿼리 최적화(skew 현상 제거),
    1) 필요한 쿼리만select or wide transformation 전에 조건 연산자 추가
  • Partition 수 증대 -> partition 크기 감소
  • core당 메모리 양 증가

Shuffle Partition 수 최적화

관련 config: Spark.sql.shuffle.partitions

  • Spark 성능에 가장 크게 영향을 미치는 Partition으로, Join,groupBy 등의 연산을 수행할 때 Shuffle Partition이 쓰임
  • join, groupBy와 같은 연산을 수행 시 Partition의 수(Task 수)가 결정

Shuffle Partition은 일반적으로 core 수 = partition 수 라고는 되어 있지만,
1. core의 2~3배 숫자를 지정하는 것이 적합,
2. shuffle Partition 1개당 size를 100Mb ~ 200Mb 사이의 크기로 맞추어 Partition 숫자를 산정

Partition 크기를 아는 방법

Partition의 크기는 shuffle read size와 Partition 수에 따라서 결정

shuffle read size:
모든 executor에 직렬화된 읽기 데이터의 총합

Partition 크기 및 개수 최적화 예시

  1. shuffle read size 240GB라 가정 partition 수가 300일 시, Partition당 크기는 800MB(partition당 읽어 들이는 양)

  2. spill(memory) size가 없다면, 설정한 partition 수로 자원의 부족함 없이 task가 실행되고 있다고 봄

  3. spill(memory) size가 있다면, 예를들면 spill(memory) size가 840GB라 가정하면 Partition당 spill(memory) size는 약 2.8GB~이므로 1core당 2GB 메모리의 자원으로는 수행이 불가

  4. Partition당 크기를 160MB가 되도록 설정한다면, 800MB/5 = 160MB ,즉 Partition의 수는 기존 300개 보다 5배 많은 300 * 5 = 1500으로 증가

300개의 partition수 일 때 일어났던 840GB의 spill(memory) size가 Partition당 840G/1500 =약 0.5xGB~정도로 1core당 2GB는 물론, 심지어 놀고 있는 메모리가 생겨 1core당 1GB를 사용해도 가능

메모리 설정 팁

  • shuffle read size + shuffle write size < executor 수 * executor당 memory 양
  • Shuffle Size가 600GB에 가깝거나 그 이상일 경우, Core당 메모리를 증가시키는 것이 좋음. 또한 1코어당 4GB를 고려하기를 권장

결론:

  • 총 코어의 개수보다 적은 수의 파티션 수는 일부 resource가 놀게 되므로 비효율적이다.
  • 일반적으로 파티션수를 늘리는 것은 오버헤드가 너무 많아지기 전까지는 성능을 높인다(2~3배가 적당)
  • 파티션을 늘리게 되면 파티션의 크기가 작아지고 각 executor에서 spark가 처리하는 partition(task)의 양이 적어지므로 메모리 부족 오류를 줄이게 된다.
  • 메모리 부족 오류 및 spill size가 줄어들면 지연이 사라지고 성능이 올라간다.
  • 너무 많은 파티션은 driver memory error, driver overhead error를 유발하며, 작은 사이즈의 파일들을 생성하기위한 I/O도 많이 발생한다(특히 block store)

참고

profile
Data Engineer

0개의 댓글