데이터센터 정전으로 모든 노드가 내려갔다 올라온 뒤 Standby NameNode 가 기동에 실패하고 HA 가 깨졌다. Active 는 불량 상태로 겨우 떠 있고, JournalNode 3대와 DataNode 12대는 양호했으며 missing block 이 179개 보고됐다. Standby 로그의 핵심은 다음이었다.
STARTUP_MSG: args = [-upgrade]
InconsistentFSStateException: Directory /hadoop/nn/data is in an inconsistent state:
previous fs state should not exist during upgrade. Finalize or rollback first.
확인 결과 업그레이드 중이 아니었고 previous/ 디렉토리는 죽은 Standby 에만 있고 Active 에는 없었다. 즉 업그레이드 실패가 아니라 두 NN 의 메타데이터 디렉토리 상태가 비대칭인 것이 원인이다. NN 은 previous/ 가 있으면 업그레이드 중이라 오판해 -upgrade 로 기동을 시도하고, Active 와 맞지 않아 예외가 난다.
# 양쪽 NN
ls -la /hadoop/nn/data/ /hadoop/nn/data/current/ /hadoop/nn/data/previous/
cat /hadoop/nn/data/current/VERSION
cat /hadoop/nn/data/previous/VERSION 2>/dev/null
# JournalNode
ls -la /hadoop/journal/<nameservice>/
# 시간 동기화 (clock offset 경고 해소)
chronyc tracking
systemctl restart chronyd
VERSION 의 layoutVersion · clusterID · namespaceID 가 Active 의 current 와 Standby 의 current/previous 사이에서 같은지 본다. Cloudera Manager 의 HDFS 구성에서 -upgrade 가 Startup Option 에 박혀 있거나 "Upgrade HDFS Metadata" 명령이 진행 중이면 제거 · 취소한다.
Standby 의 NameNode 프로세스가 멈춘 상태에서 메타데이터 디렉토리를 백업하고 비운 뒤 Active 에서 다시 받아온다. bootstrapStandby 는 단순 동기화라 previous/ 를 만들지 않는다.
tar czf /backup/nn-data-$(hostname)-$(date +%Y%m%d).tar.gz -C /hadoop/nn data
sudo -u hdfs rm -rf /hadoop/nn/data/*
sudo -u hdfs hdfs namenode -bootstrapStandby
# CM 에서 Standby NameNode 시작 (-upgrade 없이)
sudo -u hdfs hdfs haadmin -getAllServiceState
hdfs zkfc -formatZK 는 ZooKeeper 의 페일오버 상태가 깨졌을 때만 쓰고, 보통은 ZKFC 재시작으로 충분하다.
체크포인트(fsimage 생성) 는 Standby 의 역할이다. Standby 가 죽어 있으면 edit log 가 쌓이기만 해 JournalNode 디스크와 NN 메모리를 압박하고, Active 까지 재시작하면 edit log 재생에 수 시간이 걸린다. 복구가 길어지면 Active 에서 수동 체크포인트를 만든다. safemode 동안 쓰기가 멈추므로 배치 영향을 확인한다.
curl -s http://<active>:9870/jmx?qry=Hadoop:service=NameNode,name=NameNodeInfo | grep -E "LastCheckpointTime|JournalTransactionInfo"
sudo -u hdfs hdfs dfsadmin -safemode enter
sudo -u hdfs hdfs dfsadmin -saveNamespace
sudo -u hdfs hdfs dfsadmin -safemode leave
sudo -u hdfs hdfs haadmin -getAllServiceState
sudo -u hdfs hdfs haadmin -failover nn2 nn1 # ZKFC 경유, 자동 페일오버 켜져 있어도 동작
sudo -u hdfs hdfs haadmin -failover --forcefence --forceactive nn2 nn1 # Active 가 응답 없을 때
sudo -u hdfs hdfs haadmin -transitionToActive --forcemanual nn1 # 비상시만. split-brain 위험
전환 전에 JournalNode 과반이 정상인지, Standby 의 TxId 가 Active 를 따라잡았는지(.../jmx?qry=Hadoop:service=NameNode,name=FSNamesystem 의 LastAppliedOrWrittenTxId), safemode 가 아닌지 본다. Cloudera 는 fencing 을 보통 shell(/bin/true) 로 두고 JournalNode 의 epoch 기반 fencing 에 의존한다. 페일오버 실패 원인은 *zkfc*.log 에 남는다. HA 복구 후에는 양방향 수동 페일오버를 한 번씩 해 봐야 한다.
sudo -u hdfs hdfs fsck / -list-corruptfileblocks > /tmp/corrupt_blocks.txt
sudo -u hdfs hdfs fsck / -files -blocks -locations > /tmp/before_fsck.txt # 작업 전 스냅샷
| 경로 | 성격 | 처리 |
|---|---|---|
/user/*/.staging/job_*/ |
YARN/MR 임시 잡 파일 | 삭제 |
/user/*/.sparkStaging/ |
Spark 임시 파일 | 삭제 |
/user/history/done_intermediate/ |
MR history 중간 파일 | 삭제 |
/tmp/ |
임시 | 검토 후 삭제 |
/user/hive/warehouse/, 운영 경로 |
비즈니스 데이터 | 복구 시도 후 결정 |
이 사례의 missing block 은 거의 전부 .staging/job_*/libjars/*.jar 였다.
sudo -u hdfs hdfs dfs -rm -r -skipTrash "/user/*/.staging"
sudo -u hdfs hdfs dfs -rm -r -skipTrash "/user/*/.sparkStaging"
sudo -u hdfs hdfs dfs -rm -r -skipTrash "/user/history/done_intermediate"
sudo -u hdfs hdfs fsck / | grep -E "Total|Missing|Corrupt|Under-replicated|Status"
-skipTrash 를 쓰지 않으면 휴지통으로 메타만 옮겨져 fsck 에서 여전히 missing 으로 잡힌다. 비즈니스 데이터가 걸려 있으면 hdfs dfsadmin -triggerBlockReport <dn>:9867 로 block report 를 강제하고, DN 디스크에서 find /data*/dfs/dn/current -name "blk_<id>*" 로 블록이 살아 있는지 찾은 뒤, 복제본이 전부 없는 파일만 개별 삭제하거나 원본에서 재적재한다. hdfs fsck / -delete 는 missing block 이 있는 모든 파일을 지우므로 임시 파일을 먼저 정리한 뒤 남은 것이 정말 버려도 되는 것일 때만 쓴다. 대량 삭제 후 Hive/Impala 메타 동기화(MSCK REPAIR TABLE, INVALIDATE METADATA) 를 확인한다.
JournalNode 1~2대가 뒤처진 경우, 뒤처진 노드의 JN 을 멈추고 edits 디렉토리를 백업한 뒤 정상 JN 의 current/ 를 복사해 재기동하면 따라잡는다. in_use.lock 은 복사하지 않는다(재기동 시 새로 만들어진다). 재발 방지로 각 JN 로그의 txid 동기화 여부를 주기적으로 본다.
grep "txid" /var/log/hadoop-hdfs/hadoop-hdfs-journalnode-*.log | tail -20