HDFS HA 가 "됐다 안 됐다" 하는 것처럼 보이는 장애를 추적한 기록이다. 근본 원인은 Standby NameNode 의 체크포인트(fsimage 업로드)가 며칠째 실패해 edits 가 계속 쌓인 것이었고, 부수적으로 JournalNode 한 대의 edits 파일이 손상돼 있었다.
Standby 로그에 다음이 보이면 체크포인트 실패를 의심한다.
TransferFsImage.copyFileToStream ... Error writing request body to server
26284초 만에 체크포인트 트리거
체크포인트가 성공하지 못하면 edits 가 계속 누적되고, 실제 failover 시 edits 재생에 오래 걸려 HA 가 동작하지 않는 것처럼 보인다. NameNode 를 재기동하면 edits 재생 동안 HTTP 포트가 열리지 않아 모니터링에서 연결 거부로 잡힌다.
GC 가 아닌 멈춤도 함께 나타났다.
pause of approximately 2855ms ... No GCs detected
Longest write-lock held interval: 60347
No GCs detected 는 GC 가 아니라 OS 레벨 문제(스왑, THP, 디스크 I/O 포화, 가상화 CPU steal)를 가리킨다. doTailEdits 에서 write lock 을 60초 잡으면 그동안 ZKFC 헬스체크가 타임아웃 나 오탐 failover 가 발생한다.
Ambari 에이전트 쪽에 URLError: <urlopen error [Errno 111] Connection refused> 와 Unable to determine the active NameNode 가 함께 뜨는 것은 에이전트 문제가 아니라 그 시각 NameNode HTTP · JMX 포트가 열려 있지 않다는 결과다. alert_metrics_deviation.py 의 TypeError: expected string or buffer 도 JMX 응답이 없어 발생한 파생 오류다.
ls -lh /hadoop/hdfs/namenode/current/
hdfs haadmin -getAllServiceState
ps -ef | grep NameNode
ss -lntp | grep -E '9870|50070'
iostat -x 1 5
dfs.image.transfer.timeout(기본 60초)과 dfs.image.transfer.bandwidthPerSec 를 확인한다. fsimage 가 크고 대역폭 제한이 걸려 있으면 전송 중 타임아웃으로 끊기는데, 이것이 가장 흔한 원인이다. 두 NameNode 호스트의 스왑 사용량과 THP 활성화 여부, 네임노드 디렉터리 디스크의 await 도 함께 본다. ZKFC 로그에서는 헬스체크 타임아웃과 세션 만료 기록을 확인한다.
Standby 가 Active 로 fsimage 를 HTTP 로 올리는 경로가 계속 끊길 때는, 각 NameNode 가 스스로 fsimage 를 만들게 하면 전송 자체가 없어 우회할 수 있다. safemode 로 진입시킨 뒤 네임스페이스를 저장하고 반드시 safemode 를 해제한다.
hdfs dfsadmin -safemode enter
hdfs dfsadmin -saveNamespace
hdfs dfsadmin -safemode leave
hdfs dfsadmin -safemode get # 두 노드 모두 OFF 여야 정상
saveNamespace 가 오래 걸려도 중단하지 않는다. 중간에 끊으면 어중간한 상태가 된다. 실패하더라도 safemode 해제는 반드시 실행한다. 성공하면 양쪽 NameNode 가 각자 fsimage 를 만들고 seen_txid 가 갱신되며, 이후 재시작 시간도 크게 줄어든다.
정상화된 뒤 설정을 반영한다. 반영은 NameNode 재시작이 필요하므로 fsimage 가 최신인 시점에 하고, Standby 를 먼저 올린 뒤 정상 확인 후 Active 를 재시작한다.
core-site: hadoop.http.idle_timeout.ms = 180000
hdfs-site: dfs.namenode.checkpoint.period = 3600
JournalNode 웹 UI 가 죽고 로그에 Can't scan · scanning through 0 ops 가 보이면 edits 파일 손상이다. 쿼럼이 살아 있으면 해당 노드만 정리해 다시 붙일 수 있다.
먼저 손상 파일을 특정한다. 전체를 지우면 동기화에 시간이 걸린다.
grep "Can't scan\|scanning through 0 ops" /logs/hadoop/hdfs/hadoop-hdfs-journalnode-<host>.log | tail -5
ls -la /hadoop/hdfs/journal/<nameservice>/current/ | sort -k5 -n | head -10
ls /hadoop/hdfs/journal/<nameservice>/current/edits_* | wc -l
디렉터리 전체를 비우는 경우의 절차는 다음과 같다. current 만 옮기고 상위 디렉터리는 남긴다.
# 1) JournalNode 중지
cd /hadoop/hdfs/journal/<nameservice>/
mv current current.bak.$(date +%Y%m%d)
# 2) VERSION 복원 — 이것이 없으면 포맷되지 않은 것으로 인식된다
mkdir -p current
cp -p current.bak.$(date +%Y%m%d)/VERSION current/VERSION
chown hdfs:hadoop current/VERSION
# 3) JournalNode 시작
VERSION 에는 클러스터 ID 와 네임스페이스 ID 가 들어 있어, 없으면 JournalNode 가 어느 클러스터 소속인지 몰라 쿼럼에 참여하지 못한다. Active NameNode 로그에 JournalNotFormattedException 이나 Journal Storage Directory not formatted 가 찍히면 이 경우다.
-initializeSharedEdits 는 이 상황에서 필요하지 않다.grep -iE "OutOfMemory|FATAL" /logs/hadoop/hdfs/hadoop-hdfs-namenode-<host>.log | tail -20
ls -lt /logs/hadoop/hdfs/hs_err_pid*.log 2>/dev/null | head -3
dmesg -T | grep -i "out of memory" | tail -5
hdfs getconf -confKey dfs.ha.namenodes.<nameservice>
hdfs getconf -confKey dfs.namenode.rpc-address.<nameservice>.nn1
hdfs haadmin -failover nn1 nn2
hdfs haadmin -getAllServiceState
전환 중 수 초에서 수십 초 쓰기가 끊기며, 클라이언트는 자동으로 새 Active 를 찾아간다.