2021. 7. 2. 17:12ㆍBigdata Platform/Spark
필자는 Spark SQL을 활용한 솔루션을 운용중인데, Spark에는 실행시 다음과 같은 옵션들이 있다.
참고) Spark란? (출저 : 위키독스)
위키독스
온라인 책을 제작 공유하는 플랫폼 서비스
wikidocs.net
예를 들어, 하나의 Spark Shell을 실행시키기 위한 옵션을 부여한다고 가정했을때,
spark-shell --master yarn --num-executors 30 --executor-cores 2 --executor-memory 10G --queue default
다음과 같은 옵션들을 넣게 된다.
이 말은 즉슨,
--master yarn # yarn을 리소스 관리자로 사용, local모드 혹은 docker기반의 mesos모드 가능
--num-executors 30 # 실행하고자 하는 작업의 executor 갯수
--executor-cores 2 # 실행하고자 하는 작업의 executor당 코어수
--executor-memory 10G # 실행하고자 하는 작업의 executor당 메모리 수
--queue # 작업이 할당될 yarn 리소스 큐
이 설정 값들의 적용 순서는
1) SparkConf
2) spark-shell
3) spark-submit
4) spark-defaults.conf
가 우선순위가 되어서 작업이 실행된다.
Spark 작업들을 실행할때 이와 같은 설정을 제외한 (ex. 네트워크 대역폭, Disk R/W등)의 성능은 우리가 조정할 수
없으므로, 작업을 실행할때 최적화를 위한 설정들은 해당 값들로 수행이 된다.
그러면 설정을 어떻게 해주어야 가장 효율적으로 (자원을 최소로, 속도는 최대로) 사용할 수 있을까? 가
우리의 주요 Issue가 될것이다.
이를 확인하기 위해 Cloudera Documentation을 참고하였다.
https://blog.cloudera.com/how-to-tune-your-apache-spark-jobs-part-2/
How-to: Tune Your Apache Spark Jobs (Part 2) - Cloudera Blog
Editor’s Note, January 2021: This blog post remains for historical interest only. It covers Spark 1.3, a version that has become obsolete since the article was published in 2015. For a modern take on the subject, be sure to read our recent post on Apach
blog.cloudera.com
< Cloudera의 Sample Case >
- 서버는 총 6대 (6node)
- 서버당 의 CPU(Core)는 16GB
- 서버당 Memory는 64GB -> 여유 메모리를 제외하여 63GB 사용
- 6대 노드는 총 96 cores와 약 378GB Memory를 가짐
1. --num-executors 6 --executor-cores 15 --executor-memory 63G
- executor는 총 6개
- executor당 15개의 Core 사용
- executor당 63GB Memory 사용
- 이는 잘못된 접근, 왜냐?
- 각 서버의 메모리가 64GB 시스템에서 OS나 NodeManager가 사용해야하는 메모리 여유분이 있어야 하기 때문에, 하나의 executor가 메모리를 63GB까지 사용하는 것은 어려움.
- 한 executor에 15개의 core를 사용하면 HDFS I/O throughput이 낮아지는 등, 성능 저하를 유발할 수 있음.
- 그래서, executor core의 수는 1보다는 크게, 그리고 5 보다는 작게 설정하는 것이 좋음.
2. --num-executors 17 --executor-cores 5 --executor-memory 19G
- executor는 총 17개
- executor당 5개의 Core 사용
- executor당 19GB Memory 사용
- 이렇게 구성하면 모든 노드에서 Executor가 3개 생성되어 Application Master가 사용하는 Executor를 제외하면
- 총 2개의 Executor가 실행됨.
memory는 (노드당 63/3 Executor) = 21.21 * 0.07 = 1.47.21 – 1.47 ~ 19로 계산되었음.
결론적으로,
1) --executor-cores의 개수를 1~5 사이값으로 정한다.
2) --num-executors를 구한다.
(--num-executors ) x (--executor-cores) < 서버 전체 CPU 수
3) 노드 하나당 할당할 수 있는 executor 개수를 구한다.
--num-executors / 전체 노드 개수 = 노드 당 executor 개수
4) --executor-memory를 구한다.
노드당 Memory / 노드당 executor 개수 = --executor-memory
라는 공식이 도출될 수 있다고 한다.
그러면 이에 따라 나는 13노드에 64Core, 512GB 서버를 통해 계산해 보았다.
(하이퍼스레딩과 OS 영역등 기타 사용량 제외)
- 노드당 코어수 : 31
- 노드당 메모리수 : 255
- 31 x 13 = 402 (코어 x 노드수)
- 402 / 2 = 201 (코어를 2~5까지 모두 계산하여 executor갯수를 코어에 맞춰서 나눠서 구함)
/ 3 = 134
/ 4 = 100
/ 5 = 80
- 255 / 201 = 1.27 (메모리수, 대충 반올림하였음)
/ 134 = 1.9
/ 100 = 2.55
/ 80 = 3
이 설정을 참고하여 Spark-SQL 작업을 실행시켰는데, 대략 결과치는 1억2천만건 정도의 Row가 생성되는 프로그램이다.
--num-executors 100 --executor-cores 4 --executor-memory 2.5G
>>> 실행 결과 : 20분 소요
그러면 코어를 줄이고 메모리를 늘리면 어떨까?
--num-executors 200 --executor-cores 2 --executor-memory 1.3G
>>> 실행 결과 : 22분 소요
환경에 따라 다를수는 있겠지만, Executor수를 늘리니 오히려 작업이 느려졌다. 그런데 다른 작업에서는 오히려 Core를 낮추고 Executor를 늘리는 것이 더 빨라졌다.
그러면 권고 설정보다 메모리를 더 많이 부여하면 어떻게 될까?
--num-executors 80 --executor-cores 2 --executor-memory 10G
>>> 실행 결과 : 17분 소요
이때까지 설정한 Properties중에 가장 빠르게 실행되었다.
왜 이런 현상이 발생하는 것일까?
Spark의 구조를 더 파악해봐야겠지만, 깃허브에서 해당 링크를 참고하였다.
여기서 말하는 것은 light한 executor는 1core당 설정을, heavy한 executor는 1노드당 설정을 기준으로 하여
결론적으로는 균형있는 executor수를 조정해야 한다는것이다.
결국 나의 Case에서도, 내가 map하거나 join할 테이블이 얼마나 heavy한지,
이 executor가 얼마나 한번에 처리해야할 task수가 많은지 적은지에 따라서 결과가 달라질 수 있다는 점을 파악하였다.
결론은 최적화된 옵션은 환경에 따라 다르고, task나 table에 따라서 다를 수 있으며,
Test Case를 여러번 적용해야 찾을 수 있을 것 같다.
그러나,
1) 계산식을 통해 Core, memory, executor 수를 먼저 계산
2) 작업하고자 하는 node(서버)의 사용량과 서버 대수를 계산
3) 실제 task가 적용할 table의 구조와 row수를 파악
을 기본적으로 해야만이 작업할 task에 대한 최적치 값을 산출할 수 있다고 생각한다.
'Bigdata Platform > Spark' 카테고리의 다른 글
Spark on Livy - NoSuchObjectException (Ranger Authorization) (0) | 2021.12.07 |
---|---|
Spark SQL - Hive Partition Key Error (0) | 2021.08.29 |