- Published on
하둡 생태계 실전 가이드: HDFS·YARN·MapReduce 운영 기준
- Authors

- Name
- Youngju Kim
- @fjvbn20031
- 들어가며
- 1. HDFS 운영 기준
- 2. HDFS 용량 계획과 데이터 수명주기
- 3. YARN 큐 설계와 리소스 관리
- 4. MapReduce 잡 튜닝
- 5. 클러스터 모니터링과 알림
- 6. 장애 대응 가이드
- 7. 운영 체크리스트
- 8. 마무리

들어가며
하둡 클러스터를 구축하는 것과 안정적으로 운영하는 것은 완전히 다른 차원의 문제다. 설치 매뉴얼은 넘쳐나지만, HDFS가 90% 차면 어떻게 해야 하는지, YARN 큐가 포화됐을 때 프리엠션 정책을 어떻게 잡아야 하는지, MapReduce 잡이 데이터 스큐로 4시간째 돌고 있을 때 어디를 봐야 하는지 같은 운영 실무 기준을 정리한 문서는 드물다.
이 글은 하둡 생태계(HDFS, YARN, MapReduce)를 프로덕션 환경에서 운영하는 관점에서 용량 계획, 큐 설계, 잡 튜닝, 모니터링, 장애 대응까지 실전 기준을 정리한다. Hadoop 3.x 기준으로 작성했으며, 각 섹션에 실제 설정 예시와 커맨드를 포함한다.
1. HDFS 운영 기준
1.1 블록 크기 설정
HDFS의 기본 블록 크기는 128MB이며, 대용량 파일을 다루는 환경에서는 256MB로 설정하는 것이 일반적이다.
<!-- hdfs-site.xml -->
<property>
<name>dfs.blocksize</name>
<value>268435456</value> <!-- 256MB -->
<description>대용량 ETL 파일 기준 256MB 권장. 소형 파일이 많으면 128MB 유지.</description>
</property>
블록 크기 선택 기준:
| 기준 | 128MB | 256MB |
|---|---|---|
| 평균 파일 크기 | 수백 MB 이하 | 수 GB 이상 |
| MapReduce 매퍼 수 | 많음 (세분화) | 적음 (대형 태스크) |
| NameNode 메모리 부담 | 높음 | 낮음 |
| 네트워크 활용 | 보통 | 효율적 |
운영 규칙: NameNode 힙에서 블록 하나가 약 150바이트의 메모리를 소비한다. 1억 개 블록이면 약 15GB의 NameNode 힙이 필요하다. 블록 수를 줄이는 것이 NameNode 안정성에 직결된다.
1.2 복제 팩터 관리
기본 복제 팩터는 3이다. 이 값을 낮추면 저장 공간을 절약할 수 있지만 장애 내성이 줄어든다.
# 클러스터 전체 복제 팩터 확인
hdfs dfsadmin -report | grep "Default Replication"
# 특정 디렉토리의 복제 팩터 변경 (콜드 데이터 아카이빙 시)
hdfs dfs -setrep -w 2 /data/archive/2024/
# 복제 부족 블록 확인
hdfs fsck / -files -blocks -replicaDetails | grep "Under-replicated"
복제 팩터 운영 정책 예시:
/data/raw/(원본 데이터): 복제 팩터 3/data/processed/(가공 데이터): 복제 팩터 2/data/tmp/(임시 데이터): 복제 팩터 1- Erasure Coding 적용 디렉토리: 복제 팩터 해당 없음 (별도 정책)
1.3 NameNode 관리
NameNode는 HDFS의 단일 장애점(SPOF)이다. HA(High Availability) 구성은 필수이며, 다음 항목을 정기적으로 점검해야 한다.
<!-- hdfs-site.xml: NameNode HA 설정 -->
<property>
<name>dfs.nameservices</name>
<value>mycluster</value>
</property>
<property>
<name>dfs.ha.namenodes.mycluster</name>
<value>nn1,nn2</value>
</property>
<property>
<name>dfs.namenode.rpc-address.mycluster.nn1</name>
<value>namenode1.example.com:8020</value>
</property>
<property>
<name>dfs.namenode.rpc-address.mycluster.nn2</name>
<value>namenode2.example.com:8020</value>
</property>
<property>
<name>dfs.namenode.handler.count</name>
<value>128</value>
<description>클라이언트 RPC 요청 처리 스레드 수. 노드 100대 이상이면 128~256 권장.</description>
</property>
# NameNode 상태 확인
hdfs haadmin -getServiceState nn1
hdfs haadmin -getServiceState nn2
# NameNode 힙 사용량 확인
jstat -gcutil $(jps | grep NameNode | awk '{print $1}') 5000
# EditLog 크기 확인 (트랜잭션 로그가 과도하게 쌓이면 문제)
hdfs dfsadmin -fetchImage /tmp/fsimage_check
ls -lh /tmp/fsimage_check
1.4 세이프모드 관리
NameNode가 세이프모드에 있으면 쓰기 작업이 차단된다. 블록 리포트를 충분히 받을 때까지 자동으로 활성화된다.
# 세이프모드 상태 확인
hdfs dfsadmin -safemode get
# 세이프모드 강제 해제 (주의: 블록 무결성 확인 후에만 실행)
hdfs dfsadmin -safemode leave
# 세이프모드 진입 조건 확인
hdfs dfsadmin -report | grep -E "Safe mode|Missing blocks"
<!-- hdfs-site.xml: 세이프모드 임계값 조정 -->
<property>
<name>dfs.namenode.safemode.threshold-pct</name>
<value>0.999</value>
<description>전체 블록 중 99.9%가 리포트되면 세이프모드 해제</description>
</property>
<property>
<name>dfs.namenode.safemode.extension</name>
<value>30000</value>
<description>세이프모드 해제 후 추가 대기 시간 (30초)</description>
</property>
1.5 HDFS Balancer 운영
DataNode 간 디스크 사용률 편차가 커지면 특정 노드에 핫스팟이 발생한다. Balancer를 정기적으로 실행해야 한다.
# Balancer 실행 (기본 임계값 10%)
hdfs balancer -threshold 5
# 대역폭 제한 설정 (운영 시간에는 제한 필요)
hdfs dfsadmin -setBalancerBandwidth 52428800 # 50MB/s
# Balancer 백그라운드 실행 (cron 등록 권장)
nohup hdfs balancer -threshold 5 -idleiterations 5 > /var/log/hadoop/balancer.log 2>&1 &
Balancer 운영 규칙:
- 야간(00:00~06:00)에 cron으로 실행
- 운영 시간에는 대역폭을 20MB/s 이하로 제한
- threshold는 5~10% 범위로 설정
- DataNode 추가 직후에는 반드시 실행
2. HDFS 용량 계획과 데이터 수명주기
2.1 HDFS Quota 관리
디스크 사용량 폭주를 방지하려면 디렉토리별 quota를 반드시 설정한다.
# 네임 쿼터 설정 (파일/디렉토리 수 제한)
hdfs dfsadmin -setQuota 1000000 /data/team-a/
# 스페이스 쿼터 설정 (용량 제한, 복제 팩터 포함)
hdfs dfsadmin -setSpaceQuota 10T /data/team-a/
# 쿼터 현황 확인
hdfs dfs -count -q -h /data/team-a/
# 출력: QUOTA REM_QUOTA SPACE_QUOTA REM_SPACE_QUOTA DIR_COUNT FILE_COUNT CONTENT_SIZE PATHNAME
# 쿼터 해제
hdfs dfsadmin -clrSpaceQuota /data/team-a/
팀별 쿼터 설계 예시:
| 팀 | 경로 | 스페이스 쿼터 | 네임 쿼터 | 비고 |
|---|---|---|---|---|
| 데이터 엔지니어링 | /data/de/ | 50TB | 5,000,000 | ETL 파이프라인 |
| ML 팀 | /data/ml/ | 30TB | 2,000,000 | 학습 데이터 |
| 분석 팀 | /data/analytics/ | 20TB | 1,000,000 | 집계 결과 |
| 임시 영역 | /data/tmp/ | 5TB | 500,000 | 7일 TTL |
2.2 데이터 압축 전략
HDFS에서 압축을 적용하면 저장 공간과 네트워크 I/O를 모두 절약할 수 있다.
| 압축 코덱 | 압축률 | 속도 | 분할 가능 | 용도 |
|---|---|---|---|---|
| Snappy | 보통 | 매우 빠름 | 아니오 (컨테이너 포맷 사용 시 가능) | 중간 데이터, 셔플 |
| LZ4 | 보통 | 매우 빠름 | 아니오 | 실시간 처리 |
| Gzip | 높음 | 느림 | 아니오 | 아카이브, 콜드 데이터 |
| Zstandard | 높음 | 빠름 | 아니오 | Gzip 대체, 아카이브 |
| Bzip2 | 매우 높음 | 매우 느림 | 예 | 장기 보관 |
<!-- core-site.xml: 압축 코덱 등록 -->
<property>
<name>io.compression.codecs</name>
<value>
org.apache.hadoop.io.compress.GzipCodec,
org.apache.hadoop.io.compress.SnappyCodec,
org.apache.hadoop.io.compress.ZStandardCodec,
org.apache.hadoop.io.compress.Lz4Codec
</value>
</property>
<!-- mapred-site.xml: MapReduce 중간 출력 압축 -->
<property>
<name>mapreduce.map.output.compress</name>
<value>true</value>
</property>
<property>
<name>mapreduce.map.output.compress.codec</name>
<value>org.apache.hadoop.io.compress.SnappyCodec</value>
</property>
2.3 Erasure Coding (EC)
Hadoop 3.x에서 도입된 Erasure Coding은 복제 팩터 3 대비 약 50%의 저장 공간을 절약하면서도 동일한 내결함성을 제공한다.
# 사용 가능한 EC 정책 확인
hdfs ec -listPolicies
# RS-6-3 정책 활성화 (6 데이터 블록 + 3 패리티 블록)
hdfs ec -enablePolicy -policy RS-6-3-1024k
# 디렉토리에 EC 정책 적용
hdfs ec -setPolicy -path /data/archive -policy RS-6-3-1024k
# EC 정책 확인
hdfs ec -getPolicy -path /data/archive
EC 적용 시 주의사항:
- 최소 9개 DataNode 필요 (RS-6-3 기준)
- 랜덤 읽기 성능이 복제 방식보다 낮음 (인코딩/디코딩 오버헤드)
- 핫 데이터보다는 콜드/웜 데이터에 적합
- 기존 파일에는 적용 불가 (새로 쓰거나 distcp로 이동)
2.4 Tiered Storage
HDFS의 스토리지 정책을 활용하면 SSD, HDD, 아카이브 스토리지를 계층적으로 관리할 수 있다.
# 스토리지 정책 확인
hdfs storagepolicies -listPolicies
# 핫 데이터 → SSD
hdfs storagepolicies -setStoragePolicy -path /data/hot -policy HOT
# 웜 데이터 → 1 SSD + N HDD
hdfs storagepolicies -setStoragePolicy -path /data/warm -policy WARM
# 콜드 데이터 → 아카이브
hdfs storagepolicies -setStoragePolicy -path /data/cold -policy COLD
# 정책에 따라 데이터 이동 실행
hdfs mover -p /data/
<!-- hdfs-site.xml: DataNode 스토리지 타입 지정 -->
<property>
<name>dfs.datanode.data.dir</name>
<value>[SSD]/ssd/hdfs/data,[DISK]/hdd1/hdfs/data,[DISK]/hdd2/hdfs/data,[ARCHIVE]/archive/hdfs/data</value>
</property>
2.5 데이터 수명주기 자동화
#!/bin/bash
# data_lifecycle.sh - 데이터 수명주기 자동화 스크립트
DATE=$(date +%Y-%m-%d)
LOG="/var/log/hadoop/lifecycle_${DATE}.log"
echo "[${DATE}] 데이터 수명주기 관리 시작" >> ${LOG}
# 1. 90일 이상 된 임시 데이터 삭제
echo "=== 임시 데이터 정리 ===" >> ${LOG}
hdfs dfs -find /data/tmp -name "*" -atime +90 -print >> ${LOG}
hdfs dfs -rm -r -skipTrash $(hdfs dfs -find /data/tmp -name "*" -atime +90) 2>> ${LOG}
# 2. 30일 이상 된 처리 데이터 → 복제 팩터 2로 변경
echo "=== 복제 팩터 조정 ===" >> ${LOG}
for dir in $(hdfs dfs -ls /data/processed/ | awk '{print $8}' | tail -n +2); do
mod_date=$(hdfs dfs -stat "%Y" ${dir})
age_days=$(( ($(date +%s) - $(date -d "${mod_date}" +%s)) / 86400 ))
if [ ${age_days} -gt 30 ]; then
hdfs dfs -setrep 2 ${dir} >> ${LOG} 2>&1
fi
done
# 3. 180일 이상 된 데이터 → Erasure Coding 디렉토리로 이동
echo "=== 아카이브 이동 ===" >> ${LOG}
hadoop distcp -skipcrccheck /data/processed/old/ /data/archive/ >> ${LOG} 2>&1
# 4. 용량 리포트
echo "=== 용량 현황 ===" >> ${LOG}
hdfs dfs -du -s -h /data/* >> ${LOG}
echo "[${DATE}] 데이터 수명주기 관리 완료" >> ${LOG}
3. YARN 큐 설계와 리소스 관리
3.1 Capacity Scheduler vs Fair Scheduler
| 항목 | Capacity Scheduler | Fair Scheduler |
|---|---|---|
| 기본 제공 | Apache Hadoop 기본 | CDH 기본 |
| 리소스 보장 | 큐별 최소 용량 보장 | 가중치 기반 균등 분배 |
| 프리엠션 | 지원 | 지원 |
| 멀티테넌시 | 강함 (계층형 큐) | 보통 |
| 설정 복잡도 | 높음 | 보통 |
권장: Hadoop 3.x에서는 Capacity Scheduler가 공식 기본값이며, 대규모 멀티테넌트 환경에 적합하다.
3.2 Capacity Scheduler 큐 설계
<!-- capacity-scheduler.xml -->
<configuration>
<!-- 루트 큐 하위 구조 -->
<property>
<name>yarn.scheduler.capacity.root.queues</name>
<value>production,development,system</value>
</property>
<!-- production 큐: 전체 리소스의 60% -->
<property>
<name>yarn.scheduler.capacity.root.production.capacity</name>
<value>60</value>
</property>
<property>
<name>yarn.scheduler.capacity.root.production.maximum-capacity</name>
<value>80</value>
</property>
<property>
<name>yarn.scheduler.capacity.root.production.queues</name>
<value>etl,realtime</value>
</property>
<!-- production > etl 큐 -->
<property>
<name>yarn.scheduler.capacity.root.production.etl.capacity</name>
<value>70</value>
</property>
<property>
<name>yarn.scheduler.capacity.root.production.etl.maximum-capacity</name>
<value>90</value>
</property>
<property>
<name>yarn.scheduler.capacity.root.production.etl.user-limit-factor</name>
<value>2</value>
</property>
<!-- production > realtime 큐 -->
<property>
<name>yarn.scheduler.capacity.root.production.realtime.capacity</name>
<value>30</value>
</property>
<property>
<name>yarn.scheduler.capacity.root.production.realtime.maximum-capacity</name>
<value>50</value>
</property>
<!-- development 큐: 전체 리소스의 30% -->
<property>
<name>yarn.scheduler.capacity.root.development.capacity</name>
<value>30</value>
</property>
<property>
<name>yarn.scheduler.capacity.root.development.maximum-capacity</name>
<value>50</value>
</property>
<!-- system 큐: 전체 리소스의 10% (모니터링, 유지보수) -->
<property>
<name>yarn.scheduler.capacity.root.system.capacity</name>
<value>10</value>
</property>
<property>
<name>yarn.scheduler.capacity.root.system.maximum-capacity</name>
<value>20</value>
</property>
</configuration>
큐 구조 다이어그램:
root (100%)
├── production (60%, max 80%)
│ ├── etl (70% of production, max 90%)
│ └── realtime (30% of production, max 50%)
├── development (30%, max 50%)
└── system (10%, max 20%)
3.3 프리엠션(Preemption) 설정
프리엠션은 큐가 보장된 리소스를 돌려받기 위해 다른 큐의 컨테이너를 강제 종료하는 메커니즘이다.
<!-- yarn-site.xml -->
<property>
<name>yarn.resourcemanager.scheduler.monitor.enable</name>
<value>true</value>
</property>
<property>
<name>yarn.resourcemanager.scheduler.monitor.policies</name>
<value>org.apache.hadoop.yarn.server.resourcemanager.monitor.capacity.ProportionalCapacityPreemptionPolicy</value>
</property>
<!-- 프리엠션 대기 시간: 15초 후 시작 -->
<property>
<name>yarn.resourcemanager.monitor.capacity.preemption.monitoring_interval</name>
<value>3000</value>
</property>
<property>
<name>yarn.resourcemanager.monitor.capacity.preemption.max_wait_before_kill</name>
<value>15000</value>
</property>
<!-- 한 번에 프리엠션할 수 있는 최대 비율 -->
<property>
<name>yarn.resourcemanager.monitor.capacity.preemption.total_preemption_per_round</name>
<value>0.1</value>
</property>
3.4 YARN 리소스 설정
<!-- yarn-site.xml: NodeManager 리소스 설정 -->
<property>
<name>yarn.nodemanager.resource.memory-mb</name>
<value>65536</value> <!-- 64GB (전체 메모리의 80% 정도) -->
</property>
<property>
<name>yarn.nodemanager.resource.cpu-vcores</name>
<value>24</value> <!-- 물리 코어 수의 1.5~2배 -->
</property>
<!-- 컨테이너 메모리 범위 -->
<property>
<name>yarn.scheduler.minimum-allocation-mb</name>
<value>1024</value>
</property>
<property>
<name>yarn.scheduler.maximum-allocation-mb</name>
<value>32768</value>
</property>
<!-- 컨테이너 vcore 범위 -->
<property>
<name>yarn.scheduler.minimum-allocation-vcores</name>
<value>1</value>
</property>
<property>
<name>yarn.scheduler.maximum-allocation-vcores</name>
<value>12</value>
</property>
# YARN 큐 상태 확인
yarn queue -status production
# 실행 중인 애플리케이션 확인
yarn application -list -appStates RUNNING
# 큐별 리소스 사용량 확인
yarn queue -status production.etl
# YARN 스케줄러 설정 리로드 (재시작 없이)
yarn rmadmin -refreshQueues
4. MapReduce 잡 튜닝
4.1 Mapper/Reducer 수 최적화
<!-- mapred-site.xml -->
<!-- 매퍼 메모리: 기본 1GB이지만, 대용량 데이터에서는 2~4GB 권장 -->
<property>
<name>mapreduce.map.memory.mb</name>
<value>2048</value>
</property>
<property>
<name>mapreduce.map.java.opts</name>
<value>-Xmx1638m</value> <!-- memory.mb의 80% -->
</property>
<!-- 리듀서 메모리: 매퍼보다 크게 설정 (집계 연산이 많으므로) -->
<property>
<name>mapreduce.reduce.memory.mb</name>
<value>4096</value>
</property>
<property>
<name>mapreduce.reduce.java.opts</name>
<value>-Xmx3276m</value> <!-- memory.mb의 80% -->
</property>
<!-- 리듀서 수 명시 (데이터 크기에 따라 조정) -->
<property>
<name>mapreduce.job.reduces</name>
<value>100</value>
</property>
Mapper/Reducer 수 산정 공식:
매퍼 수 ≈ 입력 데이터 크기 / 블록 크기
예: 1TB 입력, 256MB 블록 → 약 4,000개 매퍼
리듀서 수 ≈ 0.95 × (클러스터 내 총 reduce 슬롯 수)
또는 실측 기반으로 리듀서 하나당 처리량이 256MB~1GB가 되도록 조정
4.2 셔플(Shuffle) 최적화
셔플은 MapReduce에서 가장 비용이 큰 단계다. 네트워크 I/O와 디스크 I/O가 집중된다.
<!-- mapred-site.xml: 맵 측 정렬/스필 설정 -->
<property>
<name>mapreduce.task.io.sort.mb</name>
<value>512</value>
<description>정렬 버퍼 크기. 기본 100MB → 512MB로 증가하면 스필 횟수 감소</description>
</property>
<property>
<name>mapreduce.task.io.sort.factor</name>
<value>100</value>
<description>동시 머지 가능한 스트림 수. 기본 10 → 100으로 증가</description>
</property>
<property>
<name>mapreduce.map.sort.spill.percent</name>
<value>0.80</value>
<description>정렬 버퍼가 80% 차면 스필 시작</description>
</property>
<!-- 리듀스 측 셔플 설정 -->
<property>
<name>mapreduce.reduce.shuffle.parallelcopies</name>
<value>20</value>
<description>리듀서가 매퍼 출력을 가져오는 병렬 스레드 수</description>
</property>
<property>
<name>mapreduce.reduce.shuffle.input.buffer.percent</name>
<value>0.70</value>
<description>셔플 입력에 할당할 힙 비율</description>
</property>
<property>
<name>mapreduce.reduce.shuffle.merge.percent</name>
<value>0.66</value>
<description>인메모리 머지 시작 임계값</description>
</property>
4.3 데이터 스큐 처리
데이터 스큐(skew)는 특정 키에 데이터가 집중되어 일부 리듀서만 과부하가 걸리는 현상이다.
스큐 진단:
# 잡의 카운터에서 리듀서별 입력 레코드 수 편차 확인
yarn logs -applicationId application_1234567890_0001 | grep "Reduce input records"
# 잡 히스토리 서버에서 태스크별 실행 시간 확인
mapred job -history /path/to/job_history_file
스큐 해결 방법:
- 솔팅 키(Salting): 키에 랜덤 접두사를 붙여 분산
// 매퍼에서 키에 솔트 추가
int salt = random.nextInt(10);
outputKey.set(salt + "_" + originalKey);
// 첫 번째 MR: 솔트 키로 부분 집계
// 두 번째 MR: 솔트 제거 후 최종 집계
- Combiner 적용: 매퍼 출력을 로컬에서 미리 집계
job.setCombinerClass(MyCombiner.class);
- 파티셔너 커스터마이징: 데이터 분포를 고려한 파티셔닝
public class SkewAwarePartitioner extends Partitioner<Text, IntWritable> {
@Override
public int getPartition(Text key, IntWritable value, int numPartitions) {
String k = key.toString();
if (k.equals("HOT_KEY")) {
// 핫 키는 여러 리듀서에 분산
return (k.hashCode() + random.nextInt(10)) % numPartitions;
}
return (k.hashCode() & Integer.MAX_VALUE) % numPartitions;
}
}
4.4 투기적 실행(Speculative Execution)
느린 태스크(straggler)를 감지하면 동일 태스크를 다른 노드에서 병렬 실행하여 먼저 완료되는 결과를 채택한다.
<!-- mapred-site.xml -->
<property>
<name>mapreduce.map.speculative</name>
<value>true</value>
</property>
<property>
<name>mapreduce.reduce.speculative</name>
<value>false</value>
<description>리듀서는 데이터를 많이 소비하므로 투기적 실행 비활성화 권장</description>
</property>
주의: 외부 시스템에 쓰기를 수행하는 태스크(DB insert, API 호출 등)에서는 반드시 비활성화해야 한다. 중복 쓰기가 발생할 수 있다.
4.5 JVM 재사용
매 태스크마다 JVM을 새로 생성하면 오버헤드가 크다. 소형 태스크가 많을 때 효과적이다.
<!-- mapred-site.xml -->
<property>
<name>mapreduce.job.jvm.numtasks</name>
<value>10</value>
<description>하나의 JVM에서 최대 10개 태스크 실행. -1이면 무제한.</description>
</property>
5. 클러스터 모니터링과 알림
5.1 주요 모니터링 메트릭
HDFS 핵심 메트릭:
| 메트릭 | 정상 범위 | 경고 임계값 | 위험 임계값 |
|---|---|---|---|
| DFS 사용률 | < 70% | 80% | 90% |
| 언더 복제 블록 | 0 | > 100 | > 1,000 |
| 누락 블록 | 0 | > 0 | > 10 |
| NN 힙 사용률 | < 70% | 80% | 90% |
| Dead DataNode 수 | 0 | > 0 | > 2 |
| NN RPC 평균 처리 시간 | < 10ms | > 50ms | > 200ms |
YARN 핵심 메트릭:
| 메트릭 | 정상 범위 | 경고 임계값 | 위험 임계값 |
|---|---|---|---|
| 클러스터 메모리 사용률 | < 80% | 85% | 95% |
| Pending 컨테이너 수 | < 50 | > 200 | > 1,000 |
| Unhealthy 노드 수 | 0 | > 0 | > 3 |
| 큐 대기 애플리케이션 수 | < 10 | > 50 | > 200 |
5.2 JMX를 통한 메트릭 수집
# NameNode JMX 메트릭 조회
curl -s http://namenode:9870/jmx | python3 -m json.tool | grep -A5 "CapacityUsed"
# ResourceManager JMX 메트릭 조회
curl -s http://resourcemanager:8088/jmx | python3 -m json.tool | grep -A5 "AllocatedMB"
# DataNode JMX 메트릭 조회
curl -s http://datanode:9864/jmx?qry=Hadoop:service=DataNode,name=FSDatasetState
5.3 Prometheus + Grafana 연동
# prometheus.yml - 하둡 JMX Exporter 설정
scrape_configs:
- job_name: 'hadoop-namenode'
scrape_interval: 30s
static_configs:
- targets: ['namenode1:7001', 'namenode2:7001']
labels:
cluster: 'production'
component: 'namenode'
- job_name: 'hadoop-datanode'
scrape_interval: 30s
static_configs:
- targets: ['datanode1:7002', 'datanode2:7002', 'datanode3:7002']
labels:
cluster: 'production'
component: 'datanode'
- job_name: 'hadoop-resourcemanager'
scrape_interval: 30s
static_configs:
- targets: ['resourcemanager:7003']
labels:
cluster: 'production'
component: 'resourcemanager'
- job_name: 'hadoop-nodemanager'
scrape_interval: 30s
static_configs:
- targets: ['datanode1:7004', 'datanode2:7004', 'datanode3:7004']
labels:
cluster: 'production'
component: 'nodemanager'
JMX Exporter 실행 설정 (hadoop-env.sh):
# hadoop-env.sh
export HDFS_NAMENODE_OPTS="$HDFS_NAMENODE_OPTS -javaagent:/opt/jmx_exporter/jmx_prometheus_javaagent.jar=7001:/opt/jmx_exporter/namenode.yml"
export HDFS_DATANODE_OPTS="$HDFS_DATANODE_OPTS -javaagent:/opt/jmx_exporter/jmx_prometheus_javaagent.jar=7002:/opt/jmx_exporter/datanode.yml"
export YARN_RESOURCEMANAGER_OPTS="$YARN_RESOURCEMANAGER_OPTS -javaagent:/opt/jmx_exporter/jmx_prometheus_javaagent.jar=7003:/opt/jmx_exporter/resourcemanager.yml"
export YARN_NODEMANAGER_OPTS="$YARN_NODEMANAGER_OPTS -javaagent:/opt/jmx_exporter/jmx_prometheus_javaagent.jar=7004:/opt/jmx_exporter/nodemanager.yml"
5.4 Grafana 알림 규칙 예시
# Grafana Alert Rules (Alerting YAML)
groups:
- name: hadoop_alerts
rules:
- alert: HDFSCapacityCritical
expr: hadoop_namenode_capacity_used_gb / hadoop_namenode_capacity_total_gb > 0.9
for: 10m
labels:
severity: critical
annotations:
summary: 'HDFS 용량 90% 초과'
description: 'HDFS 사용률이 {{ $value | humanizePercentage }}입니다. 즉시 데이터 정리 또는 노드 추가 필요.'
- alert: HDFSMissingBlocks
expr: hadoop_namenode_missing_blocks > 0
for: 5m
labels:
severity: critical
annotations:
summary: 'HDFS 누락 블록 발생'
description: '{{ $value }}개의 블록이 누락되었습니다.'
- alert: YARNUnhealthyNodes
expr: hadoop_resourcemanager_unhealthy_nodes > 0
for: 5m
labels:
severity: warning
annotations:
summary: 'YARN Unhealthy 노드 발생'
description: '{{ $value }}개의 노드가 unhealthy 상태입니다.'
- alert: YARNMemoryPressure
expr: hadoop_resourcemanager_allocated_mb / hadoop_resourcemanager_available_mb > 0.95
for: 15m
labels:
severity: warning
annotations:
summary: 'YARN 메모리 리소스 부족'
description: '클러스터 메모리 사용률이 95%를 초과했습니다.'
5.5 Ambari / Cloudera Manager 활용
전용 관리 도구를 사용하면 설정 관리, 모니터링, 알림을 통합적으로 처리할 수 있다.
| 기능 | Ambari (Apache) | Cloudera Manager |
|---|---|---|
| 설정 관리 | UI 기반, 버전 이력 | UI 기반, 롤백 지원 |
| 모니터링 | 내장 대시보드 | 내장 + Grafana 연동 |
| 알림 | SMTP, SNMP | SMTP, SNMP, Webhook |
| 서비스 관리 | 개별 서비스 제어 | 롤링 재시작 지원 |
| 라이선스 | Apache (무료) | 상용 (CDP) |
6. 장애 대응 가이드
6.1 DataNode 장애
증상: DataNode 프로세스 다운, 네트워크 단절, 디스크 장애
# 1단계: Dead DataNode 확인
hdfs dfsadmin -report | grep -A3 "Dead datanodes"
# 2단계: 해당 DataNode 로그 확인
tail -500 /var/log/hadoop/hdfs/hadoop-hdfs-datanode-*.log | grep -E "ERROR|WARN|FATAL"
# 3단계: 디스크 상태 확인
df -h # 디스크 용량
smartctl -a /dev/sda # 디스크 건강 상태
dmesg | grep -i "error\|fail\|i/o" # 커널 로그에서 디스크 오류 확인
# 4단계: DataNode 재시작 또는 제거
# 재시작 가능한 경우:
hdfs --daemon start datanode
# 제거해야 하는 경우 (Decommission):
# 1) dfs.hosts.exclude에 노드 추가
# 2) 설정 리프레시
hdfs dfsadmin -refreshNodes
# 3) 데이터 마이그레이션 진행 상황 모니터링
hdfs dfsadmin -report | grep "Decommission Status"
DataNode Decommission 설정:
<!-- hdfs-site.xml -->
<property>
<name>dfs.hosts.exclude</name>
<value>/etc/hadoop/conf/dfs.exclude</value>
</property>
# /etc/hadoop/conf/dfs.exclude
datanode-bad-01.example.com
datanode-bad-02.example.com
6.2 NameNode Failover
HA 환경에서 Active NameNode 장애 시 자동 Failover가 동작해야 한다.
# NameNode 상태 확인
hdfs haadmin -getAllServiceState
# 출력 예:
# nn1 active
# nn2 standby
# 수동 Failover (긴급 시)
hdfs haadmin -failover nn1 nn2
# ZKFC 프로세스 확인 (자동 Failover의 핵심)
jps | grep DFSZKFailoverController
# ZooKeeper 세션 상태 확인
echo "stat" | nc zookeeper1 2181
# Failover가 안 될 때: ZKFC 재시작
hdfs --daemon stop zkfc
hdfs --daemon start zkfc
자동 Failover 설정:
<!-- hdfs-site.xml -->
<property>
<name>dfs.ha.automatic-failover.enabled</name>
<value>true</value>
</property>
<!-- core-site.xml -->
<property>
<name>ha.zookeeper.quorum</name>
<value>zk1.example.com:2181,zk2.example.com:2181,zk3.example.com:2181</value>
</property>
6.3 디스크 장애 대응
DataNode에서 특정 디스크가 장애를 일으켰을 때, 전체 DataNode를 내리지 않고 해당 디스크만 제외할 수 있다.
<!-- hdfs-site.xml: 디스크 장애 허용 설정 -->
<property>
<name>dfs.datanode.failed.volumes.tolerated</name>
<value>2</value>
<description>최대 2개 볼륨 장애까지 DataNode 유지. 전체 볼륨 수의 1/3 이하 권장.</description>
</property>
# 디스크 교체 절차
# 1. 장애 디스크 확인
hdfs dfsadmin -getDatanodeInfo datanode01:9866
# 2. 해당 볼륨을 dfs.datanode.data.dir에서 제거
# 3. DataNode 재시작 (Hadoop 3.x에서는 리컨피그 가능)
hdfs dfsadmin -reconfig datanode datanode01:9866 start
# 4. 리컨피그 상태 확인
hdfs dfsadmin -reconfig datanode datanode01:9866 status
# 5. 새 디스크 마운트 후 data.dir에 추가, 다시 리컨피그
6.4 YARN ResourceManager 장애
# RM HA 상태 확인
yarn rmadmin -getAllServiceState
# RM 수동 전환
yarn rmadmin -transitionToActive rm2
# NodeManager가 RM에 연결 못하는 경우
# NM 로그 확인
tail -200 /var/log/hadoop/yarn/hadoop-yarn-nodemanager-*.log | grep "ERROR"
# NM 재시작
yarn --daemon stop nodemanager
yarn --daemon start nodemanager
7. 운영 체크리스트
7.1 일간 체크리스트
#!/bin/bash
# daily_health_check.sh
echo "========== HDFS 일간 점검 =========="
# HDFS 상태 요약
hdfs dfsadmin -report | head -20
# 누락/복제부족 블록 확인
hdfs fsck / -list-corruptfileblocks
# NameNode 세이프모드 확인
hdfs dfsadmin -safemode get
echo "========== YARN 일간 점검 =========="
# YARN 노드 상태
yarn node -list -all | head -20
# 실패한 애플리케이션 확인 (최근 24시간)
yarn application -list -appStates FAILED
# 큐 사용 현황
yarn queue -status root
echo "========== 시스템 점검 =========="
# 디스크 사용량
df -h | grep -E "/data|/hdfs"
# 메모리/CPU
free -g
uptime
7.2 주간 체크리스트
| 항목 | 커맨드/행동 | 기준 |
|---|---|---|
| HDFS fsck 전체 실행 | hdfs fsck / -files -blocks | Corrupt 블록 0 |
| Balancer 실행 | hdfs balancer -threshold 5 | 노드 간 편차 < 5% |
| YARN 로그 정리 | yarn logs -applicationId ... -am | 30일 이상 로그 삭제 |
| GC 로그 분석 | NN/RM GC 로그 검토 | Full GC < 5회/일 |
| 디스크 SMART 점검 | smartctl -a /dev/sd* | 오류 0 |
7.3 월간 체크리스트
| 항목 | 설명 |
|---|---|
| 용량 추세 분석 | 월별 HDFS 사용량 증가율 계산, 3개월 후 용량 예측 |
| 큐 리소스 재조정 | 팀별 실제 사용량 기반으로 capacity 재설정 |
| 성능 베이스라인 갱신 | 주요 ETL 잡 실행 시간 트렌드 확인 |
| 보안 감사 | 접근 권한, 서비스 계정 점검 |
| 하둡 버전/패치 검토 | 보안 패치, 버그 수정 적용 여부 |
7.4 용량 계획 스프레드시트
현재 클러스터 상태:
- 총 DataNode 수: N
- 노드당 디스크: 12 × 4TB HDD = 48TB
- 총 원시 용량: N × 48TB
- HDFS 사용 가능 용량 (복제 팩터 3 기준): N × 48TB / 3 = N × 16TB
- 현재 HDFS 사용량: X TB
- 사용률: X / (N × 16) × 100 = Y%
월별 증가량: Z TB/month
노드 추가 시점 계산:
- 안전 임계값: 80%
- 여유 용량: (N × 16 × 0.8) - X = W TB
- 현재 증가 속도로 W / Z = M개월 후 80% 도달
- 노드 주문 리드타임 고려 → M - 2개월 전에 주문 필요
8. 마무리
하둡 클러스터 운영은 초기 구축보다 지속적인 관리와 튜닝에 더 많은 노력이 필요하다. 이 글에서 다룬 핵심 사항을 정리하면 다음과 같다.
HDFS: 블록 크기와 복제 팩터를 데이터 특성에 맞게 설정하고, NameNode 힙 관리와 Balancer 실행을 정기 루틴으로 확립한다. Erasure Coding과 Tiered Storage를 활용해 스토리지 비용을 최적화한다.
YARN: Capacity Scheduler 기반의 계층형 큐를 설계하고, 프리엠션 정책을 활성화하여 리소스 공정성을 보장한다. 큐 capacity는 실제 사용 패턴에 맞춰 주기적으로 재조정한다.
MapReduce: 셔플 최적화(정렬 버퍼, 스필 임계값)와 데이터 스큐 처리가 잡 성능의 핵심이다. JVM 재사용과 투기적 실행을 상황에 맞게 설정한다.
모니터링: JMX + Prometheus + Grafana 파이프라인을 구축하고, HDFS 용량/블록 상태, YARN 리소스/큐 상태에 대한 알림을 설정한다.
장애 대응: NameNode HA, DataNode Decommission, 디스크 핫스왑 절차를 사전에 문서화하고 훈련한다.
운영 체크리스트를 일간/주간/월간으로 나눠 실행하고, 용량 계획을 데이터 기반으로 수립하면 대부분의 운영 이슈를 선제적으로 방지할 수 있다.