1. 기존 대용량 파일 시스템과의 차이점
- 저사양 서버를 여러 대 이용해 스토리지를 구성할 수 있음.
- 물리적으로 분산된 서버의 로컬 디스크에 저장되어 있지만, 파일의 읽기 및 저장과 같은 제어는 HDFS에서 제공하는 API를 이용해 처리함
- API는 Java Base이며, "하둡은 자바로 이루어져있다" 라는 맥락은 여기서 나온게 아닌가 싶습니다.
- API에 대해 정리한 내용은 아래 4. 파일 저장하기, 읽기 에 나와있습니다.
사실은 여러 서버에 분산되어 저장되어있지만, 마치 한 서버의 파일시스템 처럼 사용할 수 있음
2. HDFS 아키텍처
1) 블록 구조 파일시스템
- HDFS에 저장하는 파일은 특정 크기의 블록으로 나눠져 분산된 서버에 저장되게 됩니다.
- 기본적으로 블록의 크기는 64MB이며 하둡 환경설정 파일 등으로 조정이 가능합니다.
- 하나의 파일이 쪼개져서 저장된다는 것인데, 이 쪼개진 파일은 하나의 서버에 저장되는것이 아니라 여러 서버에 나눠서, 복제되서 저장됩니다.
- 복제되는 갯수는 세개로, 데이터노드에 나눠서 저장됩니다.
따라서 특정 서버의 디스크에 문제가 생겨도 다른 서버에 복제본을 사용하면 됩니다.
*블록의 크기가 64MB인 이유는(하둡 2.0에서 128MB로 늘어났습니다.)
1. 탐색시간 감소
2. 네임노드가 유지하는 메타데이터의 크기 감소
*네임노드가 관리하는 블록의 갯수는 네임노드에 할당된 힙 메모리의 크게에 영향을 받습니다.
3. 클라이언트와 네임노드의 통신 감소
- 클라이언트가 HDFS에 저장된 파일을 접근할 때 네임노드에서 해당 파일을 구성하는 블록의 위치를 조회합니다
3. 네임노드와 데이터노드
- HDFS는 마스터 - 슬레이브 아키텍처입니다.
- 마스터 역할은 네임노드가, 슬레이브 역할은 데이터 노드가 맡게 됩니다.
1) 네임노드
(1) 메타데이터 관리
- 파일시스템을 유지하기 위한 메타데이터를 관리함.
- 메타데이터는 파일시스템 이미지(파일명, 디렉터리, 크기, 권한)와 파일에 대한 블록 매핑 정보로 구성
(2) 데이터 노드 모니터링
- 하트비트를 이용해 데이터노드의 실행상태와 용량을 모니터링, 하트비트를 수신하지 못하면 장애가 발생한 서버로 판단
(3) 블록 관리
- 데이터노드에 장애가 발생하면, 해당 데이터노드의 블록을 새로운 데이터노드로 복제함
- 만약 데이터노드에 용량이 부족해지면 여유가 있는 데이터노드로 블록을 이동시킴
- 복제본 수가 일치하지 않으면 추가로 복제하거나 삭제함
(4) 클라이언트 요청 접수
- 클라이언트가 HDFS에 접근하려면 네임노드에 먼저 접근해야함
- 파일을 저장할 때는 기존 파일의 저장여부와 권환 확인절차 등을 거쳐 저장을 승인함
- 파일을 조회 할 경우 블록의 위치 정보를 반환
2) 데이터노드
- HDFS에 저장하는 파일을 로컬디스크에 유지하는 역할
- 로컬디스크에 저장하는 파일은 두 종류로 구성됨
(1) 실제 데이터가 저장되어있는 로우 데이터
(2) 체크섬이나 파일 생성 일자와 같은 메타데이터가 설정 돼 있는 파일
3) 보조 네임 노드
- 네임노드는 메타데이터를 메모리에서 처리함
- 따라서 서버가 재부팅되면 메타데이터가 유실될 수 있음
- 유실을 방지하기 위해 Editslog, Fsimage라는 두 개의 파일을 생성함
- 보조 네임노드와 HA구성은 다릅니다! 보조 네임노드는 체크포인팅만 합니다!
(1) Editslog, FsImage
- Editslog : HDFS의 변경 이력
- Fsimage : 메모리에 저장된 메타데이터와 파일 시스템 이미지
- Editslog, Fsimage는 다음과 같이 사용됩니다.
(1) 네임노드가 구동되면 로컬에 저장된 fsimage와 editslog를 조회합니다.
(2) 메모리에 fsimage를 로딩해 파일시스템 이미지를 생성합니다.
(3) 메모리에 로딩된 파일 시스템 이미지에 editslog에 기록된 변경 이력을 적용
(4) 메모리에 로딩된 파일 시스템 이미지를 이용해 fsimage파일을 갱신함
(5) editslog를 초기화 합니다.
(6) 데이터노드가 전송한 블록 리포트를 메모리에 로딩된 파일 시스템 이미지에 적용합니다.
- 단, editslog의 크기에는 제약이 없습니다. 따라서 무한대로 커질 수 있기 때문에 (3) 의 작업에 많은 시간이 소요될 수 있습니다.
10년동안 큰 하나의 가계부로 계산하는 것 보다, 매년 결산내고 새로운 공책에 쓰는 것이 더 효율적이겠죠?
(2) 체크포인팅
- fsimage, editslog를 주기적으로 갱신해 fsimage의 크기를 줄여주는 역할(한시간에 한번, fs.checkpoint.period 속성으로 수정 가능)
- 위와 같은 역할을 하는 서버이므로 "체크포인팅 서버"라고도 함.
- 체크포인팅 단계는 다음과 같습니다.
(1) 네임노드에 editslog를 롤링 요청(롤링 : 현재 로그 파일의 이름을 변경하고, 원래 이름으로 새 로그 파일을 만드는 작업)
(2) 지금 editslog --> editslog.new를 생성
(3) 보조 네임노드가 editslog.new, fsimage를 다운로드
(4)다운로드 받은 fsimage를 메모리에 로딩하고, editslog에 있는 변경 이력을 메모리에 로딩된 파일시스템 이미지에 적용, 새 fsimage 생성 --> 체크포인팅할 때 사용 , "fsimage.ckpt"로 생성됨
(5) fsimage.ckpt를 네임노드로 전송
(6) 저장되있던 fsimage를 보조 네임노드가 전송한 fsimage.ckpt로 변경, editslog.new --> editslog로 변경
4. 파일 저장하기, 읽기
- API에서 저장, 읽기 요청을 보낼 때 단계별 세부 동작 방식을 정리 했습니다.
- 자세한 내용은 시작하세요, 하둡 프로그래밍 도서 참고 부탁드립니다.
1) 파일 저장
(1) 파일 저장 요청
- 파일 저장 요청시 파일을 저장하기 위한 스트림 객체를 생성해야 합니다.
- 스트림 요청 -> 스트림 생성 -> 유효성 검사 요청 -> 스트림 반환의 단계로 이뤄지며, 스트림 요청,생성, 반환은 클라이언트 JVM에서 이뤄집니다.
(2) 패킷 전송
- 클라이언트가 네임노드에게서 파일 제어권을 얻으면 파일 저장을 진행합니다.
- 이때 클라이언트는 파일을 네임노드가 아닌 데이터노드로 전송합니다.
- 전송할 파일은 패킷 단위로 나눠서 저장됩니다.
- 전송할 패킷은 클랑이언트 JVM의 DFSOutputStream객체 내부 데이터 큐에 등록됩니다.
- 패킷이 등록되면, 네임노드의 addBlock 메소드를 호출합니다.
- 네임노드는 블록을 저장할 데이터노드 목록을 반환하고, 복제본 수와 동일한 수의 데이터노드를 연결한 파이프라인을 형성합니다.
- 파이프라인의 첫번째 노드부터 패킷 전송을 실행하며, 데이터노드는 DataXceiverServer 데몬을 실행해 클라이언트 및 다른 데이터노드와 패킷을 교환합니다.
- 패킷 저장이 완료되면, blockRecieved라는 메서드를 호출해 정상적으로 저장 된 것을 인지합니다.
(3) 파일 닫기
- DistributedFileSystem의 close 메서드를 호출해 파일 닫기 요청
- DFSOutputStream은 complete 메서드를 호출해 true를 반환하면, 패킷이 정상적으로 저장/파일 저장이 완료
2) 파일 읽기
(1) 파일 조회 요청
- 저장과 마찬가지로 스트림 객체를 생성해야 합니다.
- 스트림 요청 -> 스트림 생성 -> 블록 위치 요청 -> 블록 위치 반환의 단계로 이뤄지며, 스트림 요청,생성, 반환은 클라이언트 JVM에서 이뤄집니다.
(2) 블록 조회
- 입력 스트림의 read 메서드를 호출해 스트림 조회를 요청합니다.
- DFSInputStream은 첫번째 블록과 가장 가까운 데이터노드부터 조회하고, 원격인 경우엔 RemoteBlockReader를 생성합니다.
-RemoteBlockReader는 원격에 저장된 노드에게 블록을 요청하고, 데이터노드의 DataXceiverServer가 블록을 DFSInputStream에게 반환합니다. DFSInputStream은 조회한 데이터의 체크섬을 검증하고, 체크섬에 문제가 있을 경우 다른 데이터노드에게 블록 조회를 요청합니다.
- 파일을 모두 읽을 때 까지 계속해서 블록을 조회하고, 만약 DFSInputStream이 저장한 모든 블록을 모두 읽었는데도 파일을 모두 읽지 못했다면 getBlockLocations 메소드를 호출해 필요한 블록 위치 정보를 다시 요청합니다.
파일을 끊임없이 연속적으로 읽기 때문에 클라이언트는 스트리밍 데이터를 읽는 것 처럼 처리할 수 있습니다.
- 네임노드는 DFSInputStream에게 클라이언트에게 가까운 순으로 정렬된 블록 위치 목록을 반환합니다.
(3) 입력 스트림 닫기
- 입력 스트림 객체의 close 메서드를 호출해 스트림 닫기 요청
- DFSInputStream은 데이터노드와 연결되어있는 커넥션을 종료하고 , 블록 조회용으로 사용했던 리더기도 닫아줍니다.
본 게시물은 시작하세요 하둡 프로그래밍 도서를 정리한 문서입니다.
잘못 이해한 개념이 있다면, 피드백 부탁드립니다. 감사합니다.
'Hadoop' 카테고리의 다른 글
맵리듀스 (0) | 2019.11.30 |
---|---|
CDH 중 Oozie에서 Permission에러가 나요! (0) | 2019.09.30 |