본문 바로가기
일하는 중에

하둡 데몬(namenode, datanode)의 기동과정과 메커니즘 이해

by likebnb 2015. 9. 14.

2010년 무렵 하둡을 처음 접한 뒤로 개발자로서의 내 삶은 많은 변화가 있었다. 내 머릿 속에 개념으로만 존재하던 분산 컴퓨팅이 일상의 개발환경이 된 것이 그 첫번째 일 것이다. 하둡과 함께 내 삶의 현장에서 일어났던 그리고 겪고 있는 이야기들을 기록하고자 한다.


사내에서 교육을 위해 정리한 자료 중 하둡의 주요 데몬들이 기동하는 과정에 서로 커뮤니케이션하는 내용을 다음과 같이 정리해봤다. 몇몇 책에서도 설명이 되어 있지만 데몬들이 기록하는 로그를 면밀하게 살펴가면서 내가 이해한 대로 그려본 것이다.


하둡은 여러 개의 브랜치가 있는데 최근에는 크게 1.x, 2.x 그리고 아직 공식 릴리즈는 없지만 로드맵 상에 3.x가 발표되어 있다. 이 글에서 언급하는 하둡은 2.x 브랜치로 2.0.0 버전이다. 


[그림 1] hadoop-hdfs 주요 데몬의 기동 과정



A. NameNode

아파치 하둡 버전 2.0부터는 NameNode를 2대로 구성한 HA(High Availability)를 지원한다. 이전 버전에 존재하던 Secondary NameNode 대신 Standby NameNode가 등장한다. 기본적으로 HA 구성된 NameNode들은 처음 기동 시에는 모두 Standby로 동작한다. 설정값들을 점검하고 디스크에 저장되어 있던 마지막 스냅샷(FsImage)을 메모리에 불러오고 스냅샷을 찍은 이후의 변경 로그(Edit Log)들을 반영하는 등의 서비스를 위한 기본 작업을 마치고 나면 8020, 8022포트를 열어 Standby 상태로 서비스를 시작한다.


이렇게 Standby 서비스를 시작한 것을 감지한 후에 HAAdmin Tool로 강제 failover 명령을 NameNode 서비스에 날려 두 대의 Standby 중 하나를 Active로 전환하면 Active로 전환된 NameNode는 Edit Log를 쓰기 모드로 전근할 수 있게 된다. 더불어 HDFS의 클라이언트들도 비로소 읽기, 쓰기 작업을 Active NameNode에게 요청할 수 있게 된다. 클라우데라의 CDH에서는 cloudera-scm-server가 forcefailover 명령을 날려 준다. 이 때 부터 정상적인 서비스를 시작하게 되는 것이다.


1. STARTUP_MSG


hadoop-hdfs NameNode STARTUP_MSG

[그림 2] NameNode의 기동과 함께 제일 먼저 보여주는 메시지


NameNode가 기동되면 제일 먼저 그림 2와 같은 기동메시지(STARTUP_MSG)를 내보낸다. 어떤 버전의 하둡이 어떤 환경에서 기동되는지를 보여주는 정보로 데몬이 실행되는 호스트 이름과 IP Address는 물론이고 하둡의 버전과 각종 라이브러리가 저장되어 있는 클래스경로 그리고 JDK 버전 등이 나열된다. 그림에서는 보여주고 있지 않지만 뒤를 이어 클러스터의 멤버인 DataNodes의 목록을 읽어들인다던가 데몬의 실행에 직접적으로 영향을 미치는 각종 환경 설정값들을 읽어들이는 과정들이 따른다.


2. Load FSImage from Disk

분산파일시스템(HDFS)과 분산컴퓨팅 프레임워크(MapReduce)는 하둡의 양대 축이라 할 수 있다. 이들 중 하둡의 근간을 이루는 것은 역시 HDFS(Hadoop Distributed File System)인데 익히 잘 알고 있는 FAT, NTFS, EXT2, EXT3, EXT4, HFS, HFS+ 등과 같은 OS에서 제공하는 파일시스템과 크게 다르지 않다. 실제 데이터를 저장하는 블럭(Block)과 데이터 블럭의 메타정보를 관리하는 메타데이터로 이원화된 구조 역시도 동일하다. 다만 한 가지 다른 점은 일반적인 파일시스템은 데이터 블럭을 물리적으로 하나의 호스트에 연결된 디스크(들)에 저장하는 반면 HDFS는 물리적으로 다수의 호스트에 연결된 디스크들에 분산 저장된다는 것이다.


[그림 3] NameNode의 fsimage가 기록된 디렉토리 구조(Hadoop The Definitive Guide)


데이터 블럭들을 읽고 쓰는 것은 DataNodes의 역할이고 NameNode는 이렇게 분산된 데이터 블럭들을 하나로 통합하고 하나의 논리적 디스크 볼륨으로 바라볼 수 있도록 해준다. 수백만에서 수천만 개에 이르는 데이터 블럭들에 대한 조회를 실시간으로 처리하기 위해서 NameNode는 블럭들의 메타데이터를 메모리에 적재하여 관리한다. 당연한 얘기지만 휘발성인 메모리에 저장된 메타데이터는 영구보존을 위해 그 스냅샷을 디스크로 정기적으로 기록해야 한다. 이 스냅샷 이미지가 바로 그림 3에서 보는 fsimage이다. 그림 4에서는 fsimage를 읽어들이기 직전에 in_use.lock 파일을 먼저 생성하여 파일시스템에 잠금을 설정하고 fsimage 파일을 읽어서 메모리에 적재한다. 일반적으로 hdfs-site.xml에 NameNode를 위한 디렉토리를 dfs.namenode.name.dir으로 지정한다. 그림 4의 경우엔 /data/dfs/nn으로 지정했다. 


[그림 4] NameNode 기동 로그 중 fsimage를 지정된 경로에서 읽어서 메모리로 적재하는 과정


3. Update Metadata with Edit Log

대부분의 in-memory 방식의 솔루셔들이 그렇듯 데이터의 영속성(persistence)과 성능 사이의 트레이드 오프가 중요하다. 하둡 HDFS의 NameNode는 이 문제를 해결하기 위하여 전체 메타데이터의 스냅샷과 이후 새롭게 발생하는 메타데이터의 변화를 로그(incremental)로 기록하는 방법을 쓴다. 일정한 주기(2분 마다)로 계속 롤링되는 이 Edit Log들을 관리하는 데몬을 JournalNode라 부른다. 


그러므로 fsimage를 메모리로 적재한 다음엔 JournalNode가 관리하는 Edit Log들 중에서 Commit되지 않은 것들을 찾아 메모리 상의 메타데이터에 반영하는 과정을 거치게 된다. 그림 5는 이 때 기록되는 로그의 예이다.


[그림 5] fsimage를 메모리에 적재한 후 Edit Log를 반영함 



4. Finished loading FSImage

앞서 설명한 바와 같이 메모리에서 관리되는 메타데이터의 스냅샷인 FSImage는 성능 상의 이유로 자주 만들 수가 없다. 대신 마지막 스냅샷을 작성한 후의 변경 내역들은 Edit Log라는 상대적으로 작은 크기의 파일로 기록하고 이 Edit Log를 주기적으로 FSImage에 반영하는 방법으로 스냅샷을 유지한다. 자세한 메커니즘은 JournalNode에 대한 설명에서 하도록 하겠다. NameNode의 기동과정에서 메타데이터의 적재는 fsimage의 적재 그리고 Edit Log에 기록된 변경분의 반영으로 완성된다. 그림 5의 마지막 줄에 기록된 로그를 참고하라. 


5. Leave Safe Mode

fsimage와 Edit Log가 모두 메모리에 반영되면 common Services를 시작하게 되는데 이 과정에서 NameNode의 자원을 점검하고, Safe Mode로 진입한 뒤 블럭정보를 조사하여 최소한의 복제수를 충족하는 블럭들이 일정 수준 이상인지 여부를 확인하고 충족하는 경우 Safe Mode를 해제한다. 이후 blockMamanger를 활성화하고 NameNode의 메트릭정보를 제공할 MBean을 등록한다. NameNode를 포맷한 뒤 처음 실행하는 경우엔  Safe Mode에 머무는 시간이 아주 짧다.


[그림 6] NameNode를 최초로 기동한 경우 Safe Mode에서 빠져 나오는 시간이 짧다


6. Service Up(Standby)

NameNode는 configuration에 정의된 설정을 근거로 자신이 운영할 클러스터가 HA가 가능한 구성인지 여부를 판단한다. 그리고 HA가 가능한 경우라면 두 개의 NameNode들은  Standby 상태로 서비스를 시작한다. REST 형식의 API 요청을 처리할 HTTP 서버를 50070 포트로 서비스하고, IPC(RPC) 서비스를 위해선 8020과 8022 두 개의 포트를 리스닝하게 된다. 아래 그림 7을 보면 새 개의 포트를 정상적으로 시작한 후에 Edit Log가 2분(120초)에 한 번 씩 롤링될 것이라는 메시지가 보이고 이어서 standby checkpoint 쓰레드를 시작하는 것이 보인다. checkpoint 서비스는 HA 이전의 Secondary NameNode와는 다른 Hot-Standby NameNode를 구현한 서비스로 fsimage에 Edit Log를 반영하여 일정 주기로 Active NameNode로 전달하여 fsimage를 갱신하는 역할을 수행한다. 기본 설정대로 하자면 1분(60초)에 한 번 씩 아직 체크되지 않은 트랜잭션(Edit Log)이 있는지 점검하고 한 시간(3600초)에 한 번 씩 checkpoint를 실시하도록 되어 있다.


[그림 7] HA 구성의 NameNode는 최초 standby로 기동하며 50070, 8020, 8022 포트를 서비스 한다



7. Adding a New Node

NameNode가  standby 서비스를 시작하면 이를 기다리고 있던 DataNode들이 등록(register)을 시도한다. NameNode는 이 요청에 부응하여 자신이 관리하는 네트워크 토폴로지에 요청의 당사자인 DataNode를 새로운 노드(new node)로 추가한다. 


8. Process Report

노드가 추가된 사실을 통보 받은 DataNode는 자신이 관리하는 데이터 블럭들을 스캔하고 이 정보를 NameNode에 보고한다. NameNode는 자신이 가지고 있는 블럭들의 메타정보와 방금 보고 받은 DataNode의 블럭정보를 서로 매핑하여 각 블럭의 위치를 파악하게 된다. 다시 한 번 설명하자면 NameNode의 기동과정에 디스크로부터 메모리로 적재한 FsImage에는 블럭 자체의 메타정보만 있고, 이 블럭이 어느 DataNode에 위치하는지에 대한 정보는 없는 것이다. DataNode가 자신을 클러스터에 등록한 뒤 Nae=meNode에 블럭 의 위치 정보를 보고하면 비로소 메타정보와 위치정보를 매핑하여 완전한 블럭맵을 서비스하게 되는 것이다. 이렇게 하는 것은 클러스터 내에서 DataNode를 좀 더 유연하게 관리하기 위함이다.  


[그림 8] DataNode의 노드 등록 요청을 처리한 후 등록된 DataNode로 부터 block report를 받아 처리한다


9. FailOver(from standby to active)

HA로 구성된 NameNode들은 기동하면 곧 바로 standby로 동작하도록 되어 있다(NameNode 클래스의 코드를 읽어보면 알 수 있다). 누군가 active로 상태를 전환하라는 메시지를 보내지 않는 한 NameNode는 스스로 active 상태로 전환하지 않는다. 잘 생각해보면 그게 당연한 얘기다. 고가용성이라 함은 장애가 발생하더라도 서비스가 중단되지 않도록 하는 것인데 상태전환에 대한 책임이 NameNode 자신에게 있다면 그 자신인 NameNode에 문제가 발생했을 때는 어떻게 한단 말인가! 그래서 상태를 감시하고 전환을 결정하고 명령을 내리는 주체는 NameNode가 아닌 다른 프로세스가 담당하도록 설계한 것이다. 그리고 이 임무는 HAAdmin이라는 클래스에게 위임됐다. 그리고 Cloudera Manager에서는 NameNode 두 대가 모두 정상적으로 standby로 동작하기 시작하면 다음의 그림 9에서와 같이 FailOver 명령을 내리게 된다. 물론 이 명령을 수행하는 것은 HAAdmin 클래스가 될 것이다.


[그림 9] FailOver 명령을 전달하는 Cloudera Manager





10. Start Active State

다음 그림 9에서 standby로 서비스 하던 NameNode가 active로 전환하라는 요청을 받아 active 서비스를 시작하는 것을 볼 수 있다. standby 자격으로 JournalNode와 연결했던 클라이언트 세션은 종료하고 이제 active 자격으로 새로이 연결한다. active NameNode는 블럭정보의 변화를 Edit Log에 기록해야 하기 때문이다. 


[그림 10] HAAdmin으로 부터 전환 요청을 받은 NameNode가 active 서비스를 시작 



11. Edit Log Tailer

Active NameNode는 자신에게 들어온 요청들(파일의 생성, 변경, 삭제)을 처리하기 앞서 Edit Log를 기록해야 한다. 물론 Edit Log의 기록은 JournalNode와 연계하여 이루어진다.  Standby로 동작하던 NameNode가 Active로 상태를 전환하면 더 이상 EditLogTailer 동작을 하지 않게 된다. Edit Log Tailer의 역할은 마지막으로 commit된 Edit Log 세그먼트의 트랜잭션들을 FSImage에 적용하는 일이기 때문이다. 이러한 동작은 Active에서는 필요치 않다. 왜? 한 번 곱씹어 보시길...


[그림 11] Edit Log Tailer는 active로 전환한 NameNode에서는 더 이상 필요치 않다.



여기까지 하둡의 NameNode가 기동되는 과정을 살펴봤습니다. 이후엔 하둡의 HDFS에서 파일을 읽거나, 새로운 파일을 생성하고 쓰는 과정도 로그를 기반으로 설명해 보도록 하겠습니다.