하둡 완벽가이드를 읽으며 정리한 내용입니다.
YARN은 하둡의 클러스터 자원관리 시스템이다. 맵리듀스의 성능을 높이기 위해 하둡2에서 처음 도입되었으나 맵리듀스뿐만 아니라 다른 분산 컴퓨팅 도구도 지원한다.
분산 컴퓨팅 프레임 워크는 위의 그림과 같이 계산 계층(YARN)과 저장계층(HDFS, HBASE)위에서 YARN 애플리케이션을 실행한다.
피크, 하이브 같은 애플리케이션은 맵리듀스, 스파크에서 구동되는 처리 프레임 워크이며 YARN에 직접 접근하지 않는다.
4.1 YARN 애플리케이션 수행 해부해보기
[YARN의 구조]
YARN은 기본적으로 Resource Management 기능과 Job Scheduling/Monitoring 기능을 분리된 데몬에서 처리한다.
이를 구현하기 위해서 Global Resource Manager(RM)와 application 단위로 존재하는 Application Master(AM) 을 가지도록 하였다. 여기서 말하는 Application은 하나의 작업 또는 작업의 DAG(Directed Acyclic Graph, 비순환 방향 그래프)을 의미한다.
- Resource Manager: Master Daemon에서 구동되며, 클러스터들로의 자원 할당을 관리한다.
- Node Manager: Slave Daemon에서 구동되며, 각 단일 노드의 Task 실행을 담당한다.
- Application Master: 개별적인 응용에서 필요로 하는 자원과 Job에 대한 lifecycle을 관리한다. 이것은 Node Manager와 함께 작동하며, 작업의 실행을 모니터링한다.
- Container: 한 노드의 자원을 모아둔 패키지 (RAM, CPU, Network, HDD 등)
Resource Manager은 시스템의 모든 Application들 사이에서 자원을 관리/중재한다. Node Manager은 Machine 단위로 존재하는 Framework Agent로 Container를 관리하고, CPU와 Memory와 같은 자원의 사용량을 모니터링하며, Resource Manager로 정보를 전달한다. Application단위로 존재하는 Application Master는 Resource Manager와 함께 자원을 협상하고, Task를 모니터링하고 실행하기 위해 Node Manager와 함께 작동한다.
[YARN의 구동방식]
- 클라이언트는 리소스매니저에 접속. 애플리케이션을 구동하기 위해 애플리케이션 마스터 프로세스의 구동을 요청
- 리소스 매니저가 노드 매니저를 찾아서 구동
- 애플리케이션 마스터를 실행할 노드매니저 탐색
- 노드 매니저 구동
- 작업 수행 후, 리소스를 리소스 매니저에 더 요청하거나 아니면 작업 종료
- 리소스를 더 할당 받은 경우 새로운 노드 매니저 찾아서 구동
- 분산처리를 수행
YARN은 클라이언트, 마스터, 프로세스와 같은 애플리케이션이 서로 통신하는 기능은 제공하지 않고 하둡의 RPC와 같은 원격 호출 방식을 이용하여 상태변경을 전달하고 클라이언트로부터 결과를 받는다.
4.1.1 자원요청
유연한 자원요청 모델을 갖고있다. 컨테이너에 필요한 자원의 용량뿐 아니라 요청에 대한 지역성 제약도 표현할 수 있다.
분산 데이터 처리 알고리즘에서 클러스터의 네트워크 대역폭을 효율적으로 활용하기 위해서는 지역성을 보장하는 것이 가장 중요하다.
→ 지역성 제약은 보통 특정 노드나 랙 또는 클러스터의 다른 곳에서 컨테이너를 요청할때 사용된다.
가끔 지역성 제약이 불가능할 경우, 할당이 실패하거나 선택적으로 제약을 조금 느슨하게 적용할 수 있다.
가령 특정 노드를 요청햇는데 그 노드에서 다른 컨테이너가 실행되고 있는 등의 상황이면, YARN은 동일한 랙의 다른 노드에서 컨테이너를 시작하려 시도한다.
YARN 애플리케이션은 실행 중에는 아무때나 자원요청을 할 수 있다.
스파크의 경우 클러스터에서 고정개수의 수행자를 시작하나 맵리듀스는 두단계로 되어있다.
처음에 필요한 맵 태스크 컨테이너를 요청한다. 하지만 리듀스 태스크 컨테이너는 맵태스크가 어느정도 실행된 후에야 시작될 수 있다.
4.1.2 애플리케이션의 수명
실행시간은 천차만별이므로 사용자가 실행하는 잡의 방식에 따라 애플리케이션을 분류하는 것이 좋다.
- 가장 단순한 유형은 사용자의 잡 당 하나의 애플리케이션이 실행되는 방식으로 맵리듀스 잡이 속한다.
- 두번째 유형은 워크플로나 사용자의 잡 세션당 하나의 애플리케이션이 실행되는 방식이다. 이 유형은 첫 유형보다 훨씬더 효율적이다. 순차적으로 실행되는 잡이 동일한 컨테이너를 재사용가능하며 잡 사이에 공유데이터를 캐싱할수 있는 장점이 있다. 대표적으로 스파
- 세번째 유형은 서로 다른 사용자들이 공유할 수 있는 장기실행 애플리케이션이다. 이러한 유형은 일종의 코디네이션 역할을 수행하기도 한다. 임팔라가 대표적. 임팔라는 여러 임팔라 데몬이 클러스터 자원을 요청할 수 있도록 프록시 애플리케이션을 제공한다. 이러한 경우 애플리케이션마스터가 항상 켜져있고 그에 따라 요청에 따른 구동 오버헤드를 피할 수 있어서 사용자가 요청하면 매우 빠른 시간내에 응답할 수 있다.
4.1.3 YARN 애플리케이션 만들기
아파치 슬라이더같이 YARN을 쉽게 만들 수 있도록 도와주는 프로젝트가 있다. 아파치 슬라이더는 기존의 분산 어플리케이션을 YARN위에서 실행하도록 해준다.
즉 YARN애플리케이션을 작성하는 것은 매우 어려우므로 기존 프로젝트를 활용하는 것을 추천한다
4.2 YARN과 맵리듀스1의 차이점
맵리듀스 API와 맵리듀스 구현은 다른 의미이다. 맵리듀스 API는 사용자 측면의 클라이언트 기능이고, 구현은 맵리듀스 프로그램을 실행하는 다른 방식을 의미한다.
[맵리듀스 1]
잡의 실행과정을 제어하는 하나의 잡 트래커와 하나 이상의 태스크트래커 등 두 종류의 데몬이 있다.
잡트래커는 여러 태스크 트래커에서 실행되는 태스크를 스케줄링함으로써 시스템에서 실행되는 모든 잡을 조율한다. 잡트래커는 태스크의 실행에 대한 진행상황을 파악하며 태스크가 실패하면 다른 태스크 트래커에 그 태스크를 다시 스케줄링할 수 있다.
잡트래커는 잡 스케줄링(태스크와 태스크 트래커 연결)와 태스크 진행 모니터링(태스크를 추적하고, 실패하거나 느린 태스크를 다시 시작하고 전체 카운터를 유지하는 방법)을 맡고 있다.
-> 즉 잡트래커 하나가 모든 작업에 대한 관리, 스케줄링 등을 진행
[맵리듀스 2]
YARN 등장.
위의 역할을 분리된 객체인 리소스 매니저와 애플리케이션 마스터(맵리듀스 잡 당 하나)를 통해 처리한다.
맵리듀스 1 | YARN |
잡 트래커 | 리소스매니저, 애플리케이션 마스터, 타임라인 서버 |
태스크 트래커 | 노드 매니저 |
슬롯 | 컨테이너 |
하둡 2.5.1에서 얀의 타임라인 서버는 아직 맵리듀스 잡 이력을 저장하지 못해서 잡 히스토리 서버 데몬은 여전히 필요하다
YARN 사용에 따른 이점
- 확장성
- 맵리듀스 1보다 더 큰 클러스터에서 실행 가능. 이는 맵리듀스1이 잡트래커가 잡과 태스크를 모두 관리하기 때문이다.
- YARN은 리소스 매니저와 애플리케이션 마스터를 분리하는 구조
- 이에 따라 애플리케이션 마스터는 해당 애플리케이션이 실행될때만 존재한다
- 가용성
- 고가용성은 서비스 데몬에 문제가 발생했을 때 서비스에 필요한 작업을 다른 데몬이 이어받을 수 있도록 상태 정보를 항상 복사해두는 방법으로 구현된다. 하지만 잡 트래커의 메모리에 있는 복잡한 상태 정보가 매우 빠르게 변경되는 상황에서 잡 트래커 서비스에 고가용성을 적용하는 것은 매우 어려운일이다.
- 이러한 잡 트래커의 역할이 YARN에서는 분리되었기 때문에 고가용성 서비스가 분할후 정복 문제로 바뀌었다.
- 먼저 리소스 매니저의 고가용성을 제공한 후 YARN 애플리케이션을 지원하면 된다.
- 하둡2는 리소스 매니저와 맵리듀스 잡을 위한 애플리케이션 마스터 모두에 고가용성을 제공한다.
- 효율성
- 맵리듀스1에서 각 태스크 트래커는 맵슬롯과 리듀스 슬롯으로 구분된 고정크기 슬롯의 정적할당 설정을 가지고 있다. 각 슬롯은 정해진 태스크실행만 가능
- YARN에서는 노드매니저는 정해진 개수의 슬롯대신 일종의 리소스 풀을 관리한다.
- 클러스터의 맵슬롯은 남아있지만 리듀스 슬롯이 없어서 리듀스 태스크가 마냥 대기하고 있는 상황은 발생하지 않는다.
- YARN의 자원은 잘게 쪼개져 있어서 애플리케이션은 필요한 만큼만 자원을 요청할 수 있다. 기존에는 개별 슬롯을 사용했기 때문에 특정 태스크를 위해 너무 많거나(자원 낭비), 너무 적게(실패원인) 자원을 할당했다.
- 멀티테넌시(다중 사용자)
- 하둡이 다양한 분산 애플리케이션을 수용할 수 있게 된것.
- 사용자는 서로 다른 버전의 맵리듀스를동일한 얀 클러스터에서 수행하는 것도 가능.
4.3 YARN 스케줄링
YARN 스케줄러의 역할은 정해진 정책에 따라 애플리케이션에 자원을 할당하는 것이다.
4.3.1 스케줄러 옵션
- FIFO 스케줄러
- 애플리케이션을 큐에 하나씩 넣고 제출된 순서에 따라 순차적으로 실행(선입선출 방식)
- 이해가 쉽고 설정이 필요없다는 장점
- 공유 클러스터환경에서는 부적합
- 대형 애플리케이션이 수행될때는 클러스터의 모든 자원을 점유해버릴수있기 때문에 무한 대기가 발생
- 공유 클러스터 환경에서는 캐퍼시티나 페어 스케줄러 권장
- 이 두개는 장시간 수행되는 잡을 계속 처리하는 동시에 작은 비정형 질의도 중간에 실행하여 적당한 시간내에 사용자가 결과를 얻을 수 있도록 허용
ii) 캐퍼시티 스케줄러는 작은 잡을 제출되는 즉시 분리된 전용 큐에서 처리. 해당 큐는 잡을 위한 자원을 미리 예약해두기 때문에 효율성은 떨어진다. 그리고 대형잡은 FIFO보다 늦게 끝난다.
iii) 페어스케줄러는 모든 잡의 자원을 동적으로 분배하기 때문에 미리 자원의 가용량을 예약할 필요가 없다. 대형잡이 실행되는 도중에 작은 잡이 추가로 시작되면 페어 스케줄러는 클러스터 자원의 절반을 이 잡에 할당한다.
이때 두 번째 잡이 시작되고 공평하게 자원을 받을때까지 약간의 시간차가 있을 수 있다. 그러나 전체적으로 클러스터의 효율성도 높고 작은 잡도 빨리 처리된다.
4.3.2 캐퍼시티 스케줄러 설정
각 조직은 전체 클러스터의 지정된 가용량을 미리 할당받는다. 분리된 전용 큐를 가지며 클러스터 가용량의 지정된 부분을 사용하도록 설정할 수 있다. 그리고 조직에 속한 서로 다른 사용자 그룹사이에도 클러스터의 가용량을 공유하도록 할 수 있다. 단일 큐 내부에 있는 애플리케이션들은 FIFO방식으로 스케줄링 된다.
하나의 단일 잡은 해당 큐의 가용량을 넘는 자원은 사용할 수 없다.
큐 안에 다수의 잡이 존재하고 현재 가용할 수 있는 자원이 클러스터에 남아있다면 해당 큐에 잇는 잡을 위해 여분의 자원을 할당할 수 있다. 이렇게 하면 큐의 가용량을 초과하게 되는데 이러한 방식을 큐 탄력성이라고 한다.
컨테이너를 선점하기 위해 강제로 죽이는 방법을 사용하지 않으므로(리소스 매니저는 애플리케이션이 컨테이너를 반환하도록 하여 캐퍼시티 스케줄러가 우선권을 선점하게 할 수 있다.) 요청한 가용량에 미달한 큐가 있으면 필요한 요청은 늘어난다.
이때 다른 큐의 컨테이너가 완료되어 자원이 해제된 경우에만 해당 큐에 가용량을 돌려준다.
이때 다른 큐의 가용량을 너무 많이 잡아먹지 않도록 큐에 최대 가용량을 설정하는 방법으로 문제를 해결할 수 있는데 이것이 큐 탄력성의 단점이다.
-> 즉 큐 탄력성의 특성 때문에, 실질적으로 클러스터 내에서 다른 큐의 자원도 할당받게 되어 그 다른 큐의 새로운 잡의 실행에 지장이 생기게 될수도 있는 문제가 발생하는 것이다.
capacity-scheduler.xml파일에서 설정가능하다
각 큐는 yarn.scheduler.capacity.<queue-path>.<sub-property>와 같은 형식의 설정 속성을 정의한 후 설정할 수 있다,.
<queue-path>에는 큐의 계층구조를 정의하면 된다.
<property>
<name>yarn.scheduler.capacity.root.queues</name>
<value>a,b,c</value>
<description>The queues at the this level (root is the root queue).
</description>
</property>
<property>
<name>yarn.scheduler.capacity.root.a.queues</name>
<value>a1,a2</value>
<description>The queues at the this level (root is the root queue).
</description>
</property>
<property>
<name>yarn.scheduler.capacity.root.b.queues</name>
<value>b1,b2,b3</value>
<description>The queues at the this level (root is the root queue).
</description>
</property>
큐배치
애플리케이션을 큐에 배치하는 방법은 애플리케이션의 종류에 따라 달라진다. 큐를 지정하지 않으면 기본큐인 default에 배치된다.
4.3.3 페어 스케줄러 설정
실행중인 모든 애플리케이션에 동일하게 자원을 할당한다.
참고로 큐와 풀은 페어스케줄러에서는 같은 의미이다.
아래의 그림을 살펴보면 페어 스케줄러에서 새로운 잡이 실행될 때 자원을 어떻게 할당받는지를 파악할 수 있다.
페어 스케줄러 활성화
yarn.resourcemanager.scheduler.class 속성에 설정한다.
원하는 스케줄러를 설정하고 싶으면 yarnsite.xml파일의 yarn.resourcemanager.scheduler.class 속성에 스케줄러의 전체 클래스 이름을 org.apache.hadoop.yarn.server.resourcemanager.scheduler.fair.FairScheduler와 같이 지정하면 된다.
큐 설정
클래스경로에 있는 fair-scheduler.xml 이라는 할당 파일에 원하는 속성을 설정한다.
yarn.scheduler.fair.allocation.file 속성을 지정하여 할당 파일의 이름을 지정할 수 있다. 할당 파일을 지정하지 않으면 각 애플리케이션은 해당 사용자 이름의 큐에 배치된다.
캐퍼시티처럼 계층적 큐 설정도 가능하다.
각 큐에 서로 다른 스케줄링 정책을 설정할수도 있다.
기본 정책은 최상단의 defaultQueueSechedulingPolicy 항목에 설정가능. 페어 스케줄러는 큐에 FIFO정책도 지원하고 우성자원 공평성정책도 사용할 수 있다.
특정 큐의 정책은 schedulingPolicy 항목으로 재정의할 수 있다.
할당 파일의 더 자세한 예제는 레퍼런스 참고
<?xml version="1.0"?>
<allocations>
<defaultQueueSchedulingPolicy>fair</defaultQueueSchedulingPolicy>
<queue name="prod">
<weight>40</weight>
<schedulingPolicy>fifo</schedulingPolicy>
</queue>
<queue name="dev">
<weight>60</weight>
<queue name="eng" />
<queue name="science" />
</queue>
<queuePlacementPolicy>
<rule name="specified" create="false" />
<rule name="primaryGroup" create="false" />
<rule name="default" create="dev.eng" />
</queuePlacementPolicy>
</allocations>
큐배치
애플리케이션을 큐에 할당할때 규칙기반 시스템을 이용한다.
<queuePlacementPolicy>
<rule name="specified" create="false" />
<rule name="primaryGroup" create="false" />
<rule name="default" create="dev.eng" />
</queuePlacementPolicy>
queuePlacementPolicy 해당 항목은 규칙목록을 포함. 맞는 규칙이 나올때까지 순서대로 시도한다.
yarn.scheduler.fair.user-as-default-queue 속성을 false로 설정하면 할당 파일을 사용하지 않고도 정책을 지정할 수 있다.
yarn.scheduler.fair.allow-underclared-pools 속성을 false로 설정하면 사용자는 동적으로 큐를 생성할 수 없게된다.
선점
빈 큐에 잡이 제출되더라도 클러스터에서 이미 실행되고 있는 다른 잡이 자원을 해제해주기전까지 잡을 시작할 수 없다.
잡의 시작시간을 어느정도 예측가능하게 만들기 위해 페어스케줄러는 선점이라는 기능을 제공한다.
선점은 스케줄러가 자원의 균등공유에 위배되는 큐에서 실행되는 컨테이너를 죽일수 있도록 허용하는 기능으로, 큐에 할당된 자원은 균등공유 기준을 반드시 따라야 한다.
yarn.scheduler.fair.preemption 속성을 true로 설정하여 전체적으로 활성화
큐가 최소보장 자원을 받지못한채 지정된 최소 공유 선점 타임아웃이 지나면 스케줄러는 다른 컨테이너를 선취할 수 있다.
모든 큐의 기본 타임아웃은 할당파일의 최상위 항목인 defaultMinSharedPreemptionTimeout으로 설정할 수 있으며, 큐를 기준으로 지정하고 싶으면 각 큐의 minSharePreemptionTimeout 항목에 설정하면 된다.
4.3.4 지연 스케줄링
모든 스케줄러는 지역성 요청을 가장 우선시한다.
클러스터에 어떤 애플리케이션이 특정 노드를 요청하면 요청하는 시점에 그 노드에 다른 컨테이너가 실행되고 있을 가능성이 높다. 이런 상황에서는 지역성 요구 수준을 조금 낮춘 후 동일한 랙에 컨테이너를 할당하는 방법도 있다.
하지만 실제로는 조금만 기다리면 요청한 지정 노드에서 컨테이너를 할당받을 수 있는 기회가 급격하게 증가한다. 이런 경우 클러스터의 효율성도 높아지게 된다. 이러한 기능을 지연스케줄링이라고 부른다.
→ 캐퍼시티와 페어 스케줄러는 모두 이러한 기능을 제공하고 있다.
YARN의 모든 노드매니저는 주기적으로 리소스 매니저에 하트비트 요청을 보낸다. 하트비트를 통해 노드 매니저가 실행 중인 컨테이너의 정보와 새로운 컨테이너를 위한 가용한 자원에 대한 정보를 주고 받는다. 하트비트는 애플리케이션이 실행할 컨테이너를 얻을 수 잇는 중요한 스케줄링 기회가된다.
지연 스케줄링을 사용할때 스케줄러는 처음오는 스케줄링 기회를 바로 사용하지는 않는다. 지역성 제약 수준을 낮추기 전에 허용하는 스케줄링 기회의 최대 횟수까지 기다린 후 그 다음에 오는 스케줄링 기회를 잡는다.
yarn.scheduler.capacity.node-locality-delay 속성에 양의 정수를 지정하는 방식으로 설정
4.3.5 우성 자원 공평성
메모리와 같은 단일 유형의 자원을 분배할때는 가용량이나 공평성의 개념을 결정하는 것은 어렵지 않다. 그러나 다수의 자원이 있으면 일이 매우 복잡해진다.
각 사용자의 우세한 자원을 확인한 후 이를 클러스터 사용량의 측정 기준으로 삼는것이다.
예를 들어, 클러스터 전체 CPU는 100개이고, 10TB의 메모리를 가지고 있다. A는 CPU2개와 300GB메모리의 컨테이너를, B는 CPU 6개와, 100GB 메모리의 컨테이너를 각각 요청했다. A의 요청은 전체 클러스터의 2%와 3%이므로, 메모리의 비율이 더 높다. B의 요청은 CPU(6%)가 더 우세하다. B의 요청을 우세자원을 기준으로 비교해보면 A보다 두배나 높다. 따라서 A는 B의 절반에 해당하는 자원을 할당 받는다.
기본적으로 해당 기능은 비활성화되어있고 자원을 계산할때는 CPU는 무시되고 메모리만 고려된다.
이 기능을 활성화하기 위해서는 capacityscheduler.xml 파일에 있는 yarn.scheduler.capacity.resource-calculator 속성에 org.apache.hadoop.yarn.uril.resource.DominateResourceCalculator를 지정하면 활성화된다.
Reference
'WIR(What I Read)' 카테고리의 다른 글
[데이터 중심 애플리케이션 설계] CH 01. 신뢰할 수 있고 확장 가능하며 유지보수하기 쉬운 애플리케이션 (0) | 2023.03.21 |
---|---|
[하둡 완벽 가이드]Ch07. 맵리듀스 작동방법 (0) | 2022.10.23 |
[하둡 완벽 가이드]Ch03. 하둡분산 파일 시스템 (0) | 2022.10.04 |
[하둡 완벽 가이드]Ch01. 하둡과의 만남 & Ch02. 맵리듀스 (5) | 2022.09.20 |
[빅데이터를 지탱하는 기술] CH 06. 실습 (0) | 2022.03.27 |