- Published on
EMR YARN Node Label Expression — CORE·TASK와 Distributed·Centralized 모드
- Authors

- Name
- 이동영
- Github
- @Github
아래 사례에서 기록된 관찰은 Core에 AM과 Executor가 몰리고 Task에 여유가 있었다는 것이다. 당시 릴리스·라벨 배타성·Queue 기본값·수정 후 측정값이 확보되지 않아 원인과 개선 효과는 미확정이다.
들어가며
Amazon EMR 클러스터는 일반적으로 Core 노드와 Task 노드를 함께 사용한다. 두 노드는 모두 Spark Executor를 실행할 수 있지만 운영 특성은 다르다.
- Core 노드는 HDFS DataNode와 YARN NodeManager를 함께 실행한다.
- Task 노드는 HDFS 데이터를 저장하지 않고 계산 작업만 수행한다.
- 비용 절감을 위해 Task 노드를 Spot 인스턴스로 구성하는 경우가 많다.
Spark ApplicationMaster가 Spot Task 노드에서 실행되다가 해당 인스턴스가 종료되면 애플리케이션 전체가 실패할 수 있다.
EMR은 이런 위험을 줄이기 위해 YARN Node Label을 사용하여 ApplicationMaster를 CORE 파티션에 배치할 수 있다.
실제로 AM의 기본 Expression만 CORE로 지정하고 Executor의 Expression은 별도로 지정하지 않은 환경에서, AM과 Executor가 모두 Core 노드에 몰리는 현상을 겪었다.
Task 노드에는 메모리가 남아 있었지만 Core 노드에는 새 AM을 실행할 메모리가 부족했다.
이 글에서는 라벨 설정을 설명한 뒤, 이 사례에서 AM 배치 제한과 Executor 배치 정책을 왜 따로 확인해야 하는지 다룬다.
YARN Node Label과 Node Label Expression
YARN Node Label은 비슷한 특성을 가진 노드를 하나의 파티션으로 묶는 기능이다.
현재 YARN의 노드 파티션 모델에서는 한 노드가 하나의 파티션에 속하며, 라벨이 없는 노드는 DEFAULT 파티션에 속한다.
Node Label을 사용할 때는 다음 네 가지 설정을 따로 생각해야 한다.
| 구분 | 역할 | 대표 설정 또는 명령 |
|---|---|---|
| 라벨 등록 | 클러스터에서 사용할 파티션 이름을 생성 | yarn rmadmin -addToClusterNodeLabels |
| 노드 매핑 | 각 NodeManager를 특정 라벨에 연결 | -replaceLabelsOnNode 또는 NodeManager provider |
| Queue 권한 | Queue가 특정 라벨 파티션을 사용할 수 있게 허용 | accessible-node-labels |
| 리소스 요청 | AM 또는 Executor가 실행될 파티션을 지정 | Node Label Expression |
라벨을 등록했다고 노드에 자동으로 연결되는 것은 아니다. 반대로 노드가 라벨을 보고하더라도 ResourceManager의 유효한 클러스터 라벨 목록과 Queue 권한이 준비되지 않으면 해당 파티션을 정상적으로 사용할 수 없다.
Exclusive와 Non-exclusive
Node Label을 등록할 때 exclusive 속성을 지정할 수 있다.
| 설정 | 동작 |
|---|---|
exclusive=true | 같은 라벨을 요청한 컨테이너만 해당 파티션에 배치된다. 기본값이다. |
exclusive=false | 라벨 요청이 없는 컨테이너도 해당 파티션의 유휴 리소스를 사용할 수 있다. |
예를 들어 CORE(exclusive=true)라면 CORE를 요청한 AM은 Core 노드에서 실행되지만, 라벨을 요청하지 않은 Executor는 Core 노드를 사용할 수 없다.
Core 노드의 유휴 CPU와 메모리까지 Executor가 사용해야 한다면 라벨의 배타성과 Executor Expression을 함께 검토해야 한다.
EMR에서 CORE와 TASK가 의미하는 것
Amazon EMR 5.19.0 이상은 Apache Hadoop에 내장된 YARN Node Label 기능을 사용한다.
EMR의 대표적인 구성은 Core 노드에 CORE 라벨을 지정하고 ApplicationMaster의 기본 Expression을 CORE로 설정하는 방식이다.
Core 노드: CORE 파티션
Task 노드: 라벨 없음, 즉 DEFAULT 파티션
ApplicationMaster 요청: CORE
Executor 요청: 라벨 없음
이 구성에서는 수명이 긴 ApplicationMaster를 Core 노드에 두고, Queue의 기본 Expression이 비어 있다면 Executor는 DEFAULT 파티션을 요청한다.
다만 CORE가 non-exclusive이면 이 요청도 Core의 유휴 자원을 사용할 수 있어, Executor가 Task 노드에서만 실행된다는 뜻은 아니다.
AWS가 안내하는 EMR 구성은 CORE(exclusive=false)이며, AM 외 컨테이너는 Core와 Task 모두에 배치될 수 있다. AWS의 EMR YARN 라벨 설정 안내
[!IMPORTANT] 일반적인 EMR 구성에서 Task 노드는
TASK라는 YARN 라벨을 받지 않는다. AWS 공식 문서도 EMR이 Task 노드에 라벨을 지정하지 않으므로 애플리케이션 프로세스를TASK라벨로 제한할 수 없다고 설명한다. YARN UI에CORE만 보이고 Task 노드가 빈 라벨로 표시되는 것은 정상일 수 있다.
Task 노드에 TASK 라벨을 붙일 때의 장단점
Task 노드에 명시적인 TASK 라벨을 붙이면 Core와 Task를 서로 다른 YARN 파티션으로 완전히 분리할 수 있다.
이 방식은 배치 위치를 강하게 통제해야 할 때 유용하지만, EMR의 일반적인 CORE + DEFAULT 구성보다 운영해야 할 설정이 많다.
장점
| 장점 | 설명 |
|---|---|
| Executor 격리 | spark.yarn.executor.nodeLabelExpression=TASK로 Executor가 계산 전용 Task 노드에서만 실행되도록 강제할 수 있다. |
| Core 노드 보호 | 큰 Executor나 공격적인 동적 할당이 HDFS를 담당하는 Core 노드의 CPU와 메모리를 잠식하는 것을 막을 수 있다. |
| 비용 정책 분리 | Task 노드를 Spot으로 구성한 경우 재시도 가능한 연산 컨테이너를 비용이 낮은 노드에 모을 수 있다. |
| Queue별 용량 통제 | Capacity Scheduler에서 TASK 파티션의 capacity와 maximum-capacity를 Queue별로 따로 지정할 수 있다. |
| 전용 하드웨어 활용 | 메모리 최적화 인스턴스나 특정 아키텍처처럼 Task 그룹의 특성이 뚜렷할 때 대상 워크로드만 보낼 수 있다. |
| 관측성 향상 | YARN Node Labels와 Scheduler 화면에서 Core·Task 파티션의 수요와 사용량을 구분해 볼 수 있다. |
단점
| 단점 | 설명 |
|---|---|
| 리소스 단편화 | TASK가 exclusive이면 Task 파티션에 여유가 있어도 라벨 없는 요청은 그 자원을 사용할 수 없다. 반대로 Executor를 TASK로 고정하면 유휴 Core 자원으로 확장할 수 없다. |
| Task 부족 시 대기 | Task 노드가 0개이거나 Scale-up이 늦으면 Core 노드에 여유가 있어도 Executor가 계속 pending 상태로 남는다. |
| 설정 범위 증가 | 라벨 등록, 노드 매핑, Queue 접근 권한, 파티션 capacity, Spark Expression을 모두 맞춰야 한다. |
| 자동 확장 관리 | Centralized 모드에서는 새 Task 호스트가 생길 때마다 매핑이 필요하다. Distributed 모드에서도 새 노드가 정확한 provider 설정을 받아야 한다. |
| EMR 관리 기능과 충돌 가능성 | Managed Scaling이 관리하는 라벨을 실행 중에 수동으로 추가하거나 변경하는 방식은 지원되지 않는다. 릴리스와 Scaling 정책에 맞는 구성이 필요하다. |
| 라벨 축 선택 제한 | YARN 노드는 하나의 파티션에만 속하므로 TASK와 SPOT처럼 노드 유형과 시장 유형을 독립 라벨로 동시에 표현할 수 없다. 어떤 기준으로 격리할지 선택해야 한다. |
| 장애 가능 지점 증가 | 라벨 오타, Queue 권한 누락, 잘못된 exclusive 설정 하나만으로도 사용 가능한 인스턴스가 있는데 컨테이너가 생성되지 않는 문제가 생긴다. |
TASK 라벨이 잘 맞는 경우는 Core 노드의 HDFS 안정성을 강하게 보호해야 하거나, 계산 전용 인스턴스에만 Executor를 배치해야 하거나, Queue별 Task 용량을 명확하게 나눠야 하는 환경이다.
단순히 Spot Task 노드 종료로부터 ApplicationMaster를 보호하는 목적이라면 Task 노드를 무라벨 DEFAULT 파티션으로 유지하고 AM에만 CORE Expression을 적용하는 구성이 더 단순하다.
이 경우 Queue의 기본 Expression이 비어 있는지 확인하고 spark.yarn.executor.nodeLabelExpression을 생략한다. CORE가 non-exclusive이면 Executor의 Core 사용까지 차단하지는 않는다.
[!TIP] Task 노드의 남는 리소스를 다른 무라벨 워크로드에도 제공해야 한다면
TASK(exclusive=false)를 검토할 수 있다. 다만 이 설정은 “Task 노드는 TASK 요청만 받는다”는 강한 격리를 완화하므로, 격리와 활용률 중 어느 쪽이 우선인지 먼저 정해야 한다.
EMR 릴리스별 차이
| EMR 릴리스 | 주요 동작 |
|---|---|
| 5.19.0 이상 | EMR 전용 패치 대신 YARN 내장 Node Label 기능을 사용한다. |
| 6.x | Node Label 기능이 기본적으로 비활성화되어 있다. 활성화 설정이 필요하다. |
| 7.x | 노드 유형 외에 ON_DEMAND, SPOT 같은 시장 유형을 기준으로도 배치를 제한할 수 있다. |
| 7.2 이상 | Managed Scaling이 AM 수요와 Executor 수요를 구분해 Core·Task 또는 On-Demand·Spot 용량을 조정할 수 있다. |
EMR 6.x에서 ApplicationMaster를 Core 노드로 제한하려면 최소한 다음 속성을 활성화해야 한다.
<property>
<name>yarn.node-labels.enabled</name>
<value>true</value>
</property>
<property>
<name>yarn.node-labels.am.default-node-label-expression</name>
<value>CORE</value>
</property>
EMR의 전체 구성에는 라벨 저장소, 관리 모드, NodeManager provider, Capacity Scheduler의 라벨 접근 권한도 포함된다. 관련 속성을 일부만 덮어쓰면 EMR이 제공하는 AM 보호 동작이 달라질 수 있으므로 실제 릴리스의 기본 설정을 먼저 확인해야 한다.
Distributed 모드
distributed는 각 NodeManager가 자신의 라벨을 결정하고 ResourceManager에 보고하는 방식이다.
NodeManager는 고정 설정, 스크립트 또는 사용자 정의 provider를 사용할 수 있다.
<!-- ResourceManager가 읽는 공통 yarn-site.xml -->
<property>
<name>yarn.node-labels.enabled</name>
<value>true</value>
</property>
<property>
<name>yarn.node-labels.configuration-type</name>
<value>distributed</value>
</property>
<property>
<name>yarn.node-labels.fs-store.root-dir</name>
<value>/apps/yarn/nodelabels</value>
</property>
Core NodeManager가 CORE 라벨을 보고하도록 하는 설정은 다음과 같다.
<!-- Core 노드의 yarn-site.xml -->
<property>
<name>yarn.nodemanager.node-labels.provider</name>
<value>config</value>
</property>
<property>
<name>yarn.nodemanager.node-labels.provider.configured-node-partition</name>
<value>CORE</value>
</property>
Task 노드에는 위의 configured-node-partition=CORE 설정을 적용하지 않는다.
Task 노드까지 같은 설정을 받으면 모든 NodeManager가 자신을 CORE로 보고해 파티션 분리가 무너진다.
직접 TASK 파티션을 운영하는 구성이라면 Task NodeManager에는 다음 설정을 적용한다.
이는 Task를 무라벨로 두는 EMR 기본 구성과는 다른 예시이며, TASK 라벨 등록과 Queue 설정이 먼저 준비되어 있어야 한다.
<!-- 명시적인 TASK 파티션을 사용하는 Task 노드의 yarn-site.xml -->
<property>
<name>yarn.nodemanager.node-labels.provider</name>
<value>config</value>
</property>
<property>
<name>yarn.nodemanager.node-labels.provider.configured-node-partition</name>
<value>TASK</value>
</property>
Core와 Task의 provider 설정은 노드 역할에 맞춰 따로 배포해야 한다. 새 Task 노드가 추가될 때도 같은 설정을 받도록 해야 하며, EMR이 제공하는 provider를 사용하는 환경에서는 실제 릴리스의 구성을 확인한 뒤 적용한다.
노드 속성이 자주 달라진다면 script provider를 사용할 수도 있다.
스크립트는 다음과 같은 형식으로 라벨을 출력한다.
#!/usr/bin/env bash
printf '%s\n' 'NODE_PARTITION:CORE'
<property>
<name>yarn.nodemanager.node-labels.provider</name>
<value>script</value>
</property>
<property>
<name>yarn.nodemanager.node-labels.provider.script.path</name>
<value>/etc/hadoop/conf/node-label-provider.sh</value>
</property>
Distributed 모드는 노드가 추가되거나 교체될 때 provider가 라벨을 다시 보고하므로 동적으로 확장되는 클러스터에 적합하다. EMR의 Core 노드 보호 구성도 이 방식을 사용한다.
Centralized 모드
centralized는 ResourceManager 관리자가 CLI, REST 또는 RPC로 노드와 라벨의 매핑을 직접 관리하는 방식이다.
별도 설정을 하지 않으면 YARN Node Label의 기본 관리 방식은 centralized다.
<property>
<name>yarn.node-labels.enabled</name>
<value>true</value>
</property>
<property>
<name>yarn.node-labels.configuration-type</name>
<value>centralized</value>
</property>
Centralized 모드에서는 먼저 라벨 이름을 클러스터에 등록하고, 그다음 각 노드에 라벨을 매핑한다.
# 1. 클러스터 라벨 등록
yarn rmadmin -addToClusterNodeLabels \
'CORE(exclusive=true),TASK(exclusive=true)'
# 2. 등록 결과 확인
yarn cluster --list-node-labels
# 3. 현재 NodeManager 이름 확인
yarn node -list -all
# 4. 노드와 라벨 매핑
yarn rmadmin -replaceLabelsOnNode \
'core-host-1=CORE core-host-2=CORE task-host-1=TASK' \
-failOnUnknownNodes
NodeManager 포트를 생략하면 해당 호스트에서 실행되는 모든 NodeManager에 라벨을 적용한다.
포트까지 구분해야 한다면 host:port=LABEL 형식을 사용한다.
Centralized 모드는 매핑이 명확하고 관리자가 즉시 수정할 수 있지만, Auto Scaling으로 노드가 자주 교체되는 환경에서는 새 호스트를 계속 매핑해야 한다. 따라서 동적인 EMR 클러스터에서는 일반적으로 distributed provider가 더 자연스럽다.
[!WARNING] Managed Scaling을 사용하는 EMR에서는 AWS가 클러스터 생성 및 프로비저닝 과정에서 지원되는 라벨을 만든다. AWS는 실행 중인 클러스터를 재구성하여 라벨을 추가하거나 Managed Scaling 설정 후 라벨을 수정하는 방식을 지원하지 않는다.
TASK라벨을 수동으로 추가하는 예시는 일반 YARN의 centralized 동작을 설명하기 위한 것이며, EMR Managed Scaling의 기본 구성을 그대로 나타내지 않는다.
addToClusterNodeLabels 명령의 정확한 역할
명령 이름의 정확한 철자는 addToClusterNodeLabels다.
yarn rmadmin -addToClusterNodeLabels \
'CORE(exclusive=true),TASK(exclusive=false)'
이 명령은 ResourceManager의 유효한 클러스터 라벨 목록에 CORE와 TASK를 추가한다.
노드를 라벨에 연결하는 명령은 아니다.
| 작업 | 명령 |
|---|---|
| 라벨 등록 | yarn rmadmin -addToClusterNodeLabels 'CORE,TASK' |
| 라벨 목록 조회 | yarn cluster --list-node-labels |
| 노드 매핑 | yarn rmadmin -replaceLabelsOnNode 'host1=CORE' |
| 특정 노드 확인 | yarn node -status <NodeId> |
| 라벨 삭제 | yarn rmadmin -removeFromClusterNodeLabels 'TASK' |
exclusive를 생략하면 기본값은 true다.
이미 Queue가 사용하는 라벨은 먼저 Queue 설정에서 연결을 제거하지 않으면 삭제할 수 없다.
Distributed 모드에서도 NodeManager가 보고할 라벨은 ResourceManager가 알고 있는 유효한 라벨이어야 한다.
다만 EMR이 관리하는 기본 CORE 라벨은 EMR의 프로비저닝 과정에서 준비되므로, 정상 구성에 같은 명령을 반복해서 실행할 필요는 없다.
두 모드에서 라벨 등록과 매핑을 구분하기
| 구분 | Distributed | Centralized |
|---|---|---|
| 클러스터 라벨 등록 | addToClusterNodeLabels 또는 EMR 프로비저닝 | addToClusterNodeLabels 또는 EMR 프로비저닝 |
| Core·Task 노드 매핑 | 각 NodeManager의 provider가 CORE 또는 TASK를 보고 | 관리자가 replaceLabelsOnNode로 호스트별 라벨 지정 |
| 새 노드 추가 시 | 역할에 맞는 provider 설정을 받아야 함 | 새 호스트의 매핑을 등록해야 함 |
| 매핑 결과 확인 | yarn node -status <NodeId> | yarn node -status <NodeId> |
즉, addToClusterNodeLabels는 centralized 전용 명령이 아니다.
두 모드 모두 ResourceManager에 유효한 라벨이 등록되어 있어야 하며, 차이는 노드와 라벨의 매핑을 누가 보고하는가에 있다.
등록 명령의 구문과 모드별 매핑 방식은 Hadoop 공식 Node Labels 문서를 기준으로 확인했다.
Capacity Scheduler에서 라벨 파티션 열기
노드 매핑이 끝나도 Queue가 해당 라벨에 접근할 수 없으면 컨테이너가 배치되지 않는다. Capacity Scheduler에서는 Queue별 접근 권한과 파티션 용량을 설정해야 한다.
<property>
<name>yarn.scheduler.capacity.root.accessible-node-labels</name>
<value>*</value>
</property>
<property>
<name>yarn.scheduler.capacity.root.accessible-node-labels.CORE.capacity</name>
<value>100</value>
</property>
<property>
<name>yarn.scheduler.capacity.root.default.accessible-node-labels</name>
<value>*</value>
</property>
<property>
<name>yarn.scheduler.capacity.root.default.accessible-node-labels.CORE.capacity</name>
<value>100</value>
</property>
위 예시는 CORE 파티션의 용량만 설정한다.
TASK를 별도 파티션으로 등록하고 Executor가 사용하도록 구성했다면 TASK 용량도 지정해야 한다.
다음은 root.default 하나가 각 라벨 파티션의 용량을 모두 사용하는 단일 Queue 구성에서 추가할 설정이다.
여러 Queue가 있다면 각 부모 아래 자식 Queue들의 파티션별 capacity 합이 100이 되도록 나눈다.
<property>
<name>yarn.scheduler.capacity.root.accessible-node-labels.TASK.capacity</name>
<value>100</value>
</property>
<property>
<name>yarn.scheduler.capacity.root.default.accessible-node-labels.TASK.capacity</name>
<value>100</value>
</property>
위 설정은 앞 예시의 accessible-node-labels=*와 함께 사용한다. 접근 라벨을 열거하는 구성이라면 부모와 제출 Queue 모두에서 TASK 접근이 허용되는지도 확인한다.
Task 노드가 무라벨인 구성에는 이 TASK 파티션 설정을 추가하지 않는다.
Queue 설정을 변경했다면 다음 명령으로 갱신한다.
yarn rmadmin -refreshQueues
accessible-node-labels는 접근 가능 여부를 정하고, accessible-node-labels.<LABEL>.capacity는 해당 파티션에서 Queue가 보장받는 비율을 정한다.
두 설정 중 하나라도 빠지면 “노드는 남는데 컨테이너가 할당되지 않는” 상황이 생길 수 있다.
Spark에서 AM과 Executor 배치하기
Spark on YARN은 AM과 Executor에 서로 다른 Node Label Expression을 지정할 수 있다.
spark-submit \
--master yarn \
--deploy-mode cluster \
--conf spark.yarn.am.nodeLabelExpression=CORE \
--conf spark.yarn.executor.nodeLabelExpression=TASK \
application.jar
| Spark 설정 | 대상 |
|---|---|
spark.yarn.am.nodeLabelExpression | YARN ApplicationMaster가 실행될 파티션 |
spark.yarn.executor.nodeLabelExpression | Spark Executor가 실행될 파티션 |
EMR의 일반적인 CORE + DEFAULT 구성에서는 TASK 라벨이 없으므로 Executor Expression을 TASK로 지정하면 Executor가 뜨지 않는다.
이때는 Queue의 기본 Expression이 비어 있는지 확인한 뒤 Executor Expression을 생략해 기본 파티션을 사용한다.
spark-submit \
--master yarn \
--deploy-mode cluster \
--conf spark.yarn.am.nodeLabelExpression=CORE \
application.jar
cluster 배포 모드에서는 Spark Driver가 ApplicationMaster 프로세스 안에서 실행되므로 CORE 배치가 Driver도 보호한다.
client 배포 모드에서는 Driver가 spark-submit을 실행한 클라이언트에 있고, YARN의 AM Expression은 YARN ApplicationMaster 컨테이너에만 적용된다.
[!IMPORTANT] YARN의
distributed·centralized는 노드와 라벨을 누가 매핑하는지에 관한 설정이다. Spark의cluster·client는 Driver가 어디에서 실행되는지에 관한 배포 모드다. 이름이 비슷해 보여도 서로 다른 축이다.
운영 사례: Task 메모리는 남는데 Core에 새 AM을 띄울 수 없었다
당시 설정과 관찰한 현상
AM을 Core에 두기 위해 다음 설정을 사용했다. Executor의 Node Label Expression은 TASK로 지정하지 않은 상태였다.
# yarn-site의 AM 기본 배치 설정
yarn.node-labels.am.default-node-label-expression=CORE
# spark.yarn.executor.nodeLabelExpression은 미지정
관찰한 결과는 AM과 Executor가 모두 Core 노드에서 실행되고, Task 노드의 메모리는 남는 것이었다. Core의 자원을 Executor까지 함께 사용하면서 새로운 AM을 할당할 메모리가 부족해졌다.
| 구분 | 관찰한 상태 | 영향 |
|---|---|---|
| Core 노드 | AM과 Executor가 함께 배치됨 | 새 AM을 위한 메모리 부족 |
| Task 노드 | 메모리가 남아 있음 | 남는 자원이 AM 실행으로 이어지지 않음 |
| 클러스터 전체 | 유휴 메모리가 존재함 | 전체 가용량만으로는 AM 배치 가능 여부를 판단하기 어려움 |
AM은 CORE를 요청하므로 Task의 남는 메모리로 대신 실행할 수 없다.
이미 실행 중인 Executor가 Core 자원을 차지하고 있다면 Task 노드를 늘리는 것만으로 그 자원이 즉시 반환되는 것도 아니다.
AM을 CORE로 제한해도 Executor가 TASK로 분리되는 것은 아니다
이 사례에서 구분해야 할 것은 AM의 실행 위치를 제한하는 설정과 Executor가 사용할 파티션을 정하는 설정이다.
yarn.node-labels.am.default-node-label-expression=CORE는 AM의 기본 배치를 정한다. 이 속성 하나로 Executor까지 CORE를 요청하게 된다고 해석해서는 안 된다.
Spark도 AM과 Executor의 Expression을 별도 속성으로 제공한다. Spark의 YARN 배치 설정
Executor Expression을 생략했을 때는 Queue의 기본 Expression과 파티션의 배타성까지 봐야 한다.
| 확인할 설정 | 해당 조건에서의 동작 |
|---|---|
Queue의 default-node-label-expression=CORE | 별도 라벨이 없는 요청이 Queue 기본값인 CORE를 사용할 수 있다. |
Queue 기본값이 비어 있고 CORE(exclusive=false) | 기본 파티션을 요청한 Executor도 Core의 유휴 자원을 사용할 수 있다. AM 전용 메모리를 예약하는 설정은 아니다. |
Task가 TASK(exclusive=true)로 매핑되어 있음 | TASK를 요청하지 않은 Executor는 이 파티션에 들어갈 수 없다. |
Task가 무라벨 DEFAULT이고 Queue 기본값도 비어 있음 | Executor Expression을 생략해도 Task를 사용할 수 있다. Core에만 몰렸다면 다른 배치 제약도 확인해야 한다. |
Queue 기본 Expression과 non-exclusive 파티션의 동작은 Hadoop Node Labels 문서에 설명되어 있다.
예를 들어 **Core는 non-exclusive, Task는 exclusive인 별도 TASK 파티션, Executor 요청은 DEFAULT**인 조합이라면 Task를 쓰지 못하면서 Core를 사용하는 상황을 설명할 수 있다. 이는 당시 설정이 확인되기 전까지는 가능한 원인이다.
[!IMPORTANT] 여기서 확인된 경험은 “Executor Expression을 지정하지 않은 환경에서 AM과 Executor가 Core에 몰렸다”는 것이다. “미지정이면 항상 Core로 간다”는 일반 규칙은 아니다. 실제 원인을 확정하려면 당시 라벨 매핑·exclusive 값·Queue 기본값·최종 Spark 설정을 함께 확인해야 한다.
원인을 좁히는 확인 순서
yarn cluster --list-node-labels와yarn node -status <NodeId>로 Task가 무라벨인지 실제TASK파티션인지, Core·Task의 exclusive 값이 무엇인지 확인한다.- 제출 Queue의
yarn.scheduler.capacity.<queue-path>.default-node-label-expression, 라벨 접근 권한과 파티션 capacity를 확인한다. 상위 Queue에서 적용되는 값도 함께 본다. spark-defaults.conf, 제출 옵션, Livy 세션 설정 등에서 최종spark.yarn.executor.nodeLabelExpression을 확인한다. 제출 명령에 없는 값도 공통 설정에 들어 있을 수 있다.- ResourceManager의 노드별 컨테이너 목록과 Spark UI의 Executors 화면을 대조해 Core 메모리 중 AM과 Executor가 각각 얼마나 할당받았는지 확인한다.
- Task가 YARN에 정상 등록되어 있는지, Executor 한 개의 메모리·vcore 요청을 수용할 수 있는지 확인한다. OS의 빈 메모리와 YARN이 할당할 수 있는 메모리는 구분한다.
새 AM이 시작되지 않을 때는 Core의 가용 자원 부족과 Queue의 maximum-am-resource-percent 한도 도달도 구분해야 한다.
AM 비율 한도를 올리더라도 이미 Executor에 할당된 메모리가 반환되지는 않는다.
Cluster 모드에서는 Driver 메모리와 overhead를 포함한 AM 컨테이너가 Core 노드 한 대에 들어갈 수 있어야 한다. 자세한 계산은 ApplicationMaster 메모리와 대기 진단 글에서 다룬다.
배치 정책에 따라 수정 방향을 나눈다
실제로 TASK 라벨을 구성한 환경에서 Executor를 Task로 격리하려면 다음과 같이 각각 지정한다.
이 예시는 CORE·TASK 매핑과 제출 Queue의 접근 권한·파티션 용량이 준비된 경우에 사용한다.
# application.py는 실행할 애플리케이션 파일로 교체한다.
spark-submit \
--master yarn \
--deploy-mode cluster \
--conf spark.yarn.am.nodeLabelExpression=CORE \
--conf spark.yarn.executor.nodeLabelExpression=TASK \
application.py
이렇게 제출한 애플리케이션은 AM은 Core, Executor는 Task를 요청한다. Task 자원이 부족하면 Executor가 기다리므로, Task 용량과 확장 시간도 함께 고려해야 한다. 설정 변경만으로 기존 애플리케이션의 Executor가 자동 이동하는 것으로 보아서는 안 되며, 새 애플리케이션이나 새 Livy 세션으로 제출해 배치를 검증한다.
Task가 무라벨인 EMR 구성에서는 TASK라는 이름만 설정하지 않는다.
Queue 기본 Expression이 의도치 않게 CORE로 지정되어 있다면 기본 파티션을 사용할 수 있도록 바로잡고, Executor의 명시적인 CORE 제한도 확인한다.
다만 CORE(exclusive=false)가 유지되면 Core와 Task 양쪽에서 Executor가 실행될 수 있다. Task 활용을 허용하는 것과 Core를 AM 전용으로 격리하는 것은 서로 다른 목표다.
엄격한 격리가 필요하면 앞에서 설명한 exclusive 설정과 파티션 구성을 검토하되, EMR 릴리스와 Managed Scaling이 지원하는 범위 안에서 설계한다.
이 경험에서 확인한 점은 클러스터 전체의 빈 메모리보다 AM이 배치될 수 있는 Core 노드에 실제로 남아 있는 자원이 중요하다는 것이다. AM을 Core에 고정했다면 Executor가 같은 자원을 얼마나 사용하는지까지 함께 봐야 한다.
자주 발생하는 문제와 확인 순서
라벨은 보이는데 연결된 노드가 0개다
addToClusterNodeLabels는 이름만 등록한다.
Centralized 모드라면 replaceLabelsOnNode를 실행하고, distributed 모드라면 각 NodeManager의 provider 설정과 로그를 확인한다.
AM이 ACCEPTED 상태에서 계속 기다린다
다음을 순서대로 확인한다.
- 실제로
CORE라벨을 가진 활성 NodeManager가 있는가 - 제출한 Queue가
CORE에 접근할 수 있는가 CORE파티션의 Queue capacity가 0보다 큰가maximum-am-resource-percent한도에 도달하지 않았는가- Expression의 대소문자와 라벨 이름이 정확한가
Executor가 하나도 생성되지 않는다
EMR Task 노드를 TASK 라벨 파티션이라고 가정하고 spark.yarn.executor.nodeLabelExpression=TASK를 설정했는지 확인한다.
YARN Nodes 화면에서 Task 노드가 무라벨이라면 Executor Expression을 제거하여 DEFAULT 파티션을 요청해야 한다.
설정은 맞지만 Managed Scaling이 기대와 다르게 움직인다
EMR 7.2 이상에서 Node Label과 Managed Scaling을 함께 사용하면 AM 수요와 Executor 수요에 따라 Core와 Task를 독립적으로 확장할 수 있다.
여러 애플리케이션을 병렬로 실행한다면 AWS는 yarn.scheduler.capacity.maximum-am-resource-percent를 1로 설정할 것을 안내한다.
또한 Core 축소 시 HDFS 안정성과 ApplicationMaster의 수명을 함께 고려해야 한다.
확인 명령과 UI
# 유효한 클러스터 라벨과 exclusive 속성
yarn cluster --list-node-labels
# 활성 NodeManager 목록
yarn node -list -all
# 개별 NodeManager의 라벨
yarn node -status <NodeId>
ResourceManager UI에서도 다음 화면을 확인할 수 있다.
/cluster/nodes: 노드별 라벨/cluster/nodelabels: 파티션별 활성 NodeManager와 전체 리소스/cluster/scheduler: Queue별 라벨 접근 권한과 파티션 사용량
결론
EMR에서 Node Label Expression을 사용할 때 핵심은 CORE와 TASK를 단순한 EC2 역할 이름으로만 보지 않는 것이다.
YARN 스케줄러 관점에서는 실제로 등록되고 노드에 매핑된 파티션 이름이어야 한다.
EMR의 일반적인 보호 구성은 Core 노드에만 CORE를 붙이고 Task 노드는 DEFAULT 파티션에 두며, ApplicationMaster만 CORE로 제한한다.
직접 TASK 라벨을 만들어 Executor를 분리하려면 라벨 등록, 노드 매핑, Queue 권한, Spark Expression을 모두 일관되게 구성해야 한다.
운영 전에는 다음 항목을 확인한다.
- EMR 릴리스에서 Node Label이 기본 활성화되어 있는가
- 클러스터 라벨과 실제 노드 매핑이 모두 존재하는가
- Queue가 해당 라벨 파티션에 접근할 수 있는가
- AM과 Executor가 요청하는 Expression이 실제 파티션 구조와 일치하는가
- Managed Scaling이 수동 라벨 변경을 지원하는 구성인가
참고 자료
- Amazon EMR 노드 유형과 Task 노드 Spot 종료 보호 설정
- Amazon EMR Managed Scaling 사용 시 Node Label 고려사항
- Amazon EMR Managed Scaling의 Core·Task 할당 시나리오
- Apache Hadoop YARN Node Labels
- Apache Spark on YARN 설정