하둡 완벽 가이드 - 3. 하둡 분산 파일시스템
본문 바로가기


Programmer/hadoop

하둡 완벽 가이드 - 3. 하둡 분산 파일시스템

사용자의 입장으로만 하둡을 바라보게 되어 깊이가 부족하다는 생각을 하게 되었다.
하둡 완벽 가이드를 읽고 이해한대로 정리한다.


분산 파일 시스템: 네트워크로 연결된 여러 머신의 스토리지를 관리하는 파일시스템
하둡의 분산 파일 시스템: HDFS (Hadoop Distributed FileSystem)로 추상화되어 S3나 로컬 파일시스템도 가능

3.1 HDFS 설계

HDFS는 매우 큰 파일스트리밍 방식(읽기 시작한 이후로 순서대로 출력)으로 접근할 수 있도록 범용 하드웨어(싼 것도 상관 없이)를 활용하여 저장할 수 있도록 설계되었다.

그러므로, 수많은 작은 파일(파일 하나는 기본으로 하나의 블록이므로 네임노드에 블록의 위치를 기록하기 위한 용량을 많이 차지)을 저장하고, 빠르게 읽고(스트리밍 방식이므로 읽기 시작 로딩시간이 김), 파일을 업데이트 하는 작업에는 맞지 않는다.

3.2 HDFS 개념

3.2.1 블록

단일 디스크를 위한 파일 시스템에서의 블록과는 다르게, 추상화된 논리적인 개념이다. 블록의 용량은 청크의 최대 크기를 의미하고 더 작은 청크가 생긴다고 해서 블록 크기의 디스크를 사용하는 것이 아니라 청크 크기의 디스크만 사용한다. 

블록의 사이즈는 상당히 큰 편인데, HDFS는 탐색 시작보다 탐색 완료의 속도를 더 중요하게 생각하도록 설계하였기 때문이다. 그러나 블록이 너무 크면 청크의 사이즈가 과하게 커질것이며, 청크별로 task가 생성되므로 오히려 속도가 과도하게 느려질 수 있다.

이로 인해 얻을 수 있는 이점이 있는데, 청크로 나누어 데이터를 저장하므로 아주 큰 파일을 저장할 수 있고, 블록단위로 추상화 하였으므로, 다양한 사이즈의 파일이 아니라 고정된 블록 사이즈로 스토리지 서브시스템을 단순하게 관리할 수 있으며, 여러개의 디스크에 동일한 블록을 저장하여 내고장성(fault tolerance)과 가용성(availability)을 보장할 수 있다.

3.2.2 네임노드와 데이터노드

HDFS는 마스터-워커 패턴으로 네임노드-데이터노드로 구성된다.

네임노드는 파일 시스템의 네임스페이스(파일시스템 트리와 모든 메타데이터)를 관리하고, 네임스페이스 이미지와 에디트 로그라는 파일을 로컬 디스크에 영속적으로 저장한다. 해당 정보는 장애 복구를 위해 사용되며, 원격 NFS 마운트에도 함께 복제되거나 보조 네임노드 혹은 대기 네임노드를 주기적으로 동기화 하여 HDFS의 가용성을 보장한다. 또한 네임노드는 블록의 위치도 임시로 기억하고 있다.

데이터노드는 블록 용량으로 청킹된 데이터를 저장하고 있는 노드로, 요청을 처리하고, 저장하고 있는 블록의 목록을 주기적으로 네임노드에 보고한다.

HDFS 클라이언트는 POSIX와 유사한 인터페이스로 네임노드와 데이터 노드 사이에서 통신하고 파일시스템에 접근할 수록 구성되어있다.

3.2.3 블록 캐싱

데이터노드의 메모리에 명시적으로 블록을 캐싱하여 읽기 성능을 높힐 수 있다. 사용자나 애플리케이션이 캐시 풀에 캐시 지지자를 추가하여 캐시를 관리하는 방법도 있다.

3.2.4 HDFS 페더레이션

여러 네임노드를 띄워 디렉토리 별로 관리하는 기능으로, 각 네임노드가 네임스페이스 볼륨(네임스페이스의 메타데이터가 저장된 디스크)과 블록 풀(네임스페이스가 관리하는 파일의 전체 블록)을 관리한다. 이때, 블록 풀에 등록되어있는 데이터 노드는 각 네임노드마다 등록되어 있다. (디렉토리 내 파일들이 여러 데이터노드에 분산 저장되어있기 때문)

3.2.5 HDFS 고가용성

2.x 릴리즈부터 지원하기 위하여 활성 네임노드 외에도 대기 네임노드가 구성되었다.

이러한 방식 지원을 위해
대기 네임노드와 에디트로그를 공유하기 위하여 고가용성 공유 스토리지를 반드시 사용하고,
데이터 노드가 블록 리포트를 활성/대기 두개의 네임노드 모두에게 보내야 하며,
클라이언트가 사용자에게 이슈를 투명하게 공유해야하고
활성 네임노드 네임스페이스의 체크포인트 작업을 대기 네임노드가 주기적으로 수행해야하도록 구성되었다.

장애복구를 위해 활성 네임노드에 health check를 진행하다가 1분 정도 문제가 있으면 대기 네임노드가 띄워지도록 장애복구 컨트롤러라는 객체가 사용되며, 1분 내에 네임노드의 구성을 손상시키지 않기 위해 펜싱이라는 메서드가 제공된다. 

3.3 명령행 인터페이스

HDFS는 POSIX와 유사한 인터페이스로 구성되어 파일 시스템을 쉽게 조작할 수 있도록 구성하였다.
관련 정보는 리눅스를 사용할 수 있는 사용자라면 쉽게 찾아 활용 할 수 있다.

3.4, 3.5 하둡 파일시스템 및 인터페이스

하둡은 파일 시스템의 추상화 개념을 가지고 있어 다양한 파일시스템(webhdfs, swebhdfs, har, viewfs, ftp, s3a, wasb, swift)이 존재한다. 해당 파일시스템을 위한 인터페이스 역시 지원하고 있으며, JAVA, HTTP, C, NFS, FUSE등이 존재한다.

3.6 데이터 흐름

3.6.1 파일 읽기

1. HDFS 클라이언트가 DistributedFileSystem 인스턴스인 FileSystem 객체의 open()메서드로 원하는 파일을 연다
2. DistributedFileSystem가 RPC 통신으로 네임노드에서 파일의 첫번째 몇개의 블록들의 위치를 받아온다. 네임노드에서는 각 블록의 복제본이 저장된 데이터노드 주소를 모두 반환한다. 이 주소의 데이터노드는 클러스터의 네트워크 위상에 따라 클라이언트와 가까운 순으로 정렬된다.
3. FSDataInputStream이 열리면 read() 매서드로 읽어온다.
4. DSFInputStream이 데이터 노드와 연결해 계속 read()를 호출하면 클라이언트로 모든 데이터가 전송된다.
5. DSFInputStream가 그 다음 블록이 존재하는 제일 가까운 데이터 노드를 찾는다.
6. 모든 블록의 읽기가 끝나면 클라이언트가 FSDataInputStream의 close() 메서드를 호출한다.

데이터를 읽는 중 데이터노드에 장애가 발생하면 DSFInputStream가 그 다음으로 가까운 데이터 노드를 찾는다. 해당 정보는 네임노드에 보고된다.

이 과정에서 네임노드에서 진행되는 일은 거의 없으므로, 병목현상 역시 거의 발생하지 않는다.


데이터노드를 선택할 때 가까운 노드를 선택한다고 표현하고 있는데, 대역폭이 가장 짧은 것을 가깝다고 표현한다. 실제로 측정할 수는 없어 하둡에서는 동일 노드, 동일 랙의 다른 노드, 동일 데이터 센터에 있는 다른 랙의 노드, 다른 데이터 센터에 있는 노드 순으로 가용 대역폭이 점차 줄어든다고 가정한다.

이때, "동일 랙"을 어떻게 측정하느냐가 궁금하였는데, 하둡에는 Rack Awareness (랙 인식)이라는 개념이 있어 하둡의 관리자가 수동으로 랙 번호를 정의할 수 있도록 되어있다고 한다.


 

3.6.2 파일 쓰기 상세

1. 클라이언트는 DistributedFileSystem의 create()를 호출하여 파일을 생성한다.
2. DistributedFileSystem은 파일시스템의 네임스페이스에 새로운 파일을 생성하기위해 네임노드에 create RPC요청을 보낸다. 네임노드는 요청한 파일과 동일한 파일이 있는지, 권한이 있는지 등의 검사를 수행한다. 검사 통과 후 새로운 파일의 레코드를 만든다.
3. DistributedFileSystem은 클라이언트에 FSDataOutputStream을 반환하고 데이터 노드와 네임노드의 통신을 처리하는 DFSOutputStream으로 래핑된다.
4. 클라이언트가 데이터 쓸때
5. DFSOutputStream이 데이터를 패킷으로 분리하고, 데이터 큐로 패킷을 보낸다. DataStreamer가 큐에 저장된 패킷을 처리한다. 네임노드에 복제본을 저장할 데이터노드의 목록을 요청하고, 각 복제 데이터가 저장될 데이터노드는 파이프라인을 구성하여 차례대로 데이터를 저장한다. 각 데이터노드는 저장이 완료될 때 ack 패킷을 보낸다.
6. ack 큐에 모든 패킷을 받는다
7. 데이터 쓰기를 완료할 때 클라이언트는 스트림에 close() 매서드를 호출한다.
8. 네임노드에 파일 쓰기 완료 신호를 보낸다.

 

3.6.3 일관성 모델

파일에 대한 읽기와 쓰기의 가시성은 파일시스템의 일관성 모델로 설명할 수 있다. HDFS는 성능을 위해 일부 POSIX 요구사항을 포기했는데, 그중 하나는 close 메서드를 호출하여 네임노드에 완료 신호를 보내기 전까지는 읽을 수 없다는 것이다.

쓰기 중간에 읽기를 원한다면 close()나 hflush()가 아닌 hsync() 메서드를 사용하거나  hflush()를 자주 호출해야 한다. 그러나 오버헤드가 있으므로 적절히 수행해야한다.

3.7 distcp로 병렬 복사하기

distcp는 리듀서 없는 맵리듀스 잡으로 구현되어있고, 클러스터 전반에 걸쳐 병렬로 수행되는 맵 태스크를 이용하여 복사작업을 한다. 기본적으로 최대 20개의 맵이 사용된다.

HDFS는 클러스터 전반에 걸쳐 파일 블록이 고르게 분산되었을 때 가장 잘 작동하므로, 균형 유지를 위해 distcp를 사용할 때 맵의 사이즈를 잘 정해야한다.
맵의 사이즈를 적절히 정하지 못하는 상황이라면 balancer 도구를 사용할 수도 있다.