3장 하둡 분산 파일시스템
1. HDFS 설계
- 분산파일 시스템 : 네트워크로 연결된 서버들의 스토리지를 관리하는 파일 시스템. 일반 디스크 파일시스템보다 복잡함
- HDFS 는 범용 하드웨어로 구성된 클러스터에서 실행되고 데이터 액세스 패턴을 스트리밍 방식으로 지원하여 매우 큰 파일들을 저장할 수 있도록 설계된 파일시스템이다.
- HDFS가 잘 맞지 않는 분야 : 빠른 응답시간의 데이타 액세스, 많은 수의 작은 파일, 다중 라이터, 임의의 파일 수정
2. HDFS 개념
- 블록 : 저장할 데이타 청크(chunk). 한번에 읽고 쓸수 있는 데이타의 최대량. 기본 64MB
- HDFS 블록이 큰 이유 : 블록의 시작을 탐색하기 위한 비용 최소화하기 위해서
- 이점 : 파일이 단일 디스크보다 커질 수 있음, 스토리지 시스템을 단순하게 만들어줌. 복제를 효율적으로 할 수 있음
- 네임노드와 데이터노드 : 네임노드(Master) - 데이타노드(worker)
네임노드는 네임스페이스 관리, 메타데이타 유지,
데이타노드는 블록 저장, 탐색, 블록 리스트를 네임노드에 보고
- 파일시스템 메타 데이타의 persistent state 파일 백업 (메타데이타 정보를 원격 NFS에도 저장하고, 로컬에도 저장하는 식)
- secondary 네임 노드 운영 : 주기적으로 네임스페이스 이미지를 에디트 로그와 병합
3. 명령행 인터페이스
의사 분산(pseudo-distributed) 모드로 실행
- fs.default.name : 하둡의 기본적인 파일시스템으로 hdfs://localhost/ 를 설정하고 있다.
- dfs.replication : 파일 시스템 블록을 1로 설정
- 기본적인 파일 시스템 연산
도움말 : hadoop fs -help - 파일 복사(-copyFromLocal : 로컬에서 hdfs로 복사, -copyToLocal : hdfs에서 로컬로 복사)
hadoop fs -copyFromLocal input/docs/quangle.txt hdfs://localhost/user/tom/quangle.txt
(URI scheme, host 생략 가능, 상대경로 가능) hadoop fs -copyFromLocal input/docs/quangle.txt /user/tom/quangle.txt
파일 비교는 md5로 실행
POSIX와 비슷한 권한 모델을 가지고 있지만, 실행권한에 한해서 파일 실행은 지원하지 않고, 디렉터리는 서브 디렉터리에 대한 접근을 위해 필요하다.
r/w/x
4. 하둡 파일시스템
org.apache.hadoop.fs.FileSystem p83. STUDY:표3-1하둡 파일시스템 참고
- 인터페이스
- 쓰리프트 : hdfs를 쓰리프트 서비스로 제공. 언어에 상관없이 hdfs와 연동 가능(C++, Perl, Python, Ruby 등 지원)
- C : libhdfs 제공
- FUSE : Filesystem in Userspace. 사용자 공간에서 구현된 파일시스템을 유닉스 파일시스템으로 통합할 수 있도록 지원
- WebDAV : 파일 편집과 수정을 지원하기 위한 HTTP 확장. hdfs를 표준 파일시스템처럼 액세스할 수 있음
- HTTP, FTP 등
5. 자바 인터페이스
- 하둡 URL로부터 데이터 읽기
URL객체를 이용하여 hdfs의 파일을 읽을때, URLStreamHandlerFactory를 통해 hdfs의 URL Scheme을 인식함
JVM 하나당 한번씩만 호출할 수 있어서 static block에서 실행됨.
- 파일시스템 API를 사용하여 데이터 읽기
HDFS의 파일은 Path객체로 표현, FileSystem 인터페이스: 일반적인 파일시스템 API임
Configuration conf = new Configuration();
FileSystem fs = FileSystem.get(URI.create(uri), conf);
InputStream in = null;
try{
in = fs.open(new Path(uri));
IOUtils.copyBytes(in, System.out, 4096, false);
} finally{
IOUtils.closeStream(in);
}
FSDataInputStream :
public class FSDataInputStream extends DataInputStream implements Seekable, PositionedReadable{
...
}
Seekable :
public interface Seekable{
void seek(long pos) throws IOException;
long getPos() throws IOException;
}
PositionedReadable :
public interface PositionedReadable {
public int read(long position, byte[] buffer, int offset, int length) throws IOException;
public void readFully(long position, byte[] buffer, int offset, int length) throws IOException;
public void readFully(long position, byte[] buffer) throws IOException;
}
모든 메서드는 현재의 파일 offset을 유지하고, thread-safe하므로, 파일의 특정 부분을 읽는 동안, 그 파일의 다른 부분에 액세스할 수 있는 기능을 제공한다.
seek() 메서드는 비용이 많이 든다.
- 데이타 쓰기
파일 생성을 위해 Path에 대한 OutputStream을 반환해준다.
public FSDataOutputStream create(Path f) throws IOException;
- creaet 메서드는 파일을 쓸 때 존재하지 않는 디렉토리도 생성해준다.
Progressable : 데이타 쓰기 진행상황을 통보받을 수 있다.
public interface Progressable {
public void progress();
}
append 와 sequential write 만 지원. 탐색은 지원하지 않는다.
- 파일시스템에 질의하기
FileSystem#getFileStatus(file)
파일 메타데이타 : FileStatus - 파일 길이, 블록 크기, 복제, 수정시간, 소유권, 권한 정보 등 파일시스템 메타데이타를 캡슐화함
- 파일 리스팅
FileSystem#listStatus()
PathFilter 사용가능, Path[STUDY:] 에 대한 리스트 결과를 단일 배열로 리턴
- 파일 패턴
FileSystem#globeStatus()
globbing : 와일드카드, p101 표3-2 글로빙 문자와 그 의미
public interface PathFilter {
boolean accept(Path path);
}
java.io.FileFilter 와 대응됨
제한사항 : 필터는 Path에 표현된 파일명으로만 동작하고, 필터의 대상으로 파일의 생성시간과 같은 파일 속성을 사용할 수 없다.
- 데이타 삭제
FileSystem#delete()
public boolean delete(Path f, boolean recursive) throws IOException
6. 데이타 흐름
- 파일 읽기 해부
DistributedFileSystem 의 open()을 호출하여 파일을 연다 => 블록 위치를 파악하기 위해 RPC를 사용하여 네임노드를 호출한다 =>
요청된 블록의 복제본을 가지고 있는 데이타 노드를 반환한다 => 데이타 노드는 클러스터의 네트워크 토폴로지에 따라 정렬된다 =>
DFSInputStream의 read() 를 호출한다 => 해당 파일의 첫번째 블록과 첫번째 데이터노드를 연결한다 =>
클라이언트는 스트림에 대해 반복적으로 read()를 호출하고, 데이타는 데이타 노드로부터 전송된다. =>
블록의 끝에 이르면 데이타 노드로의 연결을 닫고, 다음 블록을 위해 가장 적합한 네임노드를 찾는다
- 네트워크 토폴로지와 하둡
- 두 노드간 거리측정은 대역폭으로 계산한다.
- 다음의 시나리오에 의해 대역폭이 점차 줄어듬
- 동일노드의 프로세스 : distance(/d1/r1/n1, /d1/r1/n1) = 0
- 동일 랙의 다른 노드 : distance(/d1/r1/n1, /d1/r1/n2) = 2
- 동일 데이타 센터에 있는 다른 랙의 노드 : distance(/d1/r1/n1, /d1/r2/n3) = 4
- 다른 데이타 센터에 있는 노드 : distance(/d1/r1/n1, /d2/r3/n4) = 6
(* 하둡은 데이타 센터를 넘나들며 수행하기에는 적합하지 않다.)
- 파일쓰기 상세
DistributedFileSystem의 create() 호출하여 파일을 생성한다 => 네임스페이스에 파일을 생성하기 위해 네임노드로 RPC 호출 =>
파일 존재 여부, 권한 등 검사 수행 => FSDataOutputStream 반환 => DFSOutputStream으로 래핑 =>
data queue에 데이타를 패킷으로 쪼개서 쓴다 => queue는 DataStreamer 에 의해 소비된다 (데이타 복제본을 저장하기 적합한 데이타노드의 리스트를 선별하여 네임노드가 새로운 블록을 할당하도록 요청) =>
데이타 리스트는 하나의 파이프라인을 형성하고, DataStreamer는 패킷을 파이프라인의 첫번째 데이타 노드로 전송하고, 전송되고 있는 패킷을 저장하고 그다음 데이터노드로 전달한다 =>
DFSOutputStream은 데이터노드로부터 승인되기를 기다리는 ack queue를 관리한다.
하나의 패킷은 파이프라인에 있는 데이타노드로부터 모두 승인되었을 때에만 승인 큐로부터 제거된다 =>
클라이언트는 데이터 쓰기를 완료할때 close를 호출하고, 남아있는 모든 패킷을 파이프라인으로 flush하고, 파일완료 신호를 보내기 전에 패킷에 대한 최종 승인을 기다린다.
- 일관성 모델
파일 시스템의 읽기 쓰기에 대한 데이타 가시성을 묘사함
FSDataOutputStream#sync() <= close() 수행시 암묵적으로 수행됨
7. distcp 병렬 복사
병렬로 다량의 데이타를 hdfs로(부터) 복사하기 위한 명령어
hadoop distcp hdfs://namenode1/foo hdfs://namenode2/bar
맵리듀스 잡으로 구성되어 있고, 클러스터 전반에 병렬로 수행되는 맵으로 복사 작업이 이루어짐. 리듀서는 없음
HFTP를 이용해 버전이 다른 hdfs의 RPC 호환
hadoop distcp hftp://namenode1:50070/foo hdfs://namenode2/bar
8. 하둡 아카이브
하둡 아카이듭 또는 HAR 파일은 더 효율적으로 HDFS 블록을 묶기 위한 파일 아카이빙 기능
네임노드의 메모리 사용량을 감소시킴
hadoop archive -archiveName files.har /my/files /my
참고문서