BigData

Spark를 YARN에 수행할 때 메모리 세팅 추천 #1

멋진그이름 2017. 10. 12. 23:39

<개요>

YARN은 현재 CPU 와 Memory에 대해서만 스케쥴링을 수행한다.

따라서 Spark를 YARN Cluster 혹은 Client로 수행할때에도 해당 리소스의 제어를 받게 되는데 이 때 최적의 세팅값을 찾는 법을 확인해본다.


<내용>

<그림 1 : Spark와 Yarn Containter간의 메모리 관계>


A. 위의 그림을 참고로 해서 Spark와 YARN Configuration값을 살펴보면


1) Sparak Executor

--executor-cores 와 spark.executor.cores  는 Spark Executor가 동시에 수행할 수 있는 tasks의 수이다. 


--executor-memory 와 spark.executor.memory 는 Spark Executor의 heap size이다.


세팅된 두 값은 모든 Spark Executor가 같은 값으로 동작한다.


2) num of executors

--num-executors 와 spark.executor.instances  Spark Executor의 수를 의미하지만

spark.dynamicAllocation.enabled 옵션을 통해서 동적으로 제어된다. (CDH 5.4/Spark 1.3)



3) YARN

yarn.nodemanager.resource.memory-mb 은 각 노드에서 컨테이너들이 사용할 수 있는 메모리의 총합이고


yarn.nodemanager.resource.cpu-vcores 은 각 노드에서 컨테이너들이 사용할 수 있는 core의 총합이다.



4) 보정수치

각 컴포넌트의 관계로 인해서 각 설정값은 정확히 일치할 수 없고 여유의 값을 두어야 한다. 예를 들면 다음과 같다.


  • --executor-memory/spark.executor.memory 는 executor의 heap size를 결정하지만 JVM은 off heap 부분에 대해서도 사용을 하기 때문에 Yarn container는 이를 감안하여 공간을 설정해야 한다.   spark.yarn.executor.memoryOverhead 값을 통해서 추가공간을 확보하며 default 는  0.07 * spark.executor.memory  이다
  • yarn.scheduler.minimum-allocation-mb 과 yarn.scheduler.increment-allocation-mb 를 통해서 



B. 예제를 통해서 살펴보자


각각 16 cores 와 64GB 의 메모리를 가진 노드가 6개 있는 cluster 인경우 


yarn.nodemanager.resource.memory-mb = 63 * 1024

yarn.nodemanager.resource.cpu-vcores = 15


를 사용할 수 있다. 


Hadoop에서 자체적으로 띄우는 데몬들이나 OS에서 사용하는 리소스들이 있기 때문에 최소 1G와 1개의 Core는 남겨둔 상태이며 필요에 따라서는 여유를 더 많이 둬야 한다.


두가지 설정값을 예시로 비교해보면



1) --num-executors 6 --executor-cores 15 --executor-memory 63G 로 세팅한다면??


단순히 생각하면 이상적인 수치이다. 각 노드에서 Executor를 하나씩 띄우고,

각 Executor는 63G의 메모리와 15 core를 Full로 사용해서 작업한다. 

그러나 다음과 같은 이유로 사실은 비효율적인 세팅이 된다.


- 그림1에서 보는 것처럼 executor의 메모리는 Yarn Nodemanager resource memory 와 Container 보다 작아야 한다.


- AM이 기동되어야 하기 때문에 해당노드에서는 executor가 15 cores 를 사용할 수 없다.


- executor가 15 cores를 사용할 경우 HDFS I/O로 인해 성능의 병목이 생긴다.



2) --num-executors 17 --executor-cores 5 --executor-memory 19G 가 더 나을 듯 하다.

이유는 다음과 같다.


- 각 노드에서 3개씩 executors가 기동되고 하나의 노드에서는 2개가 기동되어 AM을 위한 공간이 확보된다.


- 각 노드에서 3개의 executors가 기동되기 때문에 63 / 3 = 21 이 되며 위에서 설명한 여유공간을 위해서 21 * 0.07 = 1.47 을 제외한 만큼 19G로 executor-memory 로 설정한다.


<기타>

실제로 YARN Application에서 모니터링을 해보면 spark.executor.memory로 설정한 값을 모두 사용하지는 않는다. 그 이유는 그림1에서 보는 것처럼 fraction수치를 코드내에서 곱해주도록 되어있기 때문이다.



<참고>

http://blog.cloudera.com/blog/2015/03/how-to-tune-your-apache-spark-jobs-part-2/