HDFS 아키텍처
HDFS 아키텍처
Hadoop 분산 파일 시스템(HDFS)의 전반적인 설계를 소개하는 문서예요. 마스터/슬레이브 구조, 데이터 복제, 메타데이터 영속화, 견고성, 데이터 구성, 접근 방법, 공간 회수까지 HDFS의 핵심 설계 원리를 하나씩 살펴봅니다.
출처: 문서
본문
소개 (Introduction)
Hadoop 분산 파일 시스템(HDFS)은 일반 상용 하드웨어(commodity hardware)에서 실행되도록 설계된 분산 파일 시스템입니다. 기존 분산 파일 시스템과 공통점이 많지만 차이점도 분명합니다. HDFS는 고장 허용(fault-tolerant) 성능이 뛰어나고 저비용 하드웨어에 배포하도록 설계되었어요. 애플리케이션 데이터에 높은 처리량으로 접근할 수 있게 해 주며, 대용량 데이터셋을 다루는 애플리케이션에 적합합니다. 스트리밍 방식으로 파일 시스템 데이터에 접근할 수 있도록 일부 POSIX 요구사항을 완화했어요. HDFS는 원래 Apache Nutch 웹 검색 엔진 프로젝트의 인프라로 만들어졌고, 지금은 Apache Hadoop Core 프로젝트의 일부입니다. 프로젝트 URL은 http://hadoop.apache.org/입니다.
가정과 목표 (Assumptions and Goals)
하드웨어 고장 (Hardware Failure)
하드웨어 고장은 예외가 아니라 일반적인 일입니다. HDFS 인스턴스는 수백~수천 대의 서버 머신으로 구성될 수 있고, 각 머신이 파일 시스템 데이터의 일부를 저장합니다. 구성 요소가 매우 많고 각 구성 요소가 무시할 수 없는 고장 확률을 가지므로, HDFS의 어떤 구성 요소는 항상 동작하지 않는 상태입니다. 따라서 고장 감지와 신속한 자동 복구가 HDFS의 핵심 아키텍처 목표입니다.
스트리밍 데이터 접근 (Streaming Data Access)
HDFS에서 실행되는 애플리케이션은 데이터셋에 대해 스트리밍 접근이 필요합니다. 일반 범용 파일 시스템에서 실행되는 범용 애플리케이션과는 달라요. HDFS는 사용자의 대화형 사용보다는 배치 처리에 더 맞게 설계됐습니다. 데이터 접근의 낮은 지연시간보다 높은 처리량에 중점을 둡니다. POSIX는 HDFS 대상 애플리케이션에 필요 없는 엄격한 요구사항이 많기 때문에, 데이터 처리량을 높이기 위해 몇몇 핵심 영역의 POSIX 의미는 희생됐어요.
대용량 데이터셋 (Large Data Sets)
HDFS에서 실행되는 애플리케이션은 대용량 데이터셋을 가집니다. HDFS의 일반적인 파일은 GB~TB 단위입니다. 따라서 HDFS는 대용량 파일을 지원하도록 튜닝됐습니다. 높은 전체 데이터 대역폭을 제공하고 단일 클러스터에서 수백 개 노드로 확장되어야 합니다. 단일 인스턴스에서 수천만 개의 파일을 지원해야 해요.
단순한 일관성 모델 (Simple Coherency Model)
HDFS 애플리케이션은 파일에 대해 쓰기-한 번, 읽기-여러 번(write-once-read-many) 접근 모델이 필요합니다. 파일은 한 번 생성·작성·닫힌 뒤에는 append와 truncate를 제외하고는 변경될 필요가 없어요. 파일 끝에 내용을 추가하는 append는 지원하지만 임의의 지점에서 업데이트할 수는 없습니다. 이 가정은 데이터 일관성 문제를 단순화하고 높은 처리량 접근을 가능하게 해요. MapReduce 애플리케이션이나 웹 크롤러 애플리케이션이 이 모델에 완벽하게 맞습니다.
"연산을 이동하는 것이 데이터를 이동하는 것보다 싸다"
애플리케이션이 요청한 연산은 그 데이터 근처에서 실행될 때 훨씬 효율적입니다. 데이터셋의 규모가 클수록 더 그렇죠. 이렇게 하면 네트워크 혼잡을 줄이고 시스템 전체 처리량을 높일 수 있어요. 데이터를 애플리케이션이 실행되는 곳으로 옮기기보다, 연산을 데이터가 있는 곳에 더 가깝게 옮기는 것이 더 낫다는 것이 기본 가정입니다. HDFS는 애플리케이션이 데이터 위치에 더 가깝게 이동할 수 있게 해 주는 인터페이스를 제공합니다.
이기종 하드웨어/소프트웨어 플랫폼 간 이식성 (Portability)
HDFS는 한 플랫폼에서 다른 플랫폼으로 쉽게 이식되도록 설계됐습니다. 이 덕분에 많은 애플리케이션의 선택 플랫폼으로서 HDFS가 널리 채택될 수 있어요.
NameNode와 DataNode (NameNode and DataNodes)
HDFS는 마스터/슬레이브 아키텍처입니다. HDFS 클러스터는 단일 NameNode(파일 시스템 네임스페이스를 관리하고 클라이언트의 파일 접근을 조절하는 마스터 서버)와 다수의 DataNode(보통 클러스터의 노드당 하나씩, 자신이 실행되는 노드에 연결된 저장소를 관리)로 구성됩니다. HDFS는 파일 시스템 네임스페이스를 노출하고 사용자 데이터를 파일로 저장할 수 있게 해 줍니다. 내부적으로 파일은 하나 이상의 블록으로 나뉘고, 이 블록들은 DataNode 집합에 저장됩니다. NameNode는 파일·디렉터리 열기, 닫기, 이름 바꾸기 같은 네임스페이스 연산을 수행하고 블록-DataNode 매핑도 결정합니다. DataNode는 파일 시스템 클라이언트의 읽기·쓰기 요청을 처리하고, NameNode의 지시에 따라 블록 생성·삭제·복제를 수행합니다.
NameNode와 DataNode는 상용 머신에서 실행되도록 설계된 소프트웨어로, 보통 GNU/Linux OS에서 동작합니다. HDFS는 Java로 만들어져 있어서 Java를 지원하는 어떤 머신에서든 실행할 수 있고, 이식성이 높아 넓은 범위의 머신에 배포 가능합니다. 일반적인 배포는 NameNode만 실행하는 전용 머신 하나와, 각 머신에서 DataNode 인스턴스를 하나씩 실행하는 방식입니다. 같은 머신에서 여러 DataNode를 실행하지 못하게 막는 것은 아니지만 실제 배포에서는 드뭅니다.
클러스터에 단일 NameNode가 있다는 것은 시스템 아키텍처를 크게 단순화합니다. NameNode는 모든 HDFS 메타데이터의 중재자이자 저장소입니다. 시스템은 사용자 데이터가 NameNode를 통해 흐르지 않도록 설계되어 있어요.
파일 시스템 네임스페이스 (The File System Namespace)
HDFS는 전통적인 계층형 파일 구성을 지원합니다. 사용자나 애플리케이션은 디렉터리를 만들고 그 안에 파일을 저장할 수 있어요. 네임스페이스 계층 구조는 대부분의 기존 파일 시스템과 비슷합니다. 파일을 만들고 지우고, 디렉터리 사이로 옮기고, 이름을 바꿀 수 있어요. HDFS는 사용자 쿼터와 접근 권한을 지원합니다. 하드 링크·소프트 링크는 지원하지 않지만, 아키텍처상 구현을 막지는 않습니다.
HDFS는 FileSystem의 네이밍 규약을 따르지만, /.reserved, .snapshot 같은 일부 경로와 이름은 예약되어 있습니다. 투명 암호화, 스냅샷 같은 기능이 예약 경로를 사용합니다.
NameNode는 파일 시스템 네임스페이스를 유지합니다. 네임스페이스나 그 속성에 대한 모든 변경은 NameNode가 기록합니다. 애플리케이션은 HDFS가 유지해야 할 파일 복제본 수를 지정할 수 있고, 이 복제본 수를 **복제 팩터(replication factor)**라고 합니다. 이 정보는 NameNode가 저장합니다.
데이터 복제 (Data Replication)
HDFS는 대규모 클러스터의 여러 머신에 매우 큰 파일을 안정적으로 저장하도록 설계됐습니다. 각 파일을 블록의 시퀀스로 저장하며, 고장 허용을 위해 파일의 블록을 복제합니다. 블록 크기와 복제 팩터는 파일마다 설정할 수 있어요.
파일의 마지막 블록을 제외한 모든 블록은 같은 크기이고, append와 hsync에 가변 길이 블록 지원이 추가된 뒤로는 마지막 블록을 설정된 블록 크기까지 채우지 않고 새 블록을 시작할 수 있습니다.
애플리케이션은 파일의 복제본 수를 지정할 수 있습니다. 복제 팩터는 파일 생성 시점에 지정하고 나중에 변경할 수 있어요. HDFS 파일은 (append와 truncate를 제외하면) 한 번만 쓰며, 항상 쓰기 주체가 하나뿐입니다.
NameNode는 블록 복제에 관한 모든 결정을 내립니다. 클러스터의 각 DataNode로부터 주기적으로 Heartbeat와 Blockreport를 받습니다. Heartbeat를 받으면 DataNode가 정상 동작함을 의미하고, Blockreport에는 DataNode에 있는 모든 블록 목록이 담겨요.
복제본 배치: 첫 걸음 (Replica Placement)
복제본 배치는 HDFS 신뢰성과 성능에 결정적입니다. 복제 배치 최적화는 HDFS를 다른 분산 파일 시스템과 구분 짓는 특징이에요. 많은 튜닝과 경험이 필요한 부분입니다. 랙 인지(rack-aware) 복제 배치 정책의 목적은 데이터 신뢰성, 가용성, 네트워크 대역폭 활용을 높이는 것입니다. 현재 구현은 이 방향의 첫 시도이며, 단기 목표는 프로덕션에서 검증하고 동작을 학습하며 더 정교한 정책을 테스트·연구할 기반을 만드는 것입니다.
대규모 HDFS 인스턴스는 여러 랙에 걸쳐 있는 컴퓨터 클러스터에서 실행됩니다. 다른 랙의 두 노드 간 통신은 스위치를 거쳐야 해요. 대부분 같은 랙 안 머신 간 네트워크 대역폭이 다른 랙 간보다 큽니다.
NameNode는 Hadoop Rack Awareness에 설명된 절차로 각 DataNode가 속한 랙 id를 결정합니다. 단순하지만 최적이 아닌 정책은 복제본을 서로 다른 랙에 두는 것입니다. 이러면 랙 전체가 실패해도 데이터 손실을 막고, 읽을 때 여러 랙의 대역폭을 쓸 수 있어요. 또한 복제본을 클러스터에 고르게 분산시켜 구성 요소 고장 시 부하 균형을 쉽게 합니다. 그러나 쓰기는 여러 랙으로 블록을 전송해야 하므로 쓰기 비용이 증가합니다.
일반적인 경우(복제 팩터 3) HDFS의 배치 정책은 다음과 같아요. 작성자가 데이터노드에 있으면 복제본 하나를 로컬 머신에 두고, 아니면 작성자와 같은 랙의 임의 데이터노드에 둡니다. 다른 복제본 하나는 다른(원격) 랙의 노드에, 마지막 복제본은 같은 원격 랙의 다른 노드에 둡니다. 이 정책은 랙 간 쓰기 트래픽을 줄여 쓰기 성능을 개선합니다. 랙 고장 확률은 노드 고장보다 훨씬 낮아서 데이터 신뢰성·가용성 보장에는 영향을 주지 않아요. 다만 블록이 3개가 아닌 2개의 고유 랙에만 배치되므로 읽기 시 전체 네트워크 대역폭 사용은 줄어들지 않습니다. 이 정책에서 블록의 복제본은 랙에 고르게 분산되지 않아요. 두 복제본은 한 랙의 서로 다른 노드에, 나머지 하나는 다른 랙의 노드에 놓입니다. 쓰기 성능은 개선하되 데이터 신뢰성이나 읽기 성능은 떨어뜨리지 않는 정책입니다.
복제 팩터가 3보다 크면 4번째 이후 복제본의 배치는 랙당 복제본 수를 상한(기본적으로 (replicas - 1) / racks + 2) 아래로 유지하면서 무작위로 결정됩니다.
NameNode는 같은 블록의 복제본을 같은 DataNode에 두는 것을 허용하지 않으므로, 생성 가능한 최대 복제본 수는 당시의 총 DataNode 수입니다.
HDFS에 저장소 유형과 저장소 정책(Storage Types and Policies) 지원이 추가된 뒤로, NameNode는 위의 랙 인지 외에도 복제 배치 시 정책을 고려합니다. 먼저 랙 인지로 후보 노드를 고르고, 그 후보 노드가 해당 파일과 연결된 정책이 요구하는 저장소를 갖고 있는지 확인해요. 없으면 다른 노드를 찾습니다. 첫 경로에서 복제본을 배치할 노드를 충분히 찾지 못하면 두 번째 경로에서 폴백(fallback) 저장소 유형을 가진 노드를 찾습니다.
여기 설명한 현재 기본 복제 배치 정책은 진행 중인 작업입니다.
복제본 선택 (Replica Selection)
전체 대역폭 소모와 읽기 지연시간을 최소화하기 위해, HDFS는 읽는 위치에서 가장 가까운 복제본으로 읽기 요청을 처리하려고 합니다. 읽는 노드와 같은 랙에 복제본이 있으면 그 복제본을 우선 사용합니다. 클러스터가 여러 데이터센터에 걸쳐 있으면 로컬 데이터센터에 있는 복제본이 원격 복제본보다 우선됩니다.
블록 배치 정책 (Block Placement Policies)
앞서 말했듯 복제 팩터가 3일 때 HDFS 배치 정책은 쓰는 쪽이 데이터노드면 로컬 머신에, 아니면 작성자와 같은 랙의 임의 데이터노드에 복제본 하나를 두고, 다른 복제본은 다른(원격) 랙 노드에, 마지막은 같은 원격 랙의 다른 노드에 두는 것입니다. 복제 팩터가 3보다 크면 4번째 이후 복제본은 랙당 복제본 수 상한(기본 (replicas - 1) / racks + 2) 아래에서 무작위로 배치됩니다. 추가로 HDFS는 4가지 플러그형 블록 배치 정책을 지원합니다. 사용자는 인프라와 사용 사례에 맞춰 정책을 선택할 수 있어요. 기본적으로 HDFS는 BlockPlacementPolicyDefault를 지원합니다.
안전 모드 (Safemode)
시작 시 NameNode는 Safemode라는 특수 상태에 들어갑니다. Safemode 상태에서는 데이터 블록의 복제가 발생하지 않아요. NameNode는 DataNode로부터 Heartbeat와 Blockreport 메시지를 받습니다. Blockreport에는 DataNode가 보유한 데이터 블록 목록이 들어 있어요. 각 블록에는 지정된 최소 복제본 수가 있습니다. 데이터 블록의 최소 복제본 수가 NameNode에 체크인되면 그 블록은 안전하게 복제된 것으로 간주됩니다. 구성 가능한 비율의 안전 복제 블록이 NameNode에 체크인되고 나면(추가로 30초 후) NameNode는 Safemode를 빠져나갑니다. 그다음 지정된 복제본 수보다 적은 복제본을 가진 블록 목록을 결정하고, 이 블록들을 다른 DataNode에 복제합니다.
파일 시스템 메타데이터의 영속화 (Persistence of File System Metadata)
HDFS 네임스페이스는 NameNode가 저장합니다. NameNode는 EditLog라는 트랜잭션 로그를 사용해 파일 시스템 메타데이터의 모든 변경을 영구적으로 기록합니다. 예를 들어 HDFS에 파일을 새로 만들면 NameNode가 EditLog에 레코드를 삽입해 표시하고, 파일의 복제 팩터를 바꿔도 새 레코드가 EditLog에 삽입됩니다. NameNode는 로컬 호스트 OS 파일 시스템의 파일로 EditLog를 저장해요. 블록-파일 매핑과 파일 시스템 속성을 포함한 전체 네임스페이스는 FsImage라는 파일에 저장되며, 이 역시 NameNode 로컬 파일 시스템에 파일로 저장됩니다.
NameNode는 전체 네임스페이스 이미지와 파일 Blockmap을 메모리에 보관합니다. NameNode가 시작할 때, 또는 구성 가능한 임계값에 의해 체크포인트가 트리거되면 디스크에서 FsImage와 EditLog를 읽고, EditLog의 모든 트랜잭션을 메모리의 FsImage 표현에 적용한 뒤 이 새 버전을 디스크의 새 FsImage로 기록합니다. 그러면 기존 EditLog는 트랜잭션이 영속 FsImage에 적용됐으므로 잘라낼(truncate) 수 있어요. 이 과정을 체크포인트라고 합니다. 체크포인트의 목적은 파일 시스템 메타데이터의 스냅샷을 찍어 FsImage에 저장함으로써 HDFS가 메타데이터에 대한 일관된 시야를 갖도록 하는 것입니다. FsImage를 읽는 것은 효율적이지만 FsImage에 직접 점진적 편집을 하는 것은 비효율적이라, 편집마다 FsImage를 수정하는 대신 편집 내용을 EditLog에 영속화합니다. 체크포인트 동안 EditLog의 변경이 FsImage에 적용되어요. 체크포인트는 일정 시간 간격(dfs.namenode.checkpoint.period, 초 단위) 또는 누적된 파일 시스템 트랜잭션 수(dfs.namenode.checkpoint.txns)로 트리거됩니다. 두 속성 모두 설정되면 먼저 도달하는 임계값이 체크포인트를 트리거해요.
DataNode는 HDFS 데이터를 자신의 로컬 파일 시스템에 있는 파일로 저장합니다. DataNode는 HDFS 파일에 대해 알지 못하며, HDFS 데이터 블록 각각을 로컬 파일 시스템의 별도 파일로 저장합니다. 모든 파일을 같은 디렉터리에 만들지는 않고, 디렉터리당 최적 파일 수를 결정하는 휴리스틱을 사용해 하위 디렉터리를 적절히 만듭니다. 단일 디렉터리에 방대한 파일 수를 로컬 파일 시스템이 효율적으로 지원하지 못할 수 있으므로 모든 로컬 파일을 한 디렉터리에 두는 것은 비효율적이에요. DataNode가 시작하면 로컬 파일 시스템을 스캔해 각 로컬 파일에 대응하는 모든 HDFS 데이터 블록 목록을 생성하고 이 보고서를 NameNode에 보냅니다. 이 보고서를 **Blockreport**라고 해요.
통신 프로토콜 (The Communication Protocols)
모든 HDFS 통신 프로토콜은 TCP/IP 위에 계층화되어 있습니다. 클라이언트는 NameNode 머신의 구성 가능한 TCP 포트에 연결하고, NameNode와 ClientProtocol로 대화합니다. DataNode는 DataNode Protocol로 NameNode와 통신해요. RPC(Remote Procedure Call) 추상화가 Client Protocol과 DataNode Protocol을 모두 감쌉니다. 설계상 NameNode는 어떤 RPC도 시작하지 않고, DataNode나 클라이언트가 보낸 RPC 요청에만 응답합니다.
견고성 (Robustness)
HDFS의 주요 목표는 고장이 있어도 데이터를 안정적으로 저장하는 것입니다. 세 가지 일반적인 고장 유형은 NameNode 고장, DataNode 고장, 네트워크 분할(partition)입니다.
데이터 디스크 고장, Heartbeat, 재복제 (Data Disk Failure, Heartbeats and Re-Replication)
각 DataNode는 주기적으로 Heartbeat 메시지를 NameNode에 보냅니다. 네트워크 분할은 일부 DataNode가 NameNode와의 연결을 잃게 만들 수 있어요. NameNode는 Heartbeat 메시지가 없음을 감지해 이 상태를 파악합니다. 최근 Heartbeat가 없는 DataNode를 dead로 표시하고 더 이상 새 IO 요청을 보내지 않습니다. dead DataNode에 등록된 데이터는 더 이상 HDFS에서 사용할 수 없어요. DataNode death로 일부 블록의 복제 팩터가 지정값 아래로 떨어질 수 있습니다. NameNode는 어떤 블록이 재복제가 필요한지 계속 추적하고 필요할 때마다 복제를 시작합니다. 재복제가 필요한 이유는 다양해요. DataNode가 사용 불가가 되거나, 복제본이 손상되거나, DataNode의 하드 디스크가 고장 나거나, 파일의 복제 팩터가 증가하는 경우입니다.
DataNode를 dead로 표시하는 타임아웃은 보수적으로 깁니다(기본 10분 이상). 이는 DataNode 상태가 오락가락하면서 생기는 복제 폭풍을 피하기 위해서예요. 성능에 민감한 워크로드는 더 짧은 간격으로 DataNode를 stale로 표시하고 읽기/쓰기에서 stale 노드를 피하도록 구성할 수 있습니다.
클러스터 리밸런싱 (Cluster Rebalancing)
HDFS 아키텍처는 데이터 리밸런싱 방식과 호환됩니다. DataNode의 여유 공간이 특정 임계값 아래로 떨어지면 자동으로 한 DataNode에서 다른 DataNode로 데이터를 옮기는 방식이 가능해요. 특정 파일에 대한 갑작스러운 높은 수요가 생기면 동적으로 추가 복제본을 만들고 클러스터의 다른 데이터를 리밸런싱할 수도 있습니다. 이런 종류의 리밸런싱 방식은 아직 구현되지 않았어요.
데이터 무결성 (Data Integrity)
DataNode에서 가져온 블록이 손상된 채 도착할 수 있습니다. 저장 장치 결함, 네트워크 결함, 버그 있는 소프트웨어 때문에 발생할 수 있어요. HDFS 클라이언트 소프트웨어는 HDFS 파일 내용에 대해 체크섬 검사를 구현합니다. 클라이언트가 HDFS 파일을 만들면 각 블록의 체크섬을 계산해 같은 HDFS 네임스페이스의 별도 숨김 파일에 저장합니다. 클라이언트가 파일 내용을 가져올 때 각 DataNode에서 받은 데이터가 관련 체크섬 파일에 저장된 체크섬과 일치하는지 확인합니다. 일치하지 않으면 클라이언트는 그 블록의 복제본을 가진 다른 DataNode에서 블록을 가져오도록 선택할 수 있어요.
메타데이터 디스크 고장 (Metadata Disk Failure)
FsImage와 EditLog는 HDFS의 핵심 데이터 구조입니다. 이 파일이 손상되면 HDFS 인스턴스가 동작하지 않을 수 있어요. 그래서 NameNode는 FsImage와 EditLog의 복사본을 여러 개 유지하도록 구성할 수 있습니다. FsImage나 EditLog에 대한 업데이트는 모든 FsImage와 EditLog에 동기적으로 반영됩니다. 이렇게 여러 복사본을 동기적으로 갱신하면 NameNode가 지원하는 초당 네임스페이스 트랜잭션 수가 떨어질 수 있는데, HDFS 애플리케이션은 데이터 집약적이지 메타데이터 집약적이지 않아서 이 감소는 허용 가능합니다. NameNode가 재시작하면 가장 최근의 일관된 FsImage와 EditLog를 선택해 사용합니다.
고장에 대한 탄력성을 높이는 또 다른 방법은 여러 NameNode로 **고가용성(High Availability)**을 활성화하는 것입니다. NFS의 공유 저장소를 쓰거나 분산 편집 로그(Journal)를 사용하는 방식이 있어요. 후자가 권장되는 접근 방식입니다.
스냅샷 (Snapshots)
스냅샷은 특정 시점의 데이터 복사본을 저장하도록 지원합니다. 손상된 HDFS 인스턴스를 이전에 알려진 정상 시점으로 롤백하는 데 활용할 수 있어요.
데이터 구성 (Data Organization)
데이터 블록 (Data Blocks)
HDFS는 매우 큰 파일을 지원하도록 설계됐습니다. HDFS와 호환되는 애플리케이션은 대용량 데이터셋을 다루는 것들이에요. 이런 애플리케이션은 데이터를 한 번만 쓰고 한 번 이상 읽으며, 읽기가 스트리밍 속도로 충족되기를 요구합니다. HDFS는 파일에 대해 쓰기-한 번, 읽기-여러 번 의미를 지원해요. HDFS가 사용하는 일반적인 블록 크기는 128 MB입니다. 따라서 HDFS 파일은 128 MB 덩어리로 쪼개지고, 가능하면 각 덩어리는 다른 DataNode에 위치합니다.
복제 파이프라이닝 (Replication Pipelining)
클라이언트가 복제 팩터 3으로 HDFS 파일에 데이터를 쓸 때, NameNode는 복제 대상 선택 알고리즘으로 DataNode 목록을 가져옵니다. 이 목록에는 그 블록의 복제본을 보유할 DataNode들이 들어 있어요. 클라이언트는 첫 번째 DataNode에 씁니다. 첫 DataNode는 데이터를 조각 단위로 받기 시작해 각 조각을 로컬 저장소에 쓰고 그 조각을 목록의 두 번째 DataNode로 전송합니다. 두 DataNode는 마찬가지로 블록의 각 조각을 받아 저장소에 쓰고 세 번째 DataNode로 플러시합니다. 마지막으로 세 DataNode가 데이터를 로컬 저장소에 씁니다. 이렇게 DataNode는 파이프라인의 이전 노드에서 데이터를 받는 동시에 다음 노드로 전달하므로, 데이터가 한 DataNode에서 다음으로 파이프라인처럼 흐릅니다.
접근성 (Accessibility)
HDFS는 애플리케이션에서 여러 가지 방식으로 접근할 수 있어요. 기본적으로 HDFS는 FileSystem Java API를 제공합니다. 이 Java API의 C 언어 래퍼와 REST API도 있어요. 또한 HTTP 브라우저로 HDFS 인스턴스의 파일을 탐색할 수 있고, NFS 게이트웨이를 이용하면 HDFS를 클라이언트 로컬 파일 시스템의 일부로 마운트할 수도 있습니다.
FS Shell
HDFS는 사용자 데이터를 파일과 디렉터리 형태로 구성할 수 있게 해 줍니다. FS shell이라는 명령줄 인터페이스를 제공해 사용자가 HDFS의 데이터와 상호작용할 수 있어요. 명령 문법은 사용자가 이미 익숙한 다른 셸(bash, csh 등)과 비슷합니다. 동작/명령 예시는 다음과 같습니다.
| 동작 | 명령 |
|---|---|
/foodir라는 디렉터리 만들기 |
bin/hadoop dfs -mkdir /foodir |
/foodir라는 디렉터리 삭제 |
bin/hadoop fs -rm -R /foodir |
/foodir/myfile.txt 파일 내용 보기 |
bin/hadoop dfs -cat /foodir/myfile.txt |
FS shell은 저장된 데이터와 상호작용할 스크립트 언어가 필요한 애플리케이션을 대상으로 합니다.
DFSAdmin
DFSAdmin 명령 집합은 HDFS 클러스터를 관리하는 데 사용됩니다. HDFS 관리자만 쓰는 명령이에요. 동작/명령 예시는 다음과 같습니다.
| 동작 | 명령 |
|---|---|
| 클러스터를 Safemode로 | bin/hdfs dfsadmin -safemode enter |
| DataNode 목록 생성 | bin/hdfs dfsadmin -report |
| DataNode 복귀/제외 | bin/hdfs dfsadmin -refreshNodes |
브라우저 인터페이스 (Browser Interface)
일반적인 HDFS 설치는 구성 가능한 TCP 포트로 HDFS 네임스페이스를 노출하도록 웹 서버를 설정합니다. 사용자는 웹 브라우저로 HDFS 네임스페이스를 탐색하고 파일 내용을 볼 수 있어요.
공간 회수 (Space Reclamation)
파일 삭제와 삭제 취소 (File Deletes and Undeletes)
휴지통(trash) 구성을 활성화하면 FS Shell로 삭제한 파일이 HDFS에서 즉시 제거되지 않습니다. 대신 HDFS는 파일을 휴지통 디렉터리(각 사용자는 /user/<username>/.Trash 아래에 자신의 휴지통 디렉터리 보유)로 옮겨요. 파일이 휴지통에 있는 동안에는 빠르게 복원할 수 있습니다.
가장 최근에 삭제된 파일은 현재 휴지통 디렉터리(/user/<username>/.Trash/Current)로 옮겨지고, 구성 가능한 간격으로 HDFS는 현재 휴지통 디렉터리의 파일에 대한 체크포인트를(/user/<username>/.Trash/<date>) 만들고 만료된 옛 체크포인트는 삭제합니다. 휴지통 체크포인트는 FS shell의 expunge 명령을 참고하세요.
휴지통 수명이 만료되면 NameNode가 파일을 HDFS 네임스페이스에서 삭제합니다. 파일 삭제는 그 파일과 연결된 블록을 해제합니다. 사용자가 파일을 삭제한 시점과 HDFS의 여유 공간이 실제로 늘어나는 시점 사이에는 상당한 시간 지연이 있을 수 있음을 유의하세요.
다음은 FS Shell이 HDFS에서 파일을 삭제하는 방법을 보여주는 예시입니다. delete 디렉터리 아래에 2개의 파일(test1, test2)을 만들었어요.
$ hadoop fs -mkdir -p delete/test1
$ hadoop fs -mkdir -p delete/test2
$ hadoop fs -ls delete/
Found 2 items
drwxr-xr-x - hadoop hadoop 0 2015-05-08 12:39 delete/test1
drwxr-xr-x - hadoop hadoop 0 2015-05-08 12:40 delete/test2
이제 test1 파일을 제거해 봅니다. 아래 주석은 파일이 휴지통 디렉터리로 옮겨졌음을 보여줍니다.
$ hadoop fs -rm -r delete/test1
Moved: hdfs://localhost:8020/user/hadoop/delete/test1 to trash at: hdfs://localhost:8020/user/hadoop/.Trash/Current
이제 skipTrash 옵션으로 파일을 제거해 봅니다. 이 옵션은 파일을 휴지통으로 보내지 않고 HDFS에서 완전히 제거합니다.
$ hadoop fs -rm -r -skipTrash delete/test2
Deleted delete/test2
이제 휴지통 디렉터리에 test1 파일만 들어 있는 것을 확인할 수 있어요.
$ hadoop fs -ls .Trash/Current/user/hadoop/delete/
Found 1 items
drwxr-xr-x - hadoop hadoop 0 2015-05-08 12:39 .Trash/Current/user/hadoop/delete/test1
즉 test1 파일은 휴지통으로 가고 test2 파일은 영구히 삭제됩니다.
복제 팩터 감소 (Decrease Replication Factor)
파일의 복제 팩터를 줄이면 NameNode가 삭제할 수 있는 초과 복제본을 선택합니다. 다음 Heartbeat가 이 정보를 DataNode에 전달하고, DataNode가 해당 블록을 제거하면 클러스터에 여유 공간이 생깁니다. setReplication API 호출 완료와 클러스터에 여유 공간이 나타나는 시점 사이에도 시간 지연이 있을 수 있어요.
참고 자료 (References)
Hadoop JavaDoc API.
HDFS 소스 코드: http://hadoop.apache.org/version_control.html
더 알아보기 (Learn more)
- 원문: 문서