하둡은 HDFS라는 분산 파일시스템을 제공한다. (Hadoop Distributed File System)
데이터가 단일 물리 머신의 저장 용량을 초과하게 되면,
전체 데이터셋 분리된 여러 머신에 나눠서 저장할 필요가 있다.
네트워크로 연결된 여러 머신의 스토리지를 관리하는 파일시스템을 분산 파일시스템이라고 한다.
분산 파일시스템은 네트워크 기반이므로 네트워크 프로그램의 복잡성을 모두 가지고 있다.
따라서 일반적인 디스크의 파일시스템보다 훨씬 더 복잡하다.
HDFS는 범용 하드웨어로 구성된 클러스터에서 실행되고
스트리밍 방식의 데이터 접근 패턴으로 대용량 파일을 다룰 수 있도록 설계되었다.
파일을 읽고 쓰는 것은 마치 일반적인 파일시스템을 사용하는 것과 같다.
하지만 그 뒤에서 여러 머신들 사이의 네트워크 이동이나 오류 처리 등 많은 일이 진행된다.
HDFS는 다음의 특징을 지닌다.
일반 디스크에 들어갈 정도로 작은 (일반적인 가정용 컴퓨터에 쓰이는 파일도 몇 백 기가가 되기도 한다) 파일을 저장할 거면 HDFS가 필요가 없다. 데이터가 너무 커서 단일 디스크에 저장하지 못하거나 혹은 저장할 수 있더라도 분산 처리의 속도와 안정성을 꾀하기 위해 클러스터 내 여러 컴퓨터에 나누어야 할 경우엔 HDFS가 필요하다. 최근에는 페타바이트 크기의 데이터를 저장하는 하둡 클러스터도 있다.
HDFS는 '가장 효율적인 데이터 처리 패턴은 한 번 쓰고 여러 번 읽는 것'이라는 아이디어에서 출발했다.
첫 번째 레코드를 읽는 데 걸리는 지연 시간보다 전체 데이터셋을 모두 읽을 때 걸리는 시간이 더 중요하다.
HDFS에 저장되는 데이터는 일반적으로 사용자들이 어떤 UI를 통해 접근해 읽거나 사용하는 용도의 데이터가 아니라 분석을 통해 데이터에서 어떠한 insight를 얻기 위한 데이터이다.
따라서 데이터의 한 부분을 읽는 것이 아니라, 전체 부분을 읽는 것에 초점을 두어야 한다.
데이터의 딱 한 부분을 읽는다면 일반 RDBMS보다 느리겠지만,
분산된 환경에서 전체 데이터를 읽는다면 RDBMS보다 이점이 있을 수 있다.
하둡은 비싼 고성능 컴퓨터에서만 돌아갈 수 있는 것이 아니라 일반적인 컴퓨터도 사용이 가능하다.
좋든 나쁘든 클러스터를 구성하는 컴퓨터만 있으면 하둡 에코시스템을 동작시킬 수 있다.
또한 HDFS 내부에서 오류가 발견됐을 시 자체적으로 대처하고 다시 보완하는 방식으로 설계되었기 때문에 사용자는 장애가 발생했다는 사실조차 모르게 작업을 할 수 있다.
하지만 HDFS의 특성 상 적용이 어려운 분야도 있다.
앞서 말했듯 데이터 하나를 읽는 것은 일반적인 파일시스템이나 RDBMS보다 느리다.
여러 컴퓨터에 나눠서 저장했기 때문에,
사용자가 찾고자 하는 데이터가 어떤 컴퓨터에 저장되어 있는지 알아내야 하고
또 필요 시 네트워크를 통해 옮겨서 합쳐야 하기 때문이다.
따라서 데이터 접근에 수십 밀리초 수준의 빠른 응답 시간을 요구하는 애플리케이션은 HDFS와 맞지 않다.
HDFS는 높은 데이터 처리량을 제공하기 위해 최적와되어 있고 이를 위해 응답 시간을 희생했다.
네임노드는 파일시스템의 메타데이터를 메모리에서 관리하기 때문에 저장할 수 있는 파일 수는 네임노드의 메모리 용량에 좌우된다.
네임노드는 HDFS에서 사용자의 입력(파일 확인이나 읽기 명령어 입력)을 받아 이에 대한 결과를 데이터노드들에서 받아온다.
HDFS는 하나의 네임노드와 네임노드가 실제로 일을 시키는 데이터노드들로 구성되어 있다.
이때 HDFS가 돌아가는 동안 네임노드는 데이터노드들에게서 실제 데이터에 대한 정보(메타데이터)를 보고 받는데, 이를 메모리에 저장한다.
메타데이타는 말 그대로 파일에 대한 정보 (혹은 디렉터리에 대한)이므로 용량에 상관 없이 일정한 수준의 크기를 갖는다.
즉, 전체 HDFS 용량이 같더라도 작은 파일들이 여러개 있는 것이 큰 파일이 조금 있는 것보다 많은 메모리를 소모한다.
HDFS는 단일 라이터로 파일을 쓴다. 또한 파일 임의의 위치에 있는 내용을 수정하는 것이 불가능하며 다중 라이터도 지원하지 않는다. (하둡 3.0부터는 가능하다)
파일 수정이 안 되는 이유는 분산 시스템에서 수정을 동기화하기가 불가능에 가깝기 때문이다.
일반적으로 파일시스템은 블록 단위로 돌아간다. HDFS도 그렇다.
파일시스템의 블록이 수 킬로바이트, 디스크 블록은 512바이트인 반면
HDFS는 기본적으로 128MB의 큰 단위의 블록을 가지고 있다.
블록 단위가 이렇게 큰 이유는 탐색 비용을 최소화하기 위해서이다.
블록이 매우 크면 블록의 시작점을 탐색하는 데 걸리는 시간을 줄일 수 있고 데이터를 전송하는 데 더 많은 시간을 할애할 수 있다.
여러 개의 블록으로 구성된 대용량 파일을 전송하는 시간은 디스크 전송 속도에 크게 영향을 받는다.
다만 기존 시스템은 블록보다 작은 크기의 데이터가 들어와도 디스크를 정해진 블록 크기만큼 쓰는 반면
HDFS는 실제 데이터의 크기만큼만 디스크를 사용한다.
파일 하나의 크기가 단일 디스크 용량보다 더 커질 수 있다.
하나의 파일을 구성하는 여러 개의 블록이 동일한 디스크에만 저장될 필요가 없다.
물론 전체 디스크를 꽉 채울만큼 큰 파일 하나를 저장하는 것도 가능하다.
시스템을 단순화할 수 있다. 오류가 생겨도 블록만 확인하면 된다.
블록에 대한 정보는 메타데이터로 따로 빼버렸으므로 이를 관리하는 또 다른 시스템을 둘 수도 있다.
블록은 내고장성과 가용성을 제공하는 데 필요한 복제를 구현할 때 매우 적합하다.
하둡에선 블록의 손상과 각종 장애에 대처하기 위해 블록을 서로 다른 세 머신에 복제한다.
하나의 머신에서 블록이 접근이 불가능하던가 한다면 다른 머신에서 블록을 가져올 수도 있다.
이후 다시 복사함으로써 복사본 개수를 맞출 수 있다.
HDFS는 하나의 네임노드와 여러개의 데이터노드로 구성되어 있다.
네임노드는 파일시스템 트리와 그 트리에 포함된 모든 파일/디렉토리에 대한 메타데이터를 가지고 있다.
이는 네임스페이스 이미지와 에디트 로그라는 것으로 로컬 디스크에 저장된다.
시스템이 시작될 때 네임노드는 데이터노드에게서 파일/디렉토리에 관한 메타데이터를 받아온다.
디스크에 영구적으로 저장하진 않고 메모리에 가지고 있는다.
HDFS 클라이언트는 사용자를 대신해서 네임노드와 데이터노드 사이의 연결을 맡는다.
사용자를 대신한다는 말은 둘 사이에 무슨 이야기가 오고 가는지를 몰라도 된다는 말이다.
POSIX와 유사한 파일시스템 인터페이스를 제공하기 때문에 사용자는 네임노드와 데이터노드에 관련된 함수를 몰라도 코드를 작성할 수 있다.
실질적인 일을 하는 것은 데이터노드이다.
데이터노드는 클라이언트나 네임노드의 요청이 있을 때 블록을 저장하고 탐색한다.
시시때때로 바뀌는 블록의 목록과 메타데이터를 주기적으로 네임노드에 보고한다.
하나의 네임노드가 여러 데이터노드를 부리는 방식으로 동작한다는 것은,
네임노드 하나가 고장나면 HDFS 전체가 불능 상태가 된다는 것을 의미한다.
이는 SPOF(Single Point Of Failure)한 특성으로, 바람직하지 않은 설계 방식이다.
다행히도 하둡은 네임노드의 장애 복구 기능을 지원한다.
첫째로 파일시스템의 메타데이터를 받아와서 지속적으로 파일로 백업하는 것이다.
네임노드가 고장나면 -> 네임노드의 메모리를 못 쓰고 -> 메모리 안에 들어있는 데이터노드들이 보내준 각종 메타데이터를 사용할 수 없게 되므로, 네임노드가 고장나더라도 메타데이터들이 일단 따로 백업되어 있다면 HDFS는 돌아갈 수 있다.
둘째로 보조 네임노드를 운영하는 것이다.
보조 네임노드의 주 역할은 에디트 로그가 너무 커지지 않도록 주기적으로 네임스페이스 이미지를 에디트 로그와 병합하여 새로운 네임스페이스 이미지를 만들고, 네임스페이스 이미지의 복제본을 보관하는 것이다.
단, 어느 정도 시간차를 두고 보조 네임노드로 복제되기 때문에 주 네임노드에 장애가 발생했을 시 어느 정도의 데이터 손실을 불가피하다.
이때는 NFS(Network File System)에 저장된 네임노드의 메타데이터 파일을 보조 네임노드로 복사하여 새로 병합된 네임스페이스 이미지를 만들고 그것을 새로운 주 네임노드에 복사한 다음 실행하는 것으로 복구할 수 있다.