티스토리 뷰

하둡1.0 에서 맵리듀스를 실행할 때는 슬롯 단위로 맵/리듀스 태스크 개수를 관리했습니다. 하지만 하둡2.0에서 YARN(이하: 얀)이 도입되면서 슬롯이 아닌 컨테이너 단위로 리소스를 할당하게 됩니다. 얀의 리소스매니저는 전체 클러스터의 리소스 정보를 토대로 할당 가능한 컨테이너 개수를 계산하며, 맵리듀스는 필요한 컨테이너들을 할당 받아서 맵리듀스 태스크를 실행하게 됩니다. 이때 컨테이너 개수와 맵과 리듀스 태스크 개수는 1:1의 관계가 아니며, 맵과 리듀스 태스크는 상황에 따라서 하나 이상의 컨테이너를 실행할 수도 있습니다. 그래서 관리자는 전체 클러스터의 리소스 상황과 얀에서 실행하는 잡들의 워크로드를 고려하여 리소스 설정을 진행해야 합니다. 필자는 아래와 같은 환경으로 구성된 클러스터에서 리소스 설정을 진행하겠습니다.

a. 서버별 리소스

- CPU 물리 코어 개수: 24개

- 메모리 크기: 128GB

- 디스크 개수: 12개

b. 전체 서버 대수 : 20대


1. 얀 설정


1) yarn.nodemanager.resource.memory-mb 설정


yarn.nodemanager.resource.memory-mb 속성은 각 노드매니저가 컨테이너 할당에 사용할 메모리 크기를 나타내며, 다음과 같은 공식으로 계산합니다.


* 컨테이너 할당용 메모리 크기 = 서버 메모리 크기 - (얀을 제외한 다른 소프트웨어들이 사용할 메모리 크기)


이때 메모리 크기는 노드매니저의 JVM 힙 메모리 크기를 초과하지 않도록 설정해야 합니다. 필자는 전체 메모리 128GB 중 8GB는 운영체제 및 다른 소프트웨어에서 사용한다고 가정하고, 예제 1과 같이 120GB를 계산했습니다. 참고로 별도 설정이 없을 경우 기본값으로 8GB를 사용합니다.


<property>

     <name>yarn.nodemanager.resource.memory-mb</name>

     <value>122880</value>

</property>

[예제 1] 노드매니저가 컨테이너 할당에 사용할 메모리 크기


2) yarn.nodemanager.resource.cpu-vcores 설정


yarn.nodemanager.resource.cpu-vcores 속성은 각 노드매니저가 컨테이너 할당에 사용할 CPU 코어 개수를 의미하며, 다음과 같은 공식으로 계산합니다.


* 컨테이너 할당용 CPU 코어 개수 = MIN(전체 CPU 코어 개수 - 얀을 제외한 다른 소프트웨어들이 사용할 CPU 코어 개수, 2 x 디스크 개수)


CPU 코어 개수는 물리적인 CPU 코어 개수를 적용할 수 있고, 하이퍼스레드를 사용 중 이라면 가상의 CPU 코어 개수를 적용해도 됩니다. 이때 CPU 코어 개수만 계산하는 것이 아니라, 디스크 개수의 2 배수도 함께 계산해서 둘 중에 작은 값을 컨테이너 할당에 사용합니다. 필자는 얀을 제외한 소프트웨어에서 CPU를 2 코어 사용한다고 가정한 후, 다음과 같이 컨테이너용 CPU 코어 개수를 22로 계산했습니다.


* 22 = MIN(24 - 2, 2 x 12)


예제 2는 계산된 CPU 코어 개수를 yarn-site.xml에 설정한 내용입니다.


<property>

     <name>yarn.nodemanager.resource.cpu-vcores</name>

     <value>22</value>

</property> 

[예제 2] 노드매니저가 컨테이너 할당에 사용할 CPU 코어 개수


3) YARN_NODEMANAGER_HEAPSIZE 설정


yarn-env.sh 파일에 노드매니저의 JVM 힙 메모리 크기를 설정합니다. yarn.nodemanager.resource.memory-mb는 노드매니저의 힙 크기를 초과할 수 없기 때문에, 힙 메모리 크기를   위 값보다 조금 여유있게 설정합니다. 필자는 힙 메모리 크기를 122GB로 설정했습니다.


export YARN_NODEMANAGER_HEAPSIZE=124928

4) yarn.scheduler.maximum-allocation-mb 설정

yarn.scheduler.maximum-allocation-mb는 ResourceManager가 하나의 컨테이너 할당에 필요한 최대 메모리 크기입니다. 관리자는 컨테이너에서 실행할 맵 태스크나 리듀스 태스크가 필요한 메모리 크기를 고려해서 이 값을 설정해야 합니다. 필자는 예제3과 같이 컨테이너당 최대 4GB의 메모리를 사용한다고 가정했습니다.


 <property>

  <name>yarn.scheduler.maximum-allocation-mb</name>

  <value>4096</value>

 </property>

[예제 3] ResourceManager가 각 컨테이너 할당에 필요한 최대 메모리 크기


yarn.scheduler.maximum-allocation-mb는 yarn.nodemanager.resource.memory-mb 속성값의 이하로 설정해야 하며, 컨테이너 할당에 필요한 최소 메모리 크기는 yarn.scheduler.minimum-allocation-mb 속성으로 설정할 수 있습니다. 참고로 yarn.scheduler.minimum-allocation-mb 속성의 기본값은 1GB, yarn.scheduler.maximum-allocation-mb 기본값은 8GB입니다.



2. 맵리듀스 설정


1) yarn.app.mapreduce.am.resource.mb 설정


yarn.app.mapreduce.am.resource.mb 속성은 맵리듀스 애플리케이션의 애플리케이션마스터인 MRAppMaster를  컨테이너에서 실행할때 필요한 메모리 크기입니다. 필자는 예제4와 같이 mapred-site.xml에 설정했습니다.


<property>

   <name>yarn.app.mapreduce.am.resource.mb</name>

   <value>1536</value>

</property>

[예제 4] MRAppMaster용 메모리 설정


2) 맵리듀스 태스크용 메모리 설정


맵리듀스 태스크가 요청하는 컨테이너의 메모리 크기를 설정합니다. 각 설정은 예제 5와 같이 mapred-site.xml에 설정합니다. mapreduce.map.memory.mb 속성은 맵 태스크가 요청하는 컨테이너 메모리 크기이고, mapreduce.reduce.memory.mb는 리듀스 태스크가 요청하는 컨테이너 메모리 크기입니다.


<property>

   <name>mapreduce.map.memory.mb</name>

   <value>2048</value>

</property>

<property>

   <name>mapreduce.reduce.memory.mb</name>

   <value>4096</value>

</property> 

[예제 5] 맵리듀스 태스크 컨테이너용 메모리 크기

맵리듀스 애플리케이션이 실행되려면 애플리케이션 마스터, 맵리듀스 태스크가 실행되어야 하므로 최소 3개의 컨테이너가 필요합니다. 그래서 mapreduce.map.memory.mb, mapreduce.reduce.memory.mb, yarn.app.mapreduce.am.resource.mb 의 합계가 yarn.nodemanager.resource.memory-mb보다 작게 설정되어야합니다. 또한 각 속성값들은 반드시 yarn.scheduler.maximum-allocation-mb 값 이하로 설정해야 합니다.


3) 맵리듀스 태스크용 힙 메모리 설정

맵리듀스 태스크는 JVM 프로세스로 실행되기 때문에 해당 JVM에 대한 최대 힙 메모리 크기를 설정해야 합니다. 힙 메모리 크기는 다음과 같은 식으로 산출되며, 컨테이너 메모리 크기의 80%로 계산합니다.


* 맵 태스크용 최대 힙 메모리 크기 = mapreduce.map.memory.mb x 80% * 리듀스 태스크용 최대 힙 메모리 크기 = mapreduce.reduce.memory.mb x 80%


필자는 위 공식으로 예제16.7의 설정값의 힙 메모리값을 계산하며, 계산 결과는 예제 6과 같이 mapred-site.xml에 설정합니다.


* 맵 태스크용 최대 힙 메모리 크기 = 2048 x 0.8 = 1638 * 리듀스 태스크용 최대 힙 메모리 크기 = 4096 x 0.8 = 3277


mapreduce.map.java.opts.max.heap은 맵 태스크 스레드의 최대 힙 메모리 크기, mapreduce.reduce.java.opts.max.heap은 리듀스 태스크 스레드의 최대 힙 메모리 크기를 나타냅니다. 참고로 각 속성의 기준 단위는 MB이며, 별도 설정이 없을 경우 800MB을 기본값으로 사용합니다.


<property>

   <name>mapreduce.map.java.opts.max.heap</name>

   <value>1638</value>

</property>

<property>

   <name>mapreduce.reduce.java.opts.max.heap</name>

   <value>3277</value>

</property> 

[예제 6] 맵리듀스 태스크 최대 힙 메모리 크기


또한 mapreduce.map.java.opts.max.heap, mapreduce.reduce.java.opts.max.heap에 설정하지 않고, JVM 실행 옵션에 힙 메모리를 설정할 수도 있습니다. 컨테이너가 맵 태스크를 실행할 때는 mapreduce.map.java.opts, 리듀스 태스크를 실행할 때는 mapreduce.reduce.java.opts 옵션을 적용하는데, 각 옵션에 예제7과 같이 힙 메모리를 설정하면 됩니다.


<property>

   <name>mapreduce.map.java.opts</name>

   <value>-Xmx1638m</value>

</property>

<property>

   <name>mapreduce.reduce.java.opts</name>

   <value>-Xmx3277m</value>

</property> 

[예제 7] JVM 실행 옵션을 이용한 맵리듀스 태스크 최대 힙 메모리 크기 설정


지금까지 주요 프로세스에 대한 메모리 설정을 진행했습니다. 그림1은 노드매니저에서 맵리듀스 태스크 실행의 계층 구조와 각 프로세스에 대한 메모리 설정값을 나타낸 그림입니다. 참고로 각 수치는 필자가 예제로 사용했던 값을 사용했습니다.




[그림1] 계층 구조에 따른 주요 프로세스별 메모리 설정


4) 맵리듀스 태스크용 CPU 코어 개수 설정


맵 태스크용 컨테이너의 CPU 코어 개수는 mapreduce.map.cpu.vcores, 리듀스 태스크용 컨테이너의 CPU 코어 개수는 mapreduce.reduce.cpu.vcores를 mapred-site.xml 설정하면 됩니다. 필자는 예제8과 같이 각 속성의 기본값인 1을 사용했습니다.


<property>

   <name>mapreduce.map.cpu.vcores</name>

   <value>1</value>

</property>

<property>

   <name>mapreduce.reduce.cpu.vcores</name>

   <value>1</value>

</property>

[예제 8] 맵리듀스 태스크 컨테이너용 CPU 코어 개수



3. 컨테이너 개수


마지막으로 리소스매니저가 할당할 수 있는 컨테이너 개수에 대해 알아보겠습니다. 리소스매니저는 관리자가 설정한 CPU 코어 개수와 메모리 크기로 컨테이너 할당 기준값을 산정한 후, 맵리듀스가 요청하는 CPU 코어 개수와 메모리 크기를 비교해서 컨테이너 개수를 산출합니다. 컨테이너 개수는 다음과 같은 식으로 산출되며, CPU 코어 계산값과 메모리 계산값 중 최소값을 전체 서버 대수에 곱한 결과가 컨테이너 개수가 됩니다.

* 맵 태스크용 컨테이너 개수 = MIN(yarn.nodemanager.resource.memory-mb / mapreduce.map.memory.mb, yarn.nodemanager.resource.cpu-vcores / mapreduce.map.cpu.vcores) x 전체 서버 대수 * 리듀스 태스크용 컨테이너 개수 = MIN(yarn.nodemanager.resource.memory-mb / mapreduce.reduce.memory.mb, yarn.nodemanager.resource.cpu-vcores / mapreduce.reduce.cpu.vcores) x 전체 서버 대수


필자의 경우 각 서버에서는 22개의 컨테이너를 실행할 수 있으며, 전체 클러스터에서는 440개의 컨테이너를 동시에 실행할 수 있습니다.


* 맵 태스크용 컨테이너 개수 = MIN(122880 / 2048, 22 / 1) x 20 = MIN(60, 22) x 20 = 22 x 20 = 440 * 리듀스 태스크용 컨테이너 개수 = MIN(122880 / 4096, 22 / 1) x 20 = MIN(30, 22) x 20 = 22 x 20 = 440



4. 메모리 사용량 검사


노드매니저는 컨테이너의 메모리 사용량을 모니터링하며, 메모리 사용량이 설정된 임계치를 넘어서면 자동으로 컨테이너를 종료할 수 있습니다.


1) yarn.nodemanager.vmem-pmem-ratio


이 속성은 컨테이너의 실제 메모리 대비 가상 메모리 사용 비율을 나타냅니다. 기본값은 2.1로 설정되어 있으며, 이는 맵 태스크용 컨테이너는 mapreduce.map.memory.mb 속성값의 2.1배의 가상 메모리를 사용할 수 있고, 리듀스 태스크용 컨테이너는 mapreduce.reduce.memory.mb 속성값의 2.1배의 가상 메모리를 사용할 수 있다는 의미입니다. 예를 들어 mapreduce.map.memory.mb가 1536MB로 설정되어 있을 경우, 컨테이너에게 허용되는 가상 메모리는 3225.6MB(2.1 x 1536MB)입니다.


2) yarn.nodemanager.vmem-check-enabled


컨테이너에 대한 가상 메모리 제한이 있는지 확인합니다. 이 속성이 true로 설정된 경우, 노드매니저는 컨테이너가 yarn.nodemanager.vmem-pmem-ratio에 설정된 비율 이상의 가상 메모리를 사용하면, 자동으로 컨테이너를 종료합니다. 아래 로그는 설정 가능한 가상 메모리 용량인 2.1GB를 초과해서, 컨테이너가 종료됐음을 나타냅니다.


Current usage: 510.3 MB of 1 GB physical memory used;

2.2 GB of 2.1 GB virtual memory used. Killing container.


참고로 이 속성은 기본적으로 false로 설정되어 있습니다. OS 마다 가상 메모리를 할당하는 방식이 다르기 때문에 관리자는 OS 의 특성을 고려하여 이 속성을 사용할지, 혹은 yarn.nodemanager.vmem-pmem-ratio 비율을 늘려줄지 고민해야 합니다.


3) yarn.nodemanager.pmem-check-enabled


컨테이너에 대한 물리 메모리 제한이 있는지 확인합니다. 이 속성이 true로 설정된 경우, 노드매니저는 컨테이너가 허용된 물리 메모리 이상을 사용할 경우, 해당 컨테이너를 자동으로 종료합니다. 예를 들어 맵 태스크용 컨테이너가 mapreduce.map.memory.mb 속성값 이상의 물리 메모리를 사용하거나, 리듀스 태스크용 컨테이너가 mapreduce.reduce.memory.mb 속성값 이상을 사용할 경우, 각 컨테이너는 자동으로 종료됩니다. 아래 로그는 2.0GB의 물리 메모리만 허용된 컨테이너가 2.1GB의 물리 메모리를 사용해서 종료된 경우입니다.


Current usage: 2.1GB of 2.0GB physical memory used;

1.6GB of 3.15GB virtual memory used. Killing container.


하지만 컨테이너가 할당된 것보다 많은 메모리가 필요한 경우에는 이 속성을 false로 설정해야 합니다. 참고로 이 속성은 기본적으로 true로 설정되어 있습니다.

저작자 표시 비영리 변경 금지
신고
크리에이티브 커먼즈 라이선스
Creative Commons License
댓글
댓글쓰기 폼