티스토리 뷰

오늘은 HDFS의 파일 저장 방식을 알아보겠습니다.


  • 파일 저장 요청


클라이언트가 HDFS에 파일을 저장하는 경우, 파일을 저장하기 위한 스트림을 생성해야합니다. 그림1은 클라이언트가 네임노드와 통신 과정을 통해서, 파일 저장용 스트림 객체를 생성하는 과정을 나타냅니다.


3_3_new.jpg

[그림3.3] 파일 저장 스트림 객체 생성


  1. 하둡은 FileSystem이라는 추상화 클래스에 일반적인 파일 시스템을 관리하기 위한 메소드를 정의합니다. 그리고 이 추상화 클래스를 상속받아서, 각 파일 시스템에 맞게 구현된 다양한 파일 시스템 클래스를 제공합니다. HDFS에 파일을 저장하는 경우에는 파일 시스템 클래스 중에 DistributedFileSystem를 사용하게 됩니다. 클라이언트는 DistributedFileSystem의 create 메소드를 호출하여, 스트림 객체를 생성합니다.


  1. DistributedFIleSystem은 클라이언트에게 반환할 스트림 객체로, FSDataOutputStream을 생성합니다.  FSDataOutputStream은 데이터노드와 네임노드의 통신을 관리하는 DFSOutputStream을 래핑하는 클래스입니다. DistributedFIleSystem은 DFSOutputStream을 생성하기 위하여, DFSClient의 create 메소드를 호출합니다.


  1. DFSClient는 DFSOutputStream를 생성합니다. 이때 DFSOutputStream은 RPC 통신으로, 네임노드의 create 메소드를 호출합니다. 네임노드는 클라이언트의 요청이 유효한지 검사를 진행합니다. 이미 생성된 파일이거나, 권한에 문제가 있거나, 현재 파일 시스템의 용량을 초과한다면 오류를 발생합니다. 네임노드는 파일 유효성 검사 결과가 정상일 경우, 파일 시스템 이미지에 해당 파일의 엔트리를 추가합니다. 마지막으로 네임노드는 클라이언트에게 해당 파일을 저장할 수 있는 제어권을 부여합니다.


  1. 네임노드의 유효성 검사가 통과됐다면, DFSOutputStream 객체가 정상적으로 생성됩니다. DFSOutputStream를 래핑한 FSDataOutputStream도 되며, DistributedFileSystem가 이 스트림 객체를 클라이언트에게 반환합니다.


  • 패킷 전송


클라이언트가 네임노드에게서 파일 제어권을 얻게 되면, 파일 저장을 진행합니다. 이때 클라이언트는 파일을 네임노드에게 전송하지 않고, 각 데이터노드에 전송하게 됩니다. 그리고 저장할 파일은 패킷 단위로 나눠서 전송하게 됩니다. 그림2는 클라이언트의 패킷 전송 과정을 나타냅니다.


3_4_new.jpg

[그림2] 패킷 전송


  1. 클라이언트는 스트림 객체의 write 메소드를 호출하여, 파일 저장을 시작합니다. DFSOutputStream은 클라이언트가 저장하는 파일을 64K 크기의 패킷들로 분할합니다.


  1. DFSOutputStream는 전송할 패킷을 내부 큐인 데이터큐(dataQueue)에 등록합니다. DFSOutputStream의 내부 스레드가 데이터큐에 패킷이 등록된 것을 확인하면, DFSOutputStream의 내장 클래스인 DataStreamer는 네임노드의 addBlock 메소드를 호출합니다.


  1. 네임노드는 DataStreamer에게 블록을 저장할 데이터노드 목록을 반환한다. 이 목록은 복제 계수와 동일한 수의 데이터노드를 연결한 파이프라인을 형성합니다. 예를 들어 HDFS의 복제 계수가 3으로 설정되어 있다면, 데이터노드 3개가 파이프라인을 형성합니다.


  1. DataStreamer는 파이프라인의 첫번째 데이터노드부터 패킷 전송을 시작합니다. 데이터노드는 클라이언트와 다른 데이터노드로부터 패킷을 주고 받기 위하여, DataXceiverServer 데몬을 실행합니다. DataXceiverServer는 클라이언트 및 다른 데이터노드와 패킷 교환 기능을 제공합니다.


첫번째 데이터노드는 패킷을 저장하면서, 두번째 데이터노드에게 패킷 저장을 요청합니다. 두번째 데이터노드도 패킷을 저장하면서,  세번째 데이터노드에게 패킷 저장을 요청합니다. 마지막으로 세번째 데이터노드가 패킷 저장합니다.


또한 첫번째 데이터노드에 패킷을 저장할 때, DFSOutputStream는 내부 큐인 승인큐(ackQueue)에 패킷을 등록합니다. 승인큐는 패킷 전송이 완료됐다는 응답을 기다리는 패킷이 등록되어 있으며, 모든 데이터노드로부터 응답을 받았을때만 해당 패킷이 제거됩니다.


  1. 각 데이터노드는 패킷이 정상적으로 저장되면, 자신에게 패킷을 전송한 데이터노드에게 ACK 메세지를 전송합니다. ACK 메세지는 패킷 수신이 정상적으로 완료됐다는 승인 메세지입니다. 승인 메세지는 파이프라인을 통해서, DFSOutputStream에게 까지 전달됩니다.


  1. 각 데이터는 패킷 저장이 완료되면, 네임노드의 blockReceived 메소드를 호출합니다. 이를 통해서, 네임노드는 해당 블록이 정상적으로 저장됐다는 것을 인지합니다.


  1. DFSOutputStream의 내부 스레드인 ResponseProcessor는 파이프라인에 있는 모든 데이터노드로부터 승인 메세지를 받게 되면, 해당 패킷을 승인큐에서 제거합니다.만약 패킷 전송 중에 장애가 발생한다면, 승인 큐에 있는 모든 패킷을 데이터큐로 이동합니다. 그리고 네임노드에게서 장애가 발생한 데이터노드가 제거된 새로운 데이터목록을 내려받습니다. 마지막으로 새로운 파이프라인을 생성한 후, 다시 패킷 전송 작업을 시작합니다.


  • 파일 닫기


이제 스트림을 닫고, 파일 저장을 완료하겠습니다. 그림3은 클라이언트가 파일을 닫는 과정을 나타냅니다.



3_5_new.jpg

[그림3] 파일 닫기


  1. 클라이언트는 DistributdFileSystem의 close 메소드를 호출하여, 파일 닫기를 요청합니다.


  1. DistributedFileSystem은 DFSOutputStream의 close 메소드를 호출합니다. 이 메소드는 DFSOutputStream에 남아 있는 모든 패킷을 파이프라인으로 플러시(flush)합니다.


  1. DFSOutputStream는 네임노드의 complete 메소드를 호출하여, 패킷이 정상적으로 저장됐는지 확인합니다. 네임노드의 complete 메소드는 최소 블록 복제 계수만 저장됐다면, true를 반환합니다. DFSOutputStream는 true를 반환 받으면, 파일 저장이 완료된 것으로 설정합니다.


저작자 표시 비영리 변경 금지
신고
댓글
댓글쓰기 폼