해당 블로그는 KT UCloud의 지원을 받고 있습니다.
해당 글은 Cloudea의 http://www.cloudera.com/blog/2012/03/high-availability-for-the-hadoop-distributed-file-system-hdfs/ 라는 글을 발 번역 한 것입니다. 다들 아시는 것 처럼 HDFS의 주요 문제점 중 하나는 Master Node의 SPOF(Single Point of Failure) 입니다. 이를 위한 페이스북 등에서 나온 것이 Avatar Node 라고 해서 실제 중요 데이터를 NFS 등의 공유 데이터 스토어에 저장해두고, 장애시 Standby Master Node를 이용해서 복구하자는 것입니다. 복구가 될 때 실제 블럭 리포트를 재구성 하는데 시간이 많이 걸리는데, 이를 Active와 Standby에 모두 보내서 실제로 장애시에 빠른 시간내에 서비스를 할 수 있도록 하는 것이 Avatar Node의 요지입니다. 다만, 페이스북의 경우 장애시 실제로 자동 복구는 하지 않고, 사람의 힘을 빌려서 판단한다고 하네요. ( 그리고 hadoop 2.0으로 넘어가면서 실제로 여러 마스터 노드에서 파일들을 나눠서 관리하고 이를 클라이언트 라이브러리에서 판단해서 하나나 전체의 파일을 가져가는 형태로 바뀌었습니다. 이 형태의 경우, Master Node의 장애가 있더라도 피해를 일부 지역으로 국소화 시킬 수 있습니다. 이 부분에 대한 내용은 해당 포스트에는 없고, Avatar 노드에 대한 것뿐이긴 합니다. ) 이런 큰 방향으로 바뀌는 것들에 대한 설명이 있으니, 주의 깊게 보시면 됩니다. 오역에 주의하시기 바랍니다.
Background
아파치 하둡은 큰 두 개의 컴포넌트 HDFS와 MapReduce로 구성되어 있습니다. 하둡 분산 파일 시스템 HDFS는 하둡의 메인 스토리지 시스템입니다. 그리고 하둡에 저장되는 모든 파일을 서비스하고 저장하는 책임이 있습니다. MapReduce는 HDFS 에 저장된 데이터를 이용하도록 디자인된 분산 처리 프레임워크입니다.
HDFS는 강한 신뢰성을 가지는 파일 시스템으로 오랬동안 고려되어 왔습니다. 야후에 경험에 근거한 연구에 따르면, 야후에서는 2009년에 10개의 다른 클러스터에서 20,000대의 노드에서 아파치 하둡을 운영했습니다. HDFS는 오직 3억2천9백만개의 데이터 블럭 중에서 오직 650개의 블럭만 유실되었습니다. 유실된 블럭의 대부분은 버그에 의해서 발생했고, 해당 버그들은 오래전에 이미 수정되었습니다.
이정도로 높은 안정성 레벨에 비해서, HDFS는 예전부터 잘 알려진 HDFS의 가용성에 큰 영향을 주는 큰 단점(SPOF: Single Point of Failure) 을 가지고 있습니다. HDFS는 하나의 싱글 Name Node가 파일 시스템에 접근하는 것을 관리합니다. 대부분 ETL이나 batch 처리 workflow 로 사용되는 클러스터의 경우 HDFS의 약간의 중단은 즉각 회사에 큰 비지니스적 영향을 주지는 않습니다. 하지만, HDFS는 과거 몇년 동안 좀 더 상호작용적인 업무에 사용되기 시작하기 시작했고, HBase의 경우에는 실시간에 고객의 요구를 처리하고 있습니다. 이런 경우에, HDFS의 중단은 내부 유저의 생산성에 바로 영향을 주게됩니다. 그리고 외부 사용자에게도 영향이 미칠것입니다. 이런 이유로, HDFS Name Node에 고가용성(HA)을 추가하는 것은 HDFS 커뮤니티에서 제일 중요한 작업 중의 하나가 되었습니다.
해당 포스트에서는 “HA Name Node”라고 불리는 HDFS의 새로운 기능 구현에 대해서 얘기합니다. 하둡 전체의 가용성에 대해서 연관된 다른 이슈들에 대해서 자세히 얘기하고 싶다면, Eli Collins의 멋진 블로그 포스트를 살펴보시기 바랍니다.
High-level Architecture
HA Name Node 프로젝트의 목표는 Active/Passive 설정으로 두 대의 NameNode 를 배포하는 것을 추가하는 것입니다. 이것은 고가용성 분산 시스템에서 일반적인 설정입니다. 그리고 HDFS의 아키텍트는 이렇게 하기에 잘 디자인되어 있습니다. HA 설정이 아니더라도, HDFS는 이미 Name Node의 동작을 체크하는 비슷한 스펙의 다른 노드를 필요로 합니다. HA Name Node의 디자인은 그 체크하는 역할을 passive Name Node에 부여해서 HDFS에서 이미 필요로 하는 것들을 넘어서 다른 추가적인 하둡 서버 장비가 필요없도록 해야 합니다.(역자 주: 기존 시스템에서는 Secondary Namenode 또는 backup node라는 이름으로 HDFS의 NameNode의 메타정보를 백업해주는 프로세스들이 있습니다. 이것만으로는 SPOF를 피할 수 없기 때문에, 결국 한 쌍의 하둡 클러스터를 더 만들어서 트래픽을 같이 보내서 HA를 보장하는 방법을 이용하곤 했습니다.)
HDFS Name Node는 두 종류의 파일시스템 메타데이터를 서비스 하는 주된 책임이 있습니다. 파일시스템의 네임스페이스와 블록 위치 정보입니다. HDFS의 아키텍처 때문에, 이것들은 개별적으로 처리되어야 합니다.
Namespace Information
파일 시스템 네임스페이스에 생기는 파일 이름 변경, 소유권한 변경, 파일 생성, 블럭 할당등의 모든 변경은 Name Node에 의해서 클라이언트의 요청에 성공이라는 응답을 주기 전에, Write-ahead log(WAL) 에 영구적으로 저장됩니다. 게다가, 파일 시스템에 정기적으로 체크포인트를 만드는 fsimage 와 edit log는 Name Node에 생성되고, 디스크에 저장됩니다. 반면에 블럭 위치 정보는 메모리에 저장됩니다. 모든 블록의 위치 정보는 “block reports” 를 통해서 Data Node로 부터 Name Node가 시작할 때 받게 됩니다.(역자 주, 정확하게 말하면 Memory에 전체 파일 블럭 정보가 있고, 이 내용을 정기적으로 fsimage로 만듭니다. 그리고 그 사이의 변경은 edits 라고 하는 파일에 저장됩니다. 기본 설정은 5분으로 되어있고, 5분마다, 현재의 fsimage에 edits를 merge 합니다. 그래서, 만약 Name Node 장애가 났다면, 해당 edits 도 필요합니다.)
HA Name Node 의 목표는 다운타임 없이 Active Name Node의 역할을 대체할 수 있는 미리 준비된 standby Name Node를 제공하는 것입니다. 이런 기능을 제공하기 위해서, 거의 대부분 완전하게 최신 파일 시스템의 상태를 가능한 메모리에 가지고 있는 것이 매우 중요합니다. 경험적으로 cold 상태에 있던 Name Node를 시작하는데는 namespace 정보를 디스크로 부터 읽기 위해서 수십분이 걸립니다.(fsimage 와 edit log) 그리고 큰 클러스터에서 필요한 블럭 위치 정보를 데이터 노드로 모두 받기 위해서 한 시간 이상 걸립니다.
Name Node는 변경 로그들을 다수의 신뢰성 있는 로컬 디렉토리에 저장해오고 있습니다. active 와 standby Name Node 들 사이에 해당 정보를 공유하기 위해서, HA Name Node 설정을 위한 기능 중에 edits 디렉토리를 공유하는 것을 설정하는 기능이 있습니다. 해당 디렉토리는 네트웤 파일 시스템을 이용해서 이용 가능해야 합니다. 그리고 반드시, 두 NameNode 모두에서 읽고 쓰기가 가능해야 합니다. 해당 디렉토리는 active 네임 노드에서는 필수로 다뤄지게 되고, 해당 디스크의 edit log에 파일 시스템의 변경이 쓰여지기 전까지는 클라이언트에 성공 메시지는 전달되지 않습니다. standby Name Node는 자주 공유된 edits 디렉토리에 접근해서, active Name Node 에 의해서 쓰여진 새로운 변경 정보를 확인합니다. 그리고 해당 변경 정보들을 읽어서 자신의 메모리의 파일 시스템 상태에 반영합니다.
하나의 공유 edits 디렉토리를 요구하는 것이 새로운 SPOF를 의미하지는 않습니다. 하지만, 이 공유 디렉토리는 스스로 HA, 고가용성을 제공해야 합니다. 그리고 Name Node들 간에 이 공유 디렉토리에 접근할 수 있는 다수의 네트웍 접근 루트가 있어야 합니다. (역자 주: 예를 들어, 네트웍 공유 디렉토리 장비쪽의 스위치가 장애가 날 수도 있고, 네트웍 카드가 문제가 될 수도 있습니다. 이럴 경우, 네트웍 카드도 여러 개, 앞 단의 스위치도 여러 개로 해서, 네트웍 공유 디렉토리 자체의 고가용성이 확보되어야 한다는 것입니다.)
해당 상황을 개선할 방법에 대해서는 아래에서 다시 얘기하도록 하겠습니다.
Block Locations
standby Name Node를 미리 준비된 상태로 유지해야하는 다른 부분은 블럭 위치 정보를 항상 최신으로 유지하는 것입니다. 블럭 위치 정보가 Name Node의 변경 로그에 쓰여지지 않으면, 공유 edits 디렉토리부터 읽는 것만으로는 파일 시스템 메타데이터를 Name Node들 간에 공유하기에 불충분합니다. 해당 문제를 처리하기 위해서 HA가 동작될 때, 클러스터의 모든 데이터 노드가 두 대의 Name Node의 네트웍 주소가 설정되어 있어야 합니다. Data Node는 모든 block report를 보내고 와 블럭의 위치 정보를 업데이트 합니다. 그리고 두 대의 Name Node에 대해서 정기적으로 상태를 체크합니다. 그러나 모든 Data Node들은 모든 블럭 관련 명령은 현재의 active Name Node로만 보고합니다.
Namespace 정보와 블럭 위치 정보 모두를 standby Name Node에서 유지하면, delay 없이 Active Name Node에서 Standby Name Node로 failover 가 가능합니다.
Client Failover
여러 데몬들이 Active Name Node로써 단일 클러스터에서 서비스를 할 수 있기 때문에, HDFS 클라이언트들은 해당 시점에 어떤 Name Node와 통신해야 하는지 알 수 있어야 합니다. Active-Active 설정은 HA Name Node 기능에서 제공하지 않습니다. 그래서 모든 클라이언트는 서비스를 위해서 Active Name Node 로만 요청을 보내야 합니다.
해당 기능을 구현하기 위해서, HDFS 클라이언트는 HA Name Node 서비스를 총괄적으로 나타내기 위해서, 각 Name Node 를 위해서 다중 네트웍 주소의 설정을 제공해야 합니다. 해당 네임 서비스는 클라이언트 쪽 설정을 통해서 HA Name Node의 두 개의 네트웍 주소를 매핑한 하나의 논리적 URI로 표현됩니다. 이 주소들은 HDFS 클라이언트에 의해서 적절히 시도됩니다. 만약 클라이언트가 standby Name Node로 요청한다면, 다른 곳으로 다시 요청하라는 응답을 받게 됩니다. active Name Node가 발견될때 까지, 클라이언트는 설정된 주소로 적절히 요청을 보내게 됩니다.
요청을 처리중에 Active Name Node가 장애가 나는 사건이 발생하면, 클라이언트는 요청이 처리되었는지 알 수가 없습니다. 읽기나 멱등한 쓰기(퍼미션 셋팅, 시간 변경, 등등 ) 같은 많은 요청들은 문제가 없습니다.(역자 주: 멱등한(idempotent) 라는 것은 ADD A 1 과 같은 명령이 아니 SET A 1 처럼 몇번 발생하더라도 문제가 없는 명령의 형태를 말합니다. 물론, 시간등 다양하게 고려해야 할 상황들이 생기지만, SET A 1 이 장애로 인해서 여러번 처리된다고 해도 SET A 2 라는 다른 명령이 들어오지만 않으면 몇번이 반복되어도 문제가 없습니다.그런데 ADD A 1은 어떨까요? 실수로 5번 처리되면 값이 5증가된 상태로 바뀌겠죠?) 클라이언트는 failover가 완료된 후에 매우 쉽게 재시도 하면 됩니다. 다른 경우에는 해당 에러는 반드시 호출자가 오류를 바르게 처리할 수 있도록 알려주어야 합니다. HA 프로젝트 과정에, 특별한 표기법을 통해서 각 멱등한 동작들을 구분할 수 있도록 Hadoop IPC 시스템을 확장했습니다.
Current Status
HA Name Node 에 대한 실제 개발은 아파치 하둡 trunk의 branch로써, 2011년 8월 부터 시작되었습니다. 개발은 HDFS-1623 과 HADOOP-7454 밑에서 완료되었습니다. 지난주 금요일, 2012년 3월 2일에 해당 branch를 아파치 하둡 trunk에 머지하였습니다. 해당 기능을 개발하면서 170개의 개별 지라 작업을 종료했습니다. 해당 작업을 HDFS trunk에서 0.23 branch로 머지해서, 아파치 하둡 0.23 릴리즈에의 업데이트로써 릴리즈하는 것이 목표입니다. 해당 작업의 대부분은 이미 2012년 2월 13일에 배포된 CDH4 beta 1 에서 이용할 수 있습니다.
failover 가 시작될 때 잠시, active Name Node가 멈추고, standby Name Node가 시작되는 작업이 몇초 정도 걸립니다. 이것은 잠시, 또는 인식하지 못할 정도로, 서비스가 failover 과정중에 동작하지 않을 수 있습니다. 개인적으로 HA cluster에서 수 백개의 MR 작업을 실행시키는데, 어떤 작업의 실패없이 두 대의 HA Name Nodes 에서 교대로 failover를 수행했습니다.
HA Name Node 첫 구현은 오직 수동 failover 만 지원합니다. 즉, 시스템에 의해서 Name Node중의 하나의 장애를 아직 자동으로 판별할 수 없고, Name Node 간의 failover 시작시에 오퍼레이터가 개입을 필요로 합니다. 이런 명백한 제약 사항에도 불구하고, 해당 버전은 많은 경우의 예정된 HDFS 다운타임을 제거하는데 유용합니다. 예를 들어, Name Node 설정의 변경이나, Name Node 장비의 예정된 유지 보수 또는 Name Node의 OS 업그레이드 시입니다.
Next Up
HA Name Node 구현에서 가장 우선순위가 높은 기능은 자동으로 Active Name Node의 장애를 탐지하는 것과 Active가 더 이상 동작하지 않는다고 생각될 때, 자동적으로 failover를 시작하는 것을 제공하는 것입니다. HDFS-3042 와 그 하위 태스크로 해당 기능을 제공하기 위해서 열심히 일하고 있습니다.
HDFS 변경 로그를 위한 HA file들에 대한 의존은 빨리 해결하고 싶은 제약사항입니다. 다음과 같은 몇개의 옵션들이 해결방법으로 논의되고 있습니다.
- BookKeeper – BookKeeper 는 고가용성 WAL 시스템입니다. 변경로그를 BookKeeper 에 쓰는 작업은 아직 HA Name Node와 함께 테스트되지는 않았지만, 이미 완료된 작업입니다.
- Multiple, non-HA filers – HA Name Node는 현재 오직 하나의 공유 edits 디렉토리에만 로깅을 합니다. 현재 상황에서 아마 가장 쉬운 구현은 Name Node 가 로그를 여러 공유 디렉토리에 나믹도록 허용하고 모든 로그는 과반 수 이상의 공유 디렉토리에 쓰여지게 하는 것입니다. 이것은 HDFS-2782에서 제안되었습니다.
- Stream edits to remote NNs – 로컬 파일 에 변경 사항을 쓰는 것 뿐만 아니라, 네트웍을 통해서 바로 변경 사항을 다른 Name Node로도 보내는 것입니다. Active Name Node 는 클라이언트에게 성공 응답을 주기 전에 과반 수 이상의 다른 Name Node로 부터 해당 변경에 대한 응답을 받아야 합니다.
- Store edit logs in HDFS itself – HBase 같은 시스템은 이미 HDFS에 모든 변경을 저장하는 WAL 데이터를 저장하고 있습니다. 만약에 HDFS가 시작 정보의 일부를 조금 확장한다면, HDFS 변경 로그를 HDFS에 저장하는 것은 불가능 하지 않습니다. HDFS-2601 에서 제안되었습니다.
몇 주 안에, 모든 옵션을 테스트하고 그 중에 하나를 선택해서 구현할 것입니다.
현재 HA Name Node의 배포는 조금 힘듭니다. 오퍼레이터가 Name Node들 간의 디스크 메타데이터 정보를 수동으로 싱크해야 합니다. HDFS-2731 에서 두 번째 Name Node 가 자동적으로 첫 번째 Name Node와 싱크를 맞춤으로써 사용자의 배포 과정을 개선하는 것을 목표로 하고 있습니다. 해당 기능은 배포 과정을 더 빠르고 에러가 적도록 해 줄 것입니다.
Further Reading
CDH4 에서의 HA Name Node 의 자세한 설명을 원하시면 CDH4 docs 를 보시기 바랍니다.( 역자 주: 아직 까지는 CDH4는 실무에서 사용할 레벨은 아닙니다. CDH3를 이용하시길 권장합니다. )
Todd Lipcom이 올린 블로그 포스트를 기대하기 바랍니다. HA Name Node 기능들을 구현하는 동안에 맞닫드렸던 문제들과 이를 어떻게 해결했는지 상세히 올릴 것입니다.
Acknowledgments
해당 작업은 처음부터, 커뮤니티의 노력으로 시작했고, 많은 컨트리뷰터들의 작업을 대표하는 것입니다. 설계와 구현 모두 많은 사람들의 노력이 모인 것이고, Todd Lipcon, Eli Collins, Uma Maheswara Rao G, Bikas Saha, Suresh Srinivas, Jitendra Nath Pandey, Hari Mankude, Brandon Li, Sanjay Radia, Mingjie Lai, and Gregory Chanan 등의 컨트리뷰터 없이는 불가능 했을 것입니다. 또한 테스트에 유용한 설계 토론과 조언을 해준 Dhruba Borthakur, Konstantin Shvachko 에게도 감사합니다. Stephen Chu, Wing Yew Poon, Patrick Ramsey 에게도 도움에 감사합니다.