본문 바로가기

갈아먹는 BigData[2] HDFS(하둡 분산 파일 시스템)

지난 글

갈아먹는 BigData [1] MapReduce 이해하기

들어가며

지난 포스팅에서 빅 데이터의 분산 저장 및 분산 처리의 시작을 연 MapReduce에 대해서 자세히 살펴보았습니다. 하둡은 이를 구현하여 오픈 소스화 시킨 프로젝트입니다. 하둡을 기반으로 이를 더 잘 활용하기 위한 각종 오픈 소스들이 등장하기 시작했으며 이를 hadoop ecosystem이라고 부릅니다. 이를 간단히 다이어그램으로 표현하면 아래와 같습니다.

Fig1. Hadoop Ecosystem

보기만 해도 살짝 현기증이 나죠?ㅎㅎ 수많은 에코 시스템들이 하둡 클러스터 위에 얹혀지지만 가장 아래에 기반을 이루는 것은 HDFS, 하둡 파일 시스템입니다. 이는 대용량의 파일을 수천대의 컴퓨터를 묶어 구성한 클러스터에 안정적으로 저장해주는 storage 역할을 수행하며 하둡 에코 시스템에서 아주 중요한 역할을 수행합니다.

 

HDFS는 하둡 프로젝트 초기에 야후의 주도로 개발되었습니다. 그리고 야후에서 발표한 HDFS 논문[1]은 인용 수가 무려 5100회에 달할 정도로 이후의 분산 파일 저장 시스템에 많은 영향을 줍니다. 이번 시간에는 이러한 HDFS가 어떠한 방식으로 파일을 나누어 저장하고, fault tolerance에 대비하는 지를 자세히 들여다보겠습니다.

File System

HDFS를 다뤄보기에 앞서서 파일 시스템에 대한 개념을 정리하고 넘어가겠습니다. 우리는 파일을 작성하고, 수정하며, 삭제하고, 복잡한 구조의 폴더를 생성하여 파일을 관리하는 등의 작업을 합니다. 하지만 어떻게 이런 작업들이 가능해질까요? 파일 시스템이란 컴퓨터에서 파일이나 자료를 쉽게 발견 및 접근할 수 있도록 보관 또는 조직하는 체제를 가리키는 말입니다.[1] 아래 다이어그램을 살펴보겠습니다.

우리가 실제 디스크에 파일을 저장하는 작업은 실제로는 응용 프로그램과 운영체제를 통해서 수행되는 것입니다. user-level에서 작동하는 응용 프로그램을 통해서 사용자는 파일을 읽거나 쓰고, 삭제하는 등의 명령을 내립니다. 그러면 kernel-level에서 동작하는 운영 체제에 포함된 파일 시스템 프로그램이 이를 수신하여 실제 하드웨어에서 파일을 읽거나 쓰는 등의 작업을 수행합니다.

 

파일 시스템 역시 프로그램이기 때문에 종류가 다양한데 디스크 파일 시스템, 데이터 베이스 파일 시스템, 트랜젝션 파일 시스템 등이 있습니다. HDFS(하둡 분산 파일 시스템) 역시 이러한 파일 시스템 중에 하나입니다. 가장 큰 특징이 있다면 수천대의 컴퓨터로 이루어진 클러스터에 파일을 분산시켜 저장할 수 있다는 것입니다. 그렇다면 이러한 시스템이 왜 필요했고, 어떻게 구현할 수 있는지 원리를 하나하나씩 뜯어보겠습니다.

HDFS Architecture

하둡은 구글이 제시한 MapReduce 프로그래밍 모델을 구현한 오픈 소스 프로젝트 입니다. 이는 한 대의 머신에 저장하고 처리하는 것이 불가능한 크기의 데이터를 여러대의 컴퓨터에 분산 저장 및 처리할 수 있는 것을 목표로 합니다. (MapReduce에 대해서 생소하신 분들은 이전 포스팅[3]을 참고해주세요.) HDFS는 클러스터에 파일을 분산하여 저장하고 이를 적절히 관리해주는 역할을 합니다. 그렇다면 HDFS가 전반적으로 어떻게 구성되었는지 살펴보겠습니다.

Fig2. HDFS Architecture[4]

 

 

먼저 전반적으로 HDFS는 Namenode, Datanode, Client 모듈로 구성되어 있습니다. Namenode는 전체적인 HDFS가 어떻게 구성되어 있는지, 어디에 어떤 블록이 저장되어 있는지 등 HDFS의 메타 데이터를 관리하는 역할을 합니다. Datanode는 실제적으로 파일을 저장하는 역할을 합니다. Client는 사용자가 작성한 프로그램으로 이 HDFS에 파일을 쓰거나 읽는 작업을 요청합니다.

HDFS 파일 저장 방식

HDFS는 파일을 분산 저장하기 위해서 먼저 파일의 메타 데이터와 컨텐츠 데이터를 분리합니다. 메타 데이터는 파일의 접근 권한, 생성일, 수정일, 네임 스페이스 등 파일에 대해 설명하는 정보들이 해당합니다. 컨텐츠 데이터는 실제 파일에 저장된 데이터를 말합니다. 파일의 메타데이터는 네임 노드에 저장되며 컨텐츠 데이터는 블록 단위로 쪼개져서 데이터 노드에 저장됩니다. 블록의 기본 크기는 128MB이며 최소 3개의 복사본을 생성하여 분산 저장합니다. 아래 다이어 그램은 하나의 파일이 어떻게 블록 단위로 쪼개어지는 지 보여줍니다.

블록을 데이터 노드에 분산 저장하였기 때문에 네임 노드는 하나의 파일을 구성하는 블록들의 리스트와 어디에 저장되었는 지를 기록해주어야 합니다. 데이터 노드 역시 블록과 함께 블록에 대한 메타 데이터를 저장해주어야합니다.

NameNode

네임 노드는 파일의 메타 데이터를 inode에 저장합니다. inode란 unix 파일 시스템에서 사용되는 폴더 구조를 저장하는 구조체를 말합니다. 또한 네임 노드에는 파일 구성하는 블록들의 목록과 위치 정보가 저장되어 있습니다. 이러한 네임 노드는 HDFS에 파일을 읽거나 쓰는 작업의 시작점 역할을 수행합니다.

 

파일 읽기 작업

1. 클라이언트는 네임 노드에 파일의 네임 스페이스에 해당하는 블록들의 목록과 주소를 요청

2. 클라이언트는 가장 가까이 위치한 데이터 노드에서 블록을 읽어옴

 

파일 쓰기 작업

1. 클라이언트는 네임 노드에게 어드 데이터 노드에 블록을 쓰면 좋을지 요청

2. 네임 노드가 데이터 노드를 할당

3. 클라이언트는 블록을 쓰기 위한 데이터 파이프라인 생성 (파이프라인에 대해서는 아래에서 좀 더 자세히 설명)

4. 데이터 파이프라인을 이용해서 블록 쓰기 작업 수행

Datanode

파일의 컨텐츠 데이터는 블록 단위로 나뉘며, 하나의 블록은 적어도 3개의 복사본을 생성합니다. 데이터 노드는 그중 하나의 복사본을 저장하는 것입니다.

 

 

이러한 데이터 노드는 네임 노드와 3개지 종류의 통신을 하면서 커넥션을 유지합니다. 

 

1. handshake

맨 처음 데이터 노드를 네임 노드에 등록할 때 수행하는 통신입니다. handshake를 통해서 네임 노드는 데이터 노드가 통신이 가능하며 적절한 소프트웨어 버전인지 확인합니다. 적합한 데이터 노드임이 확인되면 데이터 노드를 식별할 수 있도록 고유한 id를 부여합니다.

 

2. block report

앞서서 네임 노드의 image에는 블록들이 저장된 위치가 포함되지 않으며, 실제 저장 위치는 계속해서 바뀔 수 있다고 언급했습니다. 네임 노드가 블록이 저장된 위치를 실제로 알 수 있는 것은 바로 이 block report 덕분입니다. 각 데이터 노드들은 매 시간마다 네임 노드에 블록이 실제로 저장되어 있는 위치와 현황을 네임 노드에게 알려줍니다. 네임 노드는 이 정보들을 취합하여 블록의 주소를 알게 됩니다.

 

3. heartbeat

하나의 HDFS 클러스터는 수천대의 컴퓨터로 구성되어 있으며, 이 중 일부 노드가 고장나는 상황은 빈번하게 발생합니다. 각 데이터 노드는 3초에 한 번씩 heartbeat를 네임 노드에게 보내어 자신이 잘 동작하고 있음을 확인시켜줍니다. 네임 노드는 10분간 응답이 없는 노드는 고장이 난 것으로 간주합니다. 그리고 해당 노드에 저장되어 있었던 블록들은 사용이 불가해지므로 다른 노드에 복사본을 하나씩 추가해줍니다.

Name Node Backup & Availability

네임 노드의 역할을 슬쩍 살펴만 보아도 매우 많은 역할을 수행합니다. 이러한 네임 노드의 데이터가 유실되거나 오염되며 큰일나겠죠? 이를 방지하기 위해서 Image, Checkpoint, Journal의 개념을 제시합니다. Image란 파일의 메타 정보를 담은 inode와 각 파일을 구성하는 블록들의 리스트를 합쳐서 지칭하는 개념입니다. (실제 블록이 저장된 위치 정보는 제외됩니다. 이는 계속해서 변화할 수 있기 때문입니다.) 이러한 image를 디스크에 쓴 것인 checkpoint입니다. journal은 image에 발생한 모든 변화들을 기록한 로그 파일입니다.

 

네임 노드는 가용성을 보장하기 위해서 주기적으로 checkpoint를 생성합니다. 만일 네임 노드가 장애를 일으켜서 커졌다가 켜진 경우, 가장 최신 체크 포인트를 읽어온 다음 journal을 순차적으로 실행시켜서 복원합니다. 체크 포인트 생성이 네임 노드에 부담이 될 수도 있으므로 별도의 백업 노드를 추가하여 네임 노드의 부담을 줄여주기도 합니다.

 

하지만 그럼에도 네임 노드는 HDFS의 취약점으로도 지목됩니다. 한 대의 네임 노드가 너무 많은 역할을 수행하기 때문에 네임 노드가 장애를 일으키면 전체 클러스터가 먹통이 될 위험성이 있다는 것입니다. 이를 방지하기 위해서 아래와 같은 구조를 설계하기도 합니다.

먼저 Active Name Node를 배치하고, 이것이 장애를 일으길 켱우를 대비한 Standby Name Node를 마련합니다. 그리고 앞서 살펴봤던 Backup Node의 역할을 수행하는 Journal Node를 NameNode에 연결해줍니다. 네임 노드는 이처럼 전체 HDFS를 조율하는 매우 중요한 역할을 담당합니다.

Block Placement

블록들을 어떻게 배치할 것이냐도 파일의 availability, I/O performance 등을 결정하는 중요한 사안입니다. HDFS는 두 단계로 이루어진 추상화를 사용합니다.

각각의 데이터 노드들은 하나의 rack에 묶입니다. rack이란 서버 컴퓨터들을 꽂아넣는 일종의 케이스를 의미하며 같은 렉에 꽂힌 데이터 노드들은 네트워크 스위치를 공유합니다. 때문에 같은 랙에 속한 데이터 노드들 간에는 네트워크 통신이 빠릅니다. 여러 개의 랙들은 코어 스위치로 묶입니다. HDFS는 이렇게 묶여있는 데이터 노드들에 다음과 같은 원칙으로 블록 replica들을 분산 시킵니다.

 

1. 하나의 데이터 노드에는 블록 replica를 하나만 저장한다. 

2. 하나의 랙에는 블록 replica를 최대 두 개 까지만 저장한다.

 

이러한 원칙을 지켜서 블록을 분산시킬 경우 availability가 확보됩니다. 하나의 데이터 노드가 고장나거나 하나의 랙이 고장나더라도 여전히 히 다른 노드 혹은 다른 랙에 블록 replica가 저장되어 있습니다. 그러므로 데이터의 유실을 방지할 수 있게 되는 것입니다. 

Balancer

데이터 노드들을 운영하다보면 imbalance 문제가 발생합니다. 나중에 추가된 데이터 노드의 디스크 공간은 비어있는 반면 오래 사용한 데이터 노드의 디스크 공간은 꽉 차게 되는 문제입니다. 이를 방지하기 위해서 balancer 모듈이 있습니다. balancer는 데이터 노드들의 디스크 사용량이 비슷하게 데이터를 옮겨주는 역할을 합니다. 그리고 그 와중에도 가용성을 떨어뜨리지 않도록 같은 노드에 두 replica를 저장하지않고 같은 랙에  세 replica를 저장하지 않도록 최적화 시키는 역할을 수행합니다.

마치며

지금까지 하둡 에코 시스템에 기반이 되는 HDFS를 알아보았습니다. 개념 자체가 어렵지는 않았습니다만 안정성을 확보하기 위한 안전 장치를 이중 삼중으로 마련해놓아 꽤나 복잡한 구조를 지니고 있었습니다. 이를 기반으로 Zookeeper, Pig, Hive, Hbase, Spark 등의 프로젝트들이 어떻게 동작하는지 궁금해지네요 ㅎㅎ 빅 데이터 기술 스택들의 페이퍼들도 꾸준히 살펴보고 포스팅 작성해보도록 하겠습니다.

 

감사합니다.

Reference

[1] File System, wikipedia

[2] The Haddop Distributed File System, Yahoo

[3] 갈아먹는 빅데이터[1] MapReduce 이해하기, 갈아먹는 머신러닝

[4] HDFS Documentation, https://hadoop.apache.org/docs/current/hadoop-project-dist/hadoop-hdfs/HdfsDesign.html, apache