DataNode 프로세스의 열린 파일 수가 수만에서 수백만 단위로 나온다. Too many open files 가 로그에 찍히거나, 모니터링에서 파일 디스크립터 사용률 경고가 올라온다.
DataNode 는 블록 파일과 메타 파일, 소켓, 공유 라이브러리를 모두 파일 디스크립터로 잡는다. 블록 수가 많은 노드에서 수천에서 수만 개는 흔하다. 수십만을 넘어가면 작은 파일 문제나 핸들 누수를 의심하고, 백만 단위는 정상으로 보기 어렵다.
PID=$(pgrep -f 'proc_datanode|org.apache.hadoop.hdfs.server.datanode.DataNode' | head -1)
lsof -p "$PID" | wc -l
lsof -p "$PID" | awk '{print $5}' | sort | uniq -c | sort -rn | head
lsof -p "$PID" | awk '{print $9}' | cut -d/ -f1-5 | sort | uniq -c | sort -rn | head -20
cat /proc/$PID/limits | grep 'open files'
타입(REG, DIR, IPv4, sock) 분포를 보면 원인이 갈린다. REG 가 압도적이면 블록 파일을 붙들고 있는 것이고, IPv4 와 sock 이 많으면 클라이언트 연결이나 짧은 연결이 정리되지 않는 상황이다.
시스템 전체를 프로세스별로 훑을 때는 다음을 쓴다. 첫 번째 열이 열린 파일 수, 두 번째가 PID 다.
lsof | awk '{print $2}' | sort | uniq -c | sort -rn | head -20
lsof 는 무겁다. 부하가 걸린 노드에서 전체를 훑으면 수 분이 걸리므로 PID 를 지정해 쓴다. 가벼운 확인은 /proc 을 직접 센다.
ls /proc/$PID/fd | wc -l
작은 파일이 지나치게 많은 경우가 가장 흔하다. 블록 수가 늘면 DataNode 가 관리할 파일이 그만큼 늘어난다. 근본 대책은 파일 병합이다. 적재 단계에서 파일 크기를 블록 크기에 가깝게 맞추거나, 이미 쌓인 것은 Hive ALTER TABLE ... CONCATENATE, Impala INSERT OVERWRITE, HAR 등으로 합친다.
전송 스레드 상한이 과도하게 높으면 동시 연결이 많아진다. dfs.datanode.max.transfer.threads 를 확인한다. 기본값은 4096 이며 대규모 클러스터에서 8192 정도로 올리기도 한다. 근거 없이 매우 큰 값을 넣으면 핸들과 메모리를 함께 소모한다.
핸들 누수가 의심되면 스레드 덤프로 반복되는 스택을 확인한다.
jstack "$PID" > /tmp/dn-jstack.txt
grep -c 'BlockSender' /tmp/dn-jstack.txt
임시 조치는 DataNode 재시작이다. 열린 디스크립터가 모두 정리된다. 다만 원인을 찾지 못하면 다시 쌓인다.
DataNode 서비스의 nofile 한도를 늘린다. systemd 로 기동한다면 유닛 파일에 둔다.
[Service]
LimitNOFILE=128000
/etc/security/limits.d/ 에 넣은 값은 systemd 로 뜬 서비스에 적용되지 않는다. 적용 여부는 cat /proc/<PID>/limits 로 확인한다.