HDFS Namenode, Datanode
네임노드와 데이터노드
HDFS 클러스터는 Master-Worker 패턴으로 동작하는 두 종류의 노드(Master : 1 - Worker : N) 로 구성 되어 있다.
-
NameNode : 파일 시스템의 Namespace를 관리한다. NameNode는 파일시스템 트리와 그 트리에 포함된 모든 파일과 디렉터리에 대한 메타데이터를 유지한다. 이 정보는 namespace 이미지와 edit log 라는 두 종류의 파일로 로컬 디스크에 영속적으로 저장된다. 파일에 속한 모든 블록이 어느 데이터노드에 있는지 파악하고 있지만, 블록의 위치 정보는 시스템이 시작할 때 모든 데이터노드로부터 받아서 재구성하기 때문에 디스크에 영속적으로 저장하지는 않는다.
-
HDFS 클라이언트 : 사용자를 대신해서 NameNode와 DataNode 사이에서 통신하고 파일시스템에 접근한다. HDFS 클라이언트는 POSIX(Portable Operation System Interface)와 유사한 파일시스템 인터페이스를 제공하기 때문에 사용자는 NameNode와 DataNode에 관련된 함수를 몰라도 코드를 작성할 수 있다.
-
DataNode : 파일 시스템의 실질적 일꾼이며, 클라이언트나 네임노드의 요청이 있을 때 블록을 저장하고 탐색하며, 저장하고 있는 블록의 목록을 주기적으로 네임노드에 보고한다.
NameNode 장애복구
NameNode 가 손상되면 파일시스템의 어떤 파일도 찾을 수 없다. DataNode에 Block이 저장되어 있지만 이러한 Block 정보를 이용하여 파일을 재구성할 수는 없기 때문이다.
장애복구 기능 두 가지 안
- 파일시스템의 메타데이터를 지속적인 상태로 보존하기 위해 파일로 백업하는 것이다. 로컬 디스크와 원격의 NFS 마운트 두 곳에 동시에 백업하는 것을 권장한다.</b>
- Secondary namenode 를 운영한다. Secondary namenode의 주 역할은 edit log가 너무 커지지 않도록 주기적으로 namespace 이미지를 edit log와 병합하여 새로운 namespace를 만드는 것이다. Secondary namenode는 주 namenode 에 장애가 발생할 것을 대비해서 Namespace 이미지의 복제본을 보관하는 역할도 맡는다. 하지만 주 namenode의 namespace 이미지는 약간의 시간차를 두고 secondary namenode로 복제되기 때문에 주 namenode에 장애가 발생하면 어느 정도의 데이터 손실은 불가피 하다. 이런 경우 NFS에 저장된 주 namenode의 메타데이터 파일을 secondary namenode에 복사하여 새로 병합된 nmamespace 이미지를 만들고 그것을 새로운 주 namenode에 복사한 다음 실행한다.
Hadoop Safe 모드 HDFS의 세이프모드(safemode)는 데이터 노드를 수정할 수 없는 상태. 세이프 모드가 되면 데이터는 읽기 전용 상태가 되고, 데이터 추가와 수정이 불가능 하며 데이터 복제도 일어나지 않는다. 관리자가 서버 운영 정비를 위해 세이프 모드를 설정 할 수도 있고, 네임노드에 문제가 생겨서 정상적인 동작을 할 수 없을 때 자동으로 세이프 모드로 전환된다.
블록 캐싱
빈번하게 접근하는 블록 파일은 off-heap(자바 힙 외부에서 관리되는) 블록 캐시라는 데이터노드의 메모리에 명시적으로 캐싱할 수 있다. 기본적으로 블록은 하나의 데이터노드 메모리에만 캐싱되지만 파일 단위로 설정할 수도 있다. Job Scheduler(MapReduce, Spark 등)는 블록이 캐싱된 데이터노드에서 테스크가 실행되도록 할 수 있으며, 이러한 블록 캐시의 장점을 이용하면 읽기 성능을 높일 수 있다.
조인을 할 때 작은 룩업 테이블을 캐싱하는 것은 좋은 활용사례이다.
사용자나 어플리케이션은 cache pool에 cache directive를 추가하여 특정 파일을 caching 하도록 명령할 수 있다. 캐시 풀은 캐시 권한이나 자원의 용도를 관리하는 관리 그룹의 역할을 맡는다.
HDFS 페더레이션
NameNode는 파일시스템의 모든 파일과 각 블록에 대한 참조 정보를 메모리에서 관리한다. 따라서 파일이 매우 많은 대형 클러스터에서 확장성에 문제를 일으키는 것은 바로 메모리다. 이러한 확장성 문제를 해결하기 위해 2.x 릴리즈부터 하둡은 HDFS 페더레이션(federation)을 지원하고 있다. HDFS 페더레이션을 활용하면 각각의 NameNode가 파일시스템의 NameSpace 일부를 나누어 관리하는 방식으로 새로운 NameNode를 추가할 수 있다. 예를 들어 /user, /share 각각의 디렉터리를 다른 네임노드들이 관리한다.
HDFS 페더레이션을 적용하면 각 네임노드는 네임스페이스의 메타데이터를 구성하는 네임스페이스 볼륨과 네임스페이스에 포함된 파일의 전체 블록을 보관하는 블록 풀을 관리한다. 네임스페이스 볼륨은 서로 독립되어 있으며, 따라서 네임노드는 서로 통신할 필요가 없고, 특정 네임노드에 장애가 발생해도 다른 네임노드가 관리하는 네임스페이스의 가용성에 영향을 주지 않는다. 그러나 블록 풀의 저장소는 분리되어 있지 않다. 모든 데이터노드는 클러스터의 각 네임노드마다 등록되어 있고, 여러 블록 풀로부터 블록을 저장한다.
HDFS 페더레이션 클러스터에 접근하기 위해 클라이언트는 파일 경로와 네임노드를 매핑한 클라이언트 측 마운트 테이블을 이용한다.
환경 설정에서 ViewFileSystem과 viewfs://URI 를 사용하여 관리할 수 있다.
HDFS 고가용성
데이터 손실을 방지하기 위해 네임노드 메타데이터(네임스페이스 이미지, 에디트 로그)를 다수의 파일시스템에 복제하는 방식과 보조 네임노드를 사용하여 체크포인트를 생성하는 방식을 조합해서 활용할 수 있다. 그러나 이런 방법은 고가용성을 궁극적으로 보장하지는 않는다. 여전히 SPOF 이다.
네임노드에 장애가 발생하면 MapReduce 잡을 포함하여 모든 클라이언트가 파일을 읽거나 쓰거나 조회할 수 없게 된다.(메타데이터와 파일 블록의 매핑 정보를 보관하는 유일한 저장소이기 때문)
네임노드의 장애를 복구하기 위해 관리자는 파일시스템 메타데이터 복제본을 가진 새로운 네임노드를 구동하고 모든 데이터노드와 클라이언트에 새로운 네임노드를 사용하도록 알려주면 되지만 아래와 같은 과정을 거친다.
- 네임스페이스 이미지를 메모리에 로드
- 에디트 로그 갱신
- 전체 데이터노드에서 충분한 블록 리포트를 받아 안전 모드를 벗어날 때 까지 기다린다.
위 과정을 거치면 안전 모드가 해제될 때 동안 그 어떤 요청도 처리하지 못한다.
일상적인 유지관리에서 재가동 시간이 오래 걸리는 것은 당연히 문제가 되며, 실무에서는 계획된 정지 시간(downtime)이 더 중요할 수도 있다.
이 문제를 해결하기 위해 하둡 2.x 릴리즈부터 HDFS 고가용성(High availability) 을 지원한다. active-standby 상태로 설정된 한 쌍의 네임노드로 구현된다.
-
네임노드는 에디트 로그를 공유하기 위해 고가용성 공유 스토리지를 반드시 사용해야 한다. 대기 네임노드가 활성화되면 먼저 기존 활성 네임노드의 상태를 동기화하기 위해 공유 에디트 로그를 읽고, 이어서 활성 네임노드에 새로 추가된 항목도 마저 읽는다.
-
데이터노드는 블록 리포트를 두 개의 네임노드에 보내야 한다. 블록 매핑 정보는 디스크가 아닌 네임노드의 메모리에 보관되기 때문이다.
-
클라이언트는 네임노드 장애를 사용자에 투명한 방식으로 처리할 수 있도록 구성해야 한다.
-
대기 네임노드는 보조 네임노드의 역할을 포함하고 있으며, 활성 네임노드 네임스페이스의 체크포인트 작업을 주기적으로 수행한다.
고가용성 공유 스토리지를 위해 NFS 필러나 QJM(quorum journal manager) 중 하나를 선택할 수 있다. QJM은 HDFS 전용 구현체로, 고가용성 에디트 로그를 지원하기 위한 목적으로 설계되었으며 HDFS의 권장 옵션이다. QJM은 저널 노드 그룹에서 동작하며, 각 에디트 로그는 전체 저널 노드에 동시에 쓰여진다. 일반적으로 저널 노드는 세 개며, 그 중 하나가 손상되어도 문제가 없는 시스템이다. 이러한 방식은 주키퍼의 작동 방식과 매우 유사하지만 QJM은 주키퍼를 사용하지 않고도 이런 기능을 구현했다는 점이 중요하다.
HDFS 고가용성은 활성 네임노드를 선출하기 위해 주키퍼를 이용한다.
활성 네임노드에 장애가 발생하면 대기 네임노드는 매우 빠르게 기존 네임노드를 대체할 수 있다. Active와 standby 네임노드는 모두 최신 에디트 로그와 실시간으로 갱신되는 블록 매핑 정보를 메모리에 유지하고 있기 때문이다. 하지만 실제로 장애 복구 시간을 보면 1분 정도 걸리는데, 시스템이 활성 네임노드에 장애가 발생했다고 판단하는 것은 매우 신중해야 하기 때문이다.
자주 있는 일은 아니지만 활성 네임노드에 장애가 발생할 때 대기 네임노드가 중단된 상태일 수도 있다. 이러한 상황에서도 관리자는 단순히 대기 네임노드를 다시 구동하면 그만이다. 이런한 과정은 하둡의 표준 운영 절차이기 때문에 고가용성을 사용하지 않는 시스템에 비해 나쁠 것도 없고 운영상의 관점에서도 진일보한 기능이다.
장애복구와 펜싱
대기 네임노드를 활성화시키는 전환 작업은 장애복구 컨트롤러라는 새로운 객체로 관리된다. 다양한 방법으로 장애복구 컨트롤러를 구현할 수 있지만 기본 구현체는 단 하나의 네임노드만 활성 상태에 있는 것을 보장하기 위해 주키퍼를 이용한다. 각 네임노드는 경량의 장애복구 컨트롤러 프로세스로 네임노드의 장애를 감시하고(heartbeat 방식 사용) 네임노드에 장애가 발생하면 장애복구를 지시한다.
장애복구는 정기적인 유지관리를 위해 관리자가 수동으로 초기화 할 수 있다. 이를 우아한 장애복구(graceful failover) 라고도 하는데, 장애복구 컨트롤러는 두 개의 네임노드가 서로 역할을 바꾸게 하는 방법으로 전환 순서를 제어할 수 있다.
ungraceful failover 에서는 장애가 발생한 네임노드가 현재 실행되지 않고 있다는 것을 확신하기 어렵다. 예를 들어 네트워크가 느려지거나 단절되어 장애복구를 위한 전환 작업이 시작된 상황에서도 기존의 활성 네임노드는 여전히 실행되고 있고 자신이 활성 네임노드라고 생각할 것이다. 고가용성을 구현하기 위해서는 기존의 활성 네임노드가 시스템을 망가뜨리지 않도록 노력해야하며 이를 위해 펜싱(fencing)이라는 메소드를 제공한다.
QJM은 한 번에 하나의 네임노드만 에디트 로그에 쓸 수 있도록 보장한다. 하지만 기존의 Active NameNode가 Client의 읽기 요청에 대해 잘 못된 정보를 줄 가능성이 있으므로 SSH 펜싱 명령어로 네임노드의 프로세스를 확실히 죽이도록 설정하는 것이 가장 좋은 방법이다. 공유 에디트 로그를 저장하기 위해 NFS 필러를 이용할 때는 한 번에 하나의 네임노드만 허용하는 것이 불가능하므로 좀 더 강력한 펜싱 메소드를 이용해야 해서 QJM 을 권장한다. 네임노드가 공유 스토리지 디렉터리에 접근하는 것을 불허하는 방법부터 원격 관리 명령어로 네트워크 포트를 막는 방법까지 다양한 펜싱 메커니즘이 있다. 최후의 수단으로 기존의 활성 네임노드를 STONITH(Shoot The Other Node In The Head)라고 알려진 방법으로 막을 수 있는데, 이것은 호스트 머신의 전원을 강제로 내려버리는 특별한 전원 분삭 유닛(PDU : Power Distrubution Unit)을 이용하는 기술이다.
클라이언트 장애복구는 클라이언트 라이브러리로 명확하게 처리된다. 가장 단순한 방법은 장애 복구 제어를 위한 클라이언트 측 설정을 이용하는 것이다. HDFS URI는 한 쌍의 네임노드 주소를 매핑한 논리적인 호스트명을 사용하고, 클라이언트 라이브러리는 성공할 때 까지 각 네임 노드의 주소로 연결을 시도한다.