- 소스 코드 컴파일 및 환경 준비 하둡의 핵심 컴포넌트인 NameNode의 동작 원리를 이해하기 위해 먼저 소스 코드를 컴파일해야 합니다. 지원되는 버전 범위: Hadoop 2.6 ~ 2.7 (기능 변경이 크지 않음) 컴파일 가이드 참고 링크:
빌드 실패는 흔한 현상이며, protocol 등 필수 종속성만 정확히 설정된다면 문제 없음.
- NameNode 메인 진입점 탐색 NameNode 실행 시 가장 먼저 호출되는 진입점은 다음과 같은 정적 메서드입니다:
public static void main(String argv[]) throws Exception {
if (DFSUtil.parseHelpArgument(argv, NameNode.USAGE, System.out, true)) {
System.out.println("옵션 검증 완료");
System.exit(0);
}
try {
StringUtils.startupShutdownMessage(NameNode.class, argv, LOG);
NameNode namenode = createNameNode(argv, null);
if (namenode != null) {
namenode.join(); // 메인 스레드 대기, 종료 시까지 기다림
}
} catch (Throwable e) {
LOG.error("NameNode 시작 실패", e);
terminate(1, e);
}
}
해당 메서드는 hadoop-daemon.sh start namenode 또는 hdfs 명령어로 실행될 때 자동으로 호출되며, 실제 초기화 로직을 createNameNode로 위임합니다.
- createNameNode 메서드 내부 구조 분석
createNameNode(argv, conf)메서드는 다양한 실행 옵션에 따라 처리를 분기합니다:
public static NameNode createNameNode(String argv[], Configuration conf)
throws IOException {
LOG.info("NameNode 생성 중: " + Arrays.asList(argv));
if (conf == null) conf = new HdfsConfiguration();
StartupOption startOpt = parseArguments(argv);
if (startOpt == null) {
printUsage(System.err);
return null;
}
setStartupOption(conf, startOpt);
switch (startOpt) {
case FORMAT:
boolean aborted = format(conf, startOpt.getForceFormat(), startOpt.getInteractiveFormat());
terminate(aborted ? 1 : 0);
return null;
case GENCLUSTERID:
System.err.println("클러스터 ID 생성:");
System.out.println(NNStorage.newClusterID());
terminate(0);
return null;
case FINALIZE:
System.err.println("FINALIZE 옵션은 더 이상 지원되지 않습니다. 업그레이드 완료 후 `hdfs dfsadmin -finalizeUpgrade` 실행 필요.");
terminate(1);
return null;
case ROLLBACK:
boolean rollbackAborted = doRollback(conf, true);
terminate(rollbackAborted ? 1 : 0);
return null;
case BOOTSTRAPSTANDBY:
String[] toolArgs = Arrays.copyOfRange(argv, 1, argv.length);
int rc = BootstrapStandby.run(toolArgs, conf);
terminate(rc);
return null;
case INITIALIZESHAREDEDITS:
boolean initAborted = initializeSharedEdits(conf, startOpt.getForceFormat(), startOpt.getInteractiveFormat());
terminate(initAborted ? 1 : 0);
return null;
case BACKUP:
case CHECKPOINT:
NamenodeRole role = startOpt.toNodeRole();
DefaultMetricsSystem.initialize(role.toString().replace(" ", ""));
return new BackupNode(conf, role);
case RECOVER:
NameNode.doRecovery(startOpt, conf);
return null;
case METADATAVERSION:
printMetadataVersion(conf);
terminate(0);
return null;
case UPGRADEONLY:
DefaultMetricsSystem.initialize("NameNode");
new NameNode(conf);
terminate(0);
return null;
default:
DefaultMetricsSystem.initialize("NameNode");
return new NameNode(conf); // 일반적인 NameNode 시작 경로
}
}
주요 실행 옵션들:
-format: 디스크 저장소 초기화-genclusterid: 새로운 클러스터 식별자 생성-upgradeonly: 업그레이드 모드로 시작-bootstrapstandby: 스탠바이 노드 초기화-rollback: 롤백 작업 수행
정상적인 서비스 시작 시 default 브랜치로 진입하여 new NameNode(conf)를 통해 인스턴스 생성.
- NameNode 생성자 내부 로직 생성자는 다음과 같은 단계를 거칩니다:
protected NameNode(Configuration conf, NamenodeRole role) throws IOException {
this.conf = conf;
this.role = role;
// 클라이언트 연결 주소 설정 (fs.defaultFS)
setClientNamenodeAddress(conf);
String nsId = getNameServiceId(conf);
String namenodeId = HAUtil.getNameNodeId(conf, nsId);
// 고가용성 여부 확인
this.haEnabled = HAUtil.isHAEnabled(conf, nsId);
// 초기 상태 결정 (예: Standby)
state = createHAState(getStartupOption(conf));
this.allowStaleStandbyReads = HAUtil.shouldAllowStandbyReads(conf);
// HA 컨텍스트 생성
this.haContext = createHAContext();
try {
initializeGenericKeys(conf, nsId, namenodeId);
initialize(conf);
// HA 상태 전환 처리
try {
haContext.writeLock();
state.prepareToEnterState(haContext);
state.enterState(haContext);
} finally {
haContext.writeUnlock();
}
} catch (IOException | HadoopIllegalArgumentException e) {
stop();
throw e;
}
this.started.set(true);
}
핵심 구성 요소:
namesystem: 파일 시스템 메타데이터 관리 (블록, 데이터노드 제어)conf: 설정 정보 저장role: 현재 역할 (Active, Standby, Backup 등)state: HA 상태 (Active/Standby 등)haEnabled: 고가용성 활성 여부haContext: HA 관련 컨텍스트rpcServer: RPC 서비스 제공 (외부 클라이언트 및 DataNode 통신)
이 과정에서 중요한 부분은 initialize(conf) 메서드이며, 다음 글에서 이 함수 내부에서 수행되는 작업들 — 메트릭 설정, 보안 인증, 웹 서비스 시작, 메타데이터 로드, RPC 서버 생성, 공통 서비스 시작 — 을 상세히 살펴볼 예정입니다.