Apache Ambari Hadoop서비스에서 겪었던 문제 & 해결 review - Heap 메모리 부족
지난 인프라 구조는 다음과 같았습니다.
- Bastion Host 구조
- Namenode 1대
- 12대의 datanode
해당 인프라 구조에서 주로 2개의 게임 서비스(Elyon, TERA)를 운영하였고 평균 쿼리 사이즈가 1GB를 상회했었습니다.

( 그림1. Bastion Host - Apache Ambari Hadoop Ecosystem Architecture )
그러나 해당 인프라를 운영하면서 유독 Heap 메모리 부족으로 많은 인프라 장애를 앓고 있었습니다. 관련 유력 원인은 다음과 같습니다.
- YARN NodeManager/ResourceManager 메모리 부족
- 컨테이너 할당이 물리 메모리를 초과할 때
- yarn.nodemanager.resource.memory-mb 설정이 실제 가용 메모리보다 클 때
- Java heap이 작은데 많은 애플리케이션이 동시 실행될 때
- MapReduce Job의 메모리 설정 문제
- Map/Reduce task의 heap size가 너무 작게 설정 (mapreduce.map.java.opts, mapreduce.reduce.java.opts)
- 대용량 데이터 처리 시 메모리 버퍼 부족
- Shuffle 단계에서 메모리 초과
- HBase RegionServer OOM
- MemStore 크기 설정이 부적절할 때
- BlockCache와 MemStore 합이 heap의 80%를 초과할 때
- 대량의 동시 요청 처리 시
- Hive/Tez 실행 엔진
- Tez AM (Application Master) heap 부족
- 복잡한 쿼리의 실행 계획 생성 시
- 조인이나 집계 연산의 중간 결과가 메모리에 쌓일 때
그러나 당시 상황 로그 분석 및 자료들 분석 결과, 1GB 정도 쿼리를 돌리는 환경에서 YARN 메모리 부족이 자주 발생했다면, 전형적인 메모리 오버커밋(over-commit) 문제였을 가능성이 높습니다.
당시 상황 분석
xlarge 인스턴스 (보통 4 vCPU, 16GB RAM 기준)
- 실제 가용 메모리: ~14GB (OS, 데몬 제외)
- DataNode가 사용: ~2GB
- NodeManager가 컨테이너에 할당 가능: 이론상 ~12GB
문제 발생 시나리오:
yarn.nodemanager.resource.memory-mb = 12288 (12GB)
mapreduce.map.memory.mb = 2048 (2GB)
mapreduce.reduce.memory.mb = 4096 (4GB)
→ Map task 6개 or Reduce task 3개까지만 가능
→ 하지만 Java heap + off-heap 메모리가 실제로는 더 사용됨
1GB 쿼리에서 왜 문제가?
Multiple Map tasks 동시 실행
1GB 데이터 → HDFS block 단위(128MB)로 나뉨 → 약 8개 Map task 각 Map task가 2GB 메모리 요청 노드당 6개만 가능한데 8개가 스케줄링되면 대기/재시도
Reduce 단계의 메모리 압박
Shuffle/Sort 단계에서 메모리 버퍼 사용
mapreduce.reduce.shuffle.memory.limit.percent (기본 0.25)
4GB reduce task의 경우 실제 heap 3GB + shuffle buffer 1GB = 실제 4GB+ 사용
Container 메모리 vs Java Heap 불일치
mapreduce.map.memory.mb = 2048
mapreduce.map.java.opts = -Xmx1638m (80% 권장)
→ 나머지 400MB는 off-heap, overhead
→ 실제로는 2GB 이상 사용하는 경우 발생
전형적인 에러 로그
Container killed by YARN for exceeding memory limits.
2.1 GB of 2 GB physical memory used.
당시 해결 방법들
즉시 조치:
yarn.nodemanager.resource.memory-mb를 10GB로 축소yarn.nodemanager.vmem-check-enabled=false(임시 우회)
근본적 해결:
- Map/Reduce task 메모리를 더 여유있게 (2GB → 3GB)
- 동시 실행 task 수 제한
- DataNode heap 메모리 최적화 (불필요하게 크면 줄임)
위의 근본적 해결방법 중중 Map/Reduce task 메모리를 더 여유있게 (2GB → 3GB) 해당 내용에 대한 조치를 순서대로 알아보겠습니다.
Ambari UI에서 변경 (가장 일반적)
- MapReduce2 설정
Ambari Web UI → Services → MapReduce2 → Configs → Advanced
[Memory 관련 설정]
mapreduce.map.memory.mb = 3072 (2048 → 3072)
mapreduce.reduce.memory.mb = 6144 (4096 → 6144)
[Java Heap 설정 - 80% 규칙]
mapreduce.map.java.opts = -Xmx2457m (80% of 3072)
mapreduce.reduce.java.opts = -Xmx4915m (80% of 6144)
- YARN 설정도 함께 확인
Services → YARN → Configs
yarn.scheduler.minimum-allocation-mb = 1024
yarn.scheduler.maximum-allocation-mb = 8192 (task가 요청 가능한 최대치)
yarn.nodemanager.resource.memory-mb = 10240 (노드당 할당 가능 총량)
설정 파일로 직접 변경 (모든 노드)
mapred-site.xml (보통 /etc/hadoop/conf/)
<property>
<name>mapreduce.map.memory.mb</name>
<value>3072</value>
</property>
<property>
<name>mapreduce.reduce.memory.mb</name>
<value>6144</value>
</property>
<property>
<name>mapreduce.map.java.opts</name>
<value>-Xmx2457m</value>
</property>
<property>
<name>mapreduce.reduce.java.opts</name>
<value>-Xmx4915m</value>
</property>
Job 실행 시 동적으로 변경 (임시 테스트용)
Hive 쿼리 실행 전:
SET mapreduce.map.memory.mb=3072;
SET mapreduce.reduce.memory.mb=6144;
SET mapreduce.map.java.opts=-Xmx2457m;
SET mapreduce.reduce.java.opts=-Xmx4915m;
SELECT ... -- 실제 쿼리
Spark submit 시:
spark-submit \
--conf spark.executor.memory=3g \
--conf spark.driver.memory=2g \
your_job.py
변경 후 필수 작업
# Ambari에서 변경 시:
1. "Save" 클릭
2. "Restart All Required Services" (NodeManager 재시작 필요)
# 직접 변경 시:
ambari-server restart
# 또는
sudo systemctl restart hadoop-yarn-nodemanager
실전 팁
메모리 계산 공식:
Java Heap = Container Memory × 0.8
예시:
Container 3GB (3072MB) → Heap 2457MB (-Xmx2457m)
Container 6GB (6144MB) → Heap 4915MB (-Xmx4915m)
왜 80%인가?
- 나머지 20%는 JVM overhead, off-heap, native memory 사용
- 100%로 설정하면 Container killed 발생