HDFS 고가용성
HDFS 고가용성 (High Availability)
이 가이드는 HDFS HA(High Availability) 기능과, NameNode에 필요한 공유 저장으로 NFS를 사용하는 HA HDFS 클러스터를 구성·관리하는 방법을 제공합니다.
이 문서는 독자가 HDFS 클러스터의 일반적 구성요소와 노드 유형을 전반적으로 이해하고 있다고 가정합니다. 자세한 내용은 HDFS 아키텍처 가이드를 참고하세요.
참고: Quorum Journal Manager 또는 기존 공유 저장 사용
이 가이드는 Active와 Standby NameNode 사이에서 edit 로그를 공유하기 위해 공유 NFS 디렉터리를 사용하는 HDFS HA 구성 방법을 다룹니다. NFS 대신 Quorum Journal Manager를 사용해 HDFS HA를 구성하는 방법은 대체 가이드를 참고하세요.
배경 (Background)
Hadoop 2.0.0 이전에는 NameNode가 HDFS 클러스터의 단일 실패 지점(SPOF)이었습니다. 각 클러스터에는 단일 NameNode가 있었고, 그 머신이나 프로세스가 사용 불가능해지면 NameNode가 재시작되거나 별도 머신에서 시작될 때까지 클러스터 전체가 사용 불가능했습니다.
이는 HDFS 클러스터의 총 가용성에 두 가지 주요 방식으로 영향을 주었습니다.
- 머신 충돌 같은 비계획적 이벤트의 경우 운영자가 NameNode를 재시작할 때까지 클러스터를 사용할 수 없습니다.
- NameNode 머신의 소프트웨어나 하드웨어 업그레이드 같은 계획된 유지보수 이벤트는 클러스터 다운타임 윈도를 초래합니다.
HDFS 고가용성 기능은 핫 스탠바이(hot standby)를 가진 Active/Passive 구성으로 같은 클러스터에서 두 개(또는 Hadoop 3.0.0부터 그 이상)의 중복 NameNode를 실행하는 옵션을 제공해 위 문제를 해결합니다. 이는 머신이 충돌할 때 새 NameNode로의 빠른 장애 조치(failover), 또는 계획된 유지보수를 위한 관리자 주도의 우아한 장애 조치를 허용합니다.
아키텍처
일반적인 HA 클러스터에서는 두 대 이상의 별도 머신이 NameNode로 구성됩니다. 어느 시점에든 정확히 하나의 NameNode가 Active 상태이고, 나머지는 Standby 상태입니다. Active NameNode는 클러스터의 모든 클라이언트 연산을 담당하고, Standby는 단순히 슬레이브 역할을 하며 필요 시 빠른 장애 조치를 위한 충분한 상태를 유지합니다.
Standby 노드가 Active 노드와 상태를 동기화하려면 현재 구현에서는 노드들이 공유 저장 장치의 디렉터리(예: NAS의 NFS 마운트)에 접근할 수 있어야 합니다. 이 제한은 향후 버전에서 완화될 가능성이 있습니다.
Active 노드가 네임스페이스 수정을 수행하면 그 수정 기록을 공유 디렉터리에 저장된 edit 로그 파일에 영속적으로 기록합니다. Standby 노드는 이 디렉터리의 edits를 계속 감시하며, edits를 보면 자신의 네임스페이스에 적용합니다. 장애 조치가 발생하면 Standby는 Active 상태로 승격하기 전에 공유 저장에서 모든 edits를 읽었는지 확인합니다. 이는 장애 조치가 발생하기 전에 네임스페이스 상태가 완전히 동기화되도록 보장합니다.
빠른 장애 조치를 제공하기 위해 Standby 노드는 클러스터의 블록 위치에 대한 최신 정보도 가져야 합니다. 이를 위해 DataNode는 모든 NameNode의 위치로 구성되며, 모든 NameNode에 블록 위치 정보와 하트비트를 보냅니다.
HA 클러스터의 올바른 작동을 위해 한 번에 하나의 NameNode만 Active여야 하는 것은 매우 중요합니다. 그렇지 않으면 두 네임스페이스 상태가 빠르게 갈라져 데이터 손실이나 다른 잘못된 결과의 위험이 있습니다. 이 속성을 보장하고 이른바 "분할 두뇌 시나리오(split-brain)"를 방지하기 위해 관리자는 공유 저장에 대해 적어도 하나의 펜싱(fencing) 방법을 구성해야 합니다. 장애 조치 중 이전 Active 노드가 Active 상태를 포기했는지 확인할 수 없으면, 펜싱 프로세스가 이전 Active의 공유 edits 저장에 대한 접근을 차단하는 역할을 합니다. 이는 이전 Active가 네임스페이스에 더 이상 edits를 하지 못하게 하여, 새 Active가 장애 조치를 안전하게 진행할 수 있게 합니다.
하드웨어 리소스
HA 클러스터를 배포하려면 다음을 준비해야 합니다.
- NameNode 머신 - Active와 Standby NameNode를 실행할 머신은 서로 동등한 하드웨어를, 그리고 비-HA 클러스터에서 사용할 것과 동등한 하드웨어를 가져야 합니다.
- 공유 저장 - NameNode 머신이 읽기/쓰기 접근 권한을 가진 공유 디렉터리가 필요합니다. 보통 이는 NFS를 지원하고 각 NameNode 머신에 마운트되는 원격 파일러입니다. 현재 단일 공유 edits 디렉터리만 지원됩니다. 따라서 시스템의 가용성은 이 공유 edits 디렉터리의 가용성에 의해 제한되며, 모든 단일 실패 지점을 제거하려면 공유 edits 디렉터리에 중복성이 필요합니다. 구체적으로 저장에 대한 여러 네트워크 경로와 저장 자체의 중복성(디스크, 네트워크, 전원)이 필요합니다. 이 때문에 공유 저장 서버는 단순한 Linux 서버보다 고품질의 전용 NAS 어플라이언스가 권장됩니다.
참고로 HA 클러스터에서는 Standby NameNode도 네임스페이스 상태의 체크포인트를 수행하므로, HA 클러스터에서 Secondary NameNode, CheckpointNode, BackupNode를 실행할 필요가 없습니다. 사실 그렇게 하는 것은 오류입니다. 이는 또한 비-HA HDFS 클러스터를 HA로 재구성하는 사람이 이전에 Secondary NameNode에 전용했던 하드웨어를 재사용할 수 있게 합니다.
배포 (Deployment)
구성 개요
페더레이션 구성과 유사하게 HA 구성은 역호환되며 기존 단일 NameNode 구성을 변경 없이 작동하게 합니다. 새 구성은 클러스터의 모든 노드가 동일한 구성을 가질 수 있도록 설계되었습니다. 즉 노드 유형에 따라 다른 머신에 다른 구성 파일을 배포할 필요가 없습니다.
HDFS 페더레이션처럼 HA 클러스터는 실제로 여러 HA NameNode로 구성될 수 있는 단일 HDFS 인스턴스를 식별하기 위해 nameservice ID를 재사용합니다. 또한 HA와 함께 NameNode ID라는 새 추상화가 추가됩니다. 클러스터의 각 개별 NameNode는 구별하기 위해 서로 다른 NameNode ID를 가집니다. 모든 NameNode에 대한 단일 구성 파일을 지원하기 위해 관련 구성 파라미터에는 nameservice ID와 NameNode ID가 접미사로 붙습니다.
구성 상세
HA NameNode를 구성하려면 hdfs-site.xml 구성 파일에 여러 구성 옵션을 추가해야 합니다.
이 설정들을 설정하는 순서는 중요하지 않지만, dfs.nameservices와 dfs.ha.namenodes.[nameservice ID]에 선택한 값이 그 뒤에 오는 것들의 키를 결정합니다. 따라서 나머지 구성 옵션을 설정하기 전에 이 값들을 결정해야 합니다.
dfs.nameservices - 이 새 nameservice의 논리적 이름
이 nameservice에 대한 논리적 이름(예: "mycluster")을 선택하고 이 구성 옵션의 값으로 사용합니다. 선택한 이름은 임의적입니다. 구성과 클러스터의 절대 HDFS 경로의 authority 구성요소로 모두 사용됩니다.
참고: HDFS 페더레이션도 사용한다면 이 구성 설정에 HA 여부와 관계없이 다른 nameservice 목록을 쉼표로 구분해 포함해야 합니다.
<property>
<name>dfs.nameservices</name>
<value>mycluster</value>
</property>
dfs.ha.namenodes.[nameservice ID] - nameservice의 각 NameNode에 대한 고유 식별자
쉼표로 구분된 NameNode ID 목록으로 구성합니다. DataNode가 클러스터의 모든 NameNode를 결정하는 데 사용합니다. 예를 들어 이전에 nameservice ID로 "mycluster"를 사용하고, NameNode의 개별 ID로 "nn1", "nn2", "nn3"을 사용하려면 이렇게 구성합니다:
<property>
<name>dfs.ha.namenodes.mycluster</name>
<value>nn1,nn2,nn3</value>
</property>
참고: HA의 최소 NameNode 수는 2개이지만 더 구성할 수 있습니다. 통신 오버헤드 때문에 5개를 초과하지 않도록 권장하며, 권장은 3개 NameNode입니다.
dfs.namenode.rpc-address.[nameservice ID].[name node ID] - 각 NameNode가 리스닝할 완전히 한정된 RPC 주소
이전에 구성한 두 NameNode ID 각각에 대해 NameNode 프로세스의 전체 주소와 IPC 포트를 설정합니다. 이는 두 개의 별도 구성 옵션을 초래합니다. 예:
<property>
<name>dfs.namenode.rpc-address.mycluster.nn1</name>
<value>machine1.example.com:8020</value>
</property>
<property>
<name>dfs.namenode.rpc-address.mycluster.nn2</name>
<value>machine2.example.com:8020</value>
</property>
<property>
<name>dfs.namenode.rpc-address.mycluster.nn3</name>
<value>machine3.example.com:8020</value>
</property>
참고: 원하면 "servicerpc-address" 설정도 유사하게 구성할 수 있습니다.
dfs.namenode.http-address.[nameservice ID].[name node ID] - 각 NameNode가 리스닝할 완전히 한정된 HTTP 주소
위의 rpc-address와 유사하게 두 NameNode의 HTTP 서버가 리스닝할 주소를 설정합니다. 예:
<property>
<name>dfs.namenode.http-address.mycluster.nn1</name>
<value>machine1.example.com:9870</value>
</property>
<property>
<name>dfs.namenode.http-address.mycluster.nn2</name>
<value>machine2.example.com:9870</value>
</property>
<property>
<name>dfs.namenode.http-address.mycluster.nn3</name>
<value>machine3.example.com:9870</value>
</property>
참고: Hadoop 보안 기능을 활성화했다면 각 NameNode에 대해 https-address도 유사하게 설정해야 합니다.
dfs.namenode.shared.edits.dir - 공유 저장 디렉터리 위치
Standby NameNode가 Active NameNode가 만드는 모든 파일시스템 변경과 동기화를 유지하는 데 사용하는 원격 공유 edits 디렉터리의 경로를 구성합니다. 이 디렉터리 중 하나만 구성해야 합니다. 이 디렉터리는 NameNode 머신에 r/w로 마운트되어야 합니다. 이 설정의 값은 NameNode 머신에서 이 디렉터리의 절대 경로여야 합니다. 예:
<property>
<name>dfs.namenode.shared.edits.dir</name>
<value>file:///mnt/filer1/dfs/ha-name-dir-shared</value>
</property>
dfs.client.failover.proxy.provider.[nameservice ID] - HDFS 클라이언트가 Active NameNode에 접촉하는 데 사용하는 Java 클래스
DFS Client가 현재 Active인 NameNode, 즉 현재 클라이언트 요청을 서빙하는 NameNode를 결정하는 데 사용할 Java 클래스의 이름을 구성합니다. 현재 Hadoop과 함께 제공되는 두 구현은 ConfiguredFailoverProxyProvider와 RequestHedgingProxyProvider(첫 호출에서 모든 namenode를 동시에 호출해 active를 결정하고, 이후 요청에서는 장애 조치가 일어날 때까지 active namenode를 호출)입니다. 사용자 지정 프록시 제공자를 사용하지 않는다면 이 중 하나를 사용하세요.
<property>
<name>dfs.client.failover.proxy.provider.mycluster</name>
<value>org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider</value>
</property>
dfs.ha.fencing.methods - 장애 조치 중 Active NameNode를 펜싱하는 데 사용할 스크립트 또는 Java 클래스 목록
어느 시점에든 하나의 NameNode만 Active 상태인 것이 시스템 정확성에 매우 중요합니다. 따라서 장애 조치 중 먼저 Active NameNode가 Standby 상태에 있거나 프로세스가 종료되었는지 확인한 다음 다른 NameNode를 Active 상태로 전환합니다. 이를 위해 적어도 하나의 펜싱 방법을 구성해야 합니다. 이것들은 캐리지 리턴으로 구분된 목록으로 구성되며, 펜싱이 성공했음을 나타낼 때까지 순서대로 시도됩니다. Hadoop과 함께 제공되는 세 가지 방법은 shell, sshfence, powershell입니다. 사용자 지정 펜싱 방법 구현에 대한 정보는 org.apache.hadoop.ha.NodeFencer 클래스를 참고하세요.
sshfence - Active NameNode로 SSH하고 프로세스를 죽임
sshfence 옵션은 대상 노드로 SSH하고 fuser를 사용해 서비스의 TCP 포트에서 리스닝하는 프로세스를 죽입니다. 이 펜싱 옵션이 작동하려면 구문 없이 대상 노드로 SSH할 수 있어야 합니다. 따라서 쉼표로 구분된 SSH 개인 키 파일 목록인 dfs.ha.fencing.ssh.private-key-files 옵션도 구성해야 합니다. 예:
<property>
<name>dfs.ha.fencing.methods</name>
<value>sshfence</value>
</property>
<property>
<name>dfs.ha.fencing.ssh.private-key-files</name>
<value>/home/exampleuser/.ssh/id_rsa</value>
</property>
선택적으로 SSH를 수행할 비표준 사용자 이름이나 포트를 구성할 수 있습니다. 또한 SSH에 대한 타임아웃(밀리초)을 구성할 수 있으며, 그 이후에는 이 펜싱 방법이 실패한 것으로 간주됩니다. 이렇게 구성할 수 있습니다:
<property>
<name>dfs.ha.fencing.methods</name>
<value>sshfence([[username][:port]])</value>
</property>
<property>
<name>dfs.ha.fencing.ssh.connect-timeout</name>
<value>30000</value>
</property>
shell - Active NameNode를 펜싱하기 위해 임의의 셸 명령을 실행
shell 펜싱 방법은 임의의 셸 명령을 실행합니다. 이렇게 구성할 수 있습니다:
<property>
<name>dfs.ha.fencing.methods</name>
<value>shell(/path/to/my/script.sh arg1 arg2 ...)</value>
</property>
'('와 ')' 사이의 문자열은 bash 셸에 직접 전달되며 닫는 괄호를 포함해서는 안 됩니다.
셸 명령은 모든 현재 Hadoop 구성 변수를 포함하도록 설정된 환경으로 실행되며, 구성 키에서 '.' 문자 대신 '_' 문자가 사용됩니다. 사용된 구성은 이미 namenode 특정 구성을 일반 형식으로 승격했습니다. 예를 들어 구성이 dfs.namenode.rpc-address.ns1.nn1로 지정하더라도 dfs_namenode_rpc-address는 대상 노드의 RPC 주소를 포함합니다.
추가로, 펜싱할 대상 노드를 가리키는 다음 변수도 사용할 수 있습니다.
| 변수 | 설명 |
|---|---|
$target_host |
펜싱할 노드의 호스트 이름 |
$target_port |
펜싱할 노드의 IPC 포트 |
$target_address |
위 둘을 host:port로 결합한 것 |
$target_nameserviceid |
펜싱할 NN의 nameservice ID |
$target_namenodeid |
펜싱할 NN의 namenode ID |
이 환경 변수들은 셸 명령 자체에서 대체로도 사용될 수 있습니다. 예:
<property>
<name>dfs.ha.fencing.methods</name>
<value>shell(/path/to/my/script.sh --nameservice=$target_nameserviceid $target_host:$target_port)</value>
</property>
셸 명령이 종료 코드 0을 반환하면 펜싱이 성공한 것으로 결정됩니다. 다른 종료 코드를 반환하면 펜싱은 성공하지 않았고 목록의 다음 펜싱 방법이 시도됩니다.
참고: 이 펜싱 방법은 타임아웃을 구현하지 않습니다. 타임아웃이 필요하면 셸 스크립트 자체에서 구현해야 합니다(예: 몇 초 후 자신의 부모를 죽이도록 서브셸을 포크).
powershell - PowerShell을 사용해 머신에 원격으로 연결하고 필요한 프로세스를 죽임
powershell 펜싱 방법은 PowerShell 명령을 사용합니다. 이렇게 구성할 수 있습니다:
<property>
<name>dfs.ha.fencing.methods</name>
<value>powershell(NameNode)</value>
</property>
이 fencer에 전달되는 인자는 "java.exe" 프로세스의 "CommandLine" 속성에서 고유한 문자열이어야 합니다. 예를 들어 Namenode의 전체 경로: "org.apache.hadoop.hdfs.server.namenode.NameNode". 관리자는 고유하다면 이름을 "Namenode"로 줄일 수도 있습니다.
참고: 이는 Windows에서만 작동합니다.
fs.defaultFS - 주어지지 않을 때 Hadoop FS 클라이언트가 사용하는 기본 경로 접두사
선택적으로 이제 Hadoop 클라이언트가 새 HA 활성 논리 URI를 사용하도록 기본 경로를 구성할 수 있습니다. 이전에 nameservice ID로 "mycluster"를 사용했다면 이것이 모든 HDFS 경로의 authority 부분의 값이 됩니다. core-site.xml 파일에서 이렇게 구성할 수 있습니다:
<property>
<name>fs.defaultFS</name>
<value>hdfs://mycluster</value>
</property>
dfs.ha.nn.not-become-active-in-safemode - safemode의 namenode가 active 또는 observer가 되는 것을 방지할지 여부
safemode에 있을 때 namenode가 active가 되는 것을 허용할지 결정합니다. true로 설정하면 safemode의 namenode는 자동 장애 조치가 켜져 있다면 ZKFC에 SERVICE_UNHEALTHY를 보고하고, 자동 장애 조치가 꺼져 있다면 active로의 전환을 실패시키는 예외를 던집니다. safemode에 있을 때 namenode를 observer 상태로 전환하면, 이 설정이 true일 때 namenode가 observer로의 전환을 실패시키는 예외를 던집니다. 예:
<property>
<name>dfs.ha.nn.not-become-active-in-safemode</name>
<value>true</value>
</property>
배포 상세
모든 필요한 구성 옵션이 설정된 후 두 HA NameNode의 온디스크 메타데이터를 처음에 동기화해야 합니다.
새 HDFS 클러스터를 설정하는 중이라면 먼저 NameNode 중 하나에서 format 명령(hdfs namenode -format)을 실행해야 합니다.
이미 NameNode를 포맷했거나 비-HA 클러스터를 HA로 변환하는 중이라면, 포맷되지 않은 다른 NameNode에서 hdfs namenode -bootstrapStandby 명령을 실행해 NameNode 메타데이터 디렉터리의 내용을 다른 NameNode로 복사해야 합니다. 이 명령을 실행하면 공유 edits 디렉터리(dfs.namenode.shared.edits.dir로 구성)가 두 NameNode를 모두 시작할 수 있을 만큼 충분한 edits 트랜잭션을 포함하는지도 보장합니다.
비-HA NameNode를 HA로 변환하는 중이라면 hdfs -initializeSharedEdits 명령을 실행해야 합니다. 이 명령은 로컬 NameNode edits 디렉터리의 edits 데이터로 공유 edits 디렉터리를 초기화합니다.
이 시점에서 평소처럼 모든 HA NameNode를 시작할 수 있습니다.
구성된 HTTP 주소를 탐색하면 각 NameNode의 웹 페이지를 개별적으로 방문할 수 있습니다. 구성된 주소 옆에 NameNode의 HA 상태("standby" 또는 "active")가 표시되는 것을 볼 수 있습니다. HA NameNode가 시작될 때마다 처음에는 Standby 상태입니다.
관리 명령 (Administrative commands)
HA NameNode가 구성되고 시작되었으니, HA HDFS 클러스터를 관리하기 위한 몇 가지 추가 명령에 접근할 수 있습니다. 구체적으로 "hdfs haadmin" 명령의 모든 서브커맨드에 익숙해져야 합니다. 추가 인자 없이 이 명령을 실행하면 다음 사용법 정보가 표시됩니다:
Usage: DFSHAAdmin [-ns <nameserviceId>]
[-transitionToActive <serviceId>]
[-transitionToStandby <serviceId>]
[-failover [--forcefence] [--forceactive] <serviceId> <serviceId>]
[-getServiceState <serviceId>]
[-getAllServiceState]
[-checkHealth <serviceId>]
[-help <command>]
이 가이드는 각 서브커맨드의 상위 수준 사용을 설명합니다. 각 서브커맨드의 특정 사용법은 hdfs haadmin -help <command>를 실행하세요.
transitionToActive 및 transitionToStandby - 주어진 NameNode의 상태를 Active 또는 Standby로 전환
이 서브커맨드들은 주어진 NameNode를 각각 Active 또는 Standby 상태로 전환시킵니다. 이 명령들은 펜싱을 수행하려고 시도하지 않으므로 거의 사용해서는 안 됩니다. 대신 거의 항상 "hdfs haadmin -failover" 서브커맨드를 사용해야 합니다.
failover - 두 NameNode 사이의 장애 조치 시작
이 서브커맨드는 첫 번째로 제공된 NameNode에서 두 번째로 장애 조치를 일으킵니다. 첫 번째 NameNode가 Standby 상태이면 이 명령은 오류 없이 두 번째를 Active 상태로 전환합니다. 첫 번째 NameNode가 Active 상태이면 그것을 우아하게 Standby 상태로 전환하려고 시도합니다. 실패하면 dfs.ha.fencing.methods로 구성된 펜싱 방법이 하나가 성공할 때까지 순서대로 시도됩니다. 이 과정 후에만 두 번째 NameNode가 Active 상태로 전환됩니다. 어떤 펜싱 방법도 성공하지 않으면 두 번째 NameNode는 Active 상태로 전환되지 않고 오류가 반환됩니다.
getServiceState - 주어진 NameNode가 Active인지 Standby인지 결정
제공된 NameNode에 연결해 현재 상태를 결정하고 "standby" 또는 "active"를 STDOUT에 적절히 출력합니다. 이 서브커맨드는 NameNode가 현재 Active인지 Standby인지에 따라 다르게 동작해야 하는 cron 작업이나 모니터링 스크립트가 사용할 수 있습니다.
getAllServiceState - 모든 NameNode의 상태 반환
구성된 NameNode에 연결해 현재 상태를 결정하고 "standby" 또는 "active"를 STDOUT에 적절히 출력합니다.
checkHealth - 주어진 NameNode의 상태 확인
제공된 NameNode에 연결해 상태를 확인합니다. NameNode는 내부 서비스가 예상대로 실행 중인지 확인하는 것을 포함해 스스로 몇 가지 진단을 수행할 수 있습니다. NameNode가 정상이면 이 명령은 0을, 그렇지 않으면 0이 아닌 값을 반환합니다. 모니터링 목적으로 이 명령을 사용할 수 있습니다.
참고: 이는 아직 구현되지 않았으며 현재는 주어진 NameNode가 완전히 다운된 경우가 아니면 항상 성공을 반환합니다.
자동 장애 조치 (Automatic Failover)
소개
위 절들은 수동 장애 조치를 구성하는 방법을 설명합니다. 그 모드에서 시스템은 active 노드가 실패해도 active에서 standby NameNode로의 장애 조치를 자동으로 트리거하지 않습니다. 이 절은 자동 장애 조치를 구성하고 배포하는 방법을 설명합니다.
구성요소 (Components)
자동 장애 조치는 HDFS 배포에 두 개의 새 구성요소를 추가합니다: ZooKeeper 쿼럼과 ZKFailoverController 프로세스(줄여서 ZKFC).
Apache ZooKeeper는 소량의 조정 데이터 유지, 해당 데이터의 변경을 클라이언트에 알림, 클라이언트의 실패 모니터링을 위한 고가용 서비스입니다. HDFS 자동 장애 조치 구현은 다음을 위해 ZooKeeper에 의존합니다.
- 실패 감지(Failure detection) - 클러스터의 각 NameNode 머신은 ZooKeeper에서 영구 세션을 유지합니다. 머신이 충돌하면 ZooKeeper 세션이 만료되어 다른 NameNode에 장애 조치가 트리거되어야 함을 알립니다.
- Active NameNode 선거(Active NameNode election) - ZooKeeper는 노드를 active로 배타적으로 선출하는 간단한 메커니즘을 제공합니다. 현재 active NameNode가 충돌하면 다른 노드가 다음 active가 되어야 함을 나타내는 ZooKeeper의 특별한 배타 잠금을 취할 수 있습니다.
ZKFailoverController(ZKFC)는 ZooKeeper 클라이언트이면서 NameNode의 상태를 모니터링하고 관리하는 새 구성요소입니다. NameNode를 실행하는 각 머신은 ZKFC도 실행하며, 그 ZKFC는 다음을 담당합니다.
- 상태 모니터링(Health monitoring) - ZKFC는 주기적으로 상태 확인 명령으로 로컬 NameNode에 ping합니다. NameNode가 적시에 정상 상태로 응답하는 한 ZKFC는 노드가 정상이라고 간주합니다. 노드가 충돌, 정지 또는 다른 방식으로 비정상 상태에 들어가면 상태 모니터가 비정상으로 표시합니다.
- ZooKeeper 세션 관리 - 로컬 NameNode가 정상일 때 ZKFC는 ZooKeeper에서 세션을 열어 유지합니다. 로컬 NameNode가 active이면 특별한 "lock" znode도 보유합니다. 이 잠금은 ZooKeeper의 "ephemeral"(임시) 노드 지원을 사용합니다. 세션이 만료되면 잠금 노드가 자동으로 삭제됩니다.
- ZooKeeper 기반 선거 - 로컬 NameNode가 정상이고 ZKFC가 현재 다른 노드가 잠금 znode를 보유하지 않음을 보면, 스스로 잠금을 획득하려고 시도합니다. 성공하면 "선거에서 이겼고", 로컬 NameNode를 active로 만들기 위해 장애 조치를 실행할 책임이 있습니다. 장애 조치 과정은 위에서 설명한 수동 장애 조치와 유사합니다: 먼저 필요하면 이전 active가 펜싱되고, 그런 다음 로컬 NameNode가 active 상태로 전환됩니다.
자동 장애 조치 설계에 대한 자세한 내용은 Apache HDFS JIRA의 HDFS-2185에 첨부된 설계 문서를 참고하세요.
ZooKeeper 배포
일반적인 배포에서 ZooKeeper 데몬은 3개 또는 5개 노드에서 실행되도록 구성됩니다. ZooKeeper 자체는 리소스 요구가 가볍기 때문에 ZooKeeper 노드를 HDFS NameNode와 Standby Node와 같은 하드웨어에 공동 배치하는 것이 허용됩니다. 많은 운영자가 세 번째 ZooKeeper 프로세스를 YARN ResourceManager와 같은 노드에 배포합니다. 최상의 성능과 격리를 위해 ZooKeeper 노드가 HDFS 메타데이터와 별개의 디스크 드라이브에 데이터를 저장하도록 구성하는 것이 좋습니다.
ZooKeeper 설정은 이 문서의 범위를 벗어납니다. 우리는 3개 이상의 노드에서 실행되는 ZooKeeper 클러스터를 설정했고 ZK CLI로 연결해 올바른 작동을 검증했다고 가정합니다.
시작 전에
자동 장애 조치 구성을 시작하기 전에 클러스터를 종료해야 합니다. 현재는 클러스터가 실행 중일 때 수동 장애 조치 설정에서 자동 장애 조치 설정으로 전환하는 것이 불가능합니다.
자동 장애 조치 구성
자동 장애 조치 구성은 구성에 두 개의 새 파라미터를 추가해야 합니다. hdfs-site.xml 파일에 다음을 추가합니다.
<property>
<name>dfs.ha.automatic-failover.enabled</name>
<value>true</value>
</property>
이는 클러스터가 자동 장애 조치용으로 설정되어야 함을 지정합니다. core-site.xml 파일에 다음을 추가합니다.
<property>
<name>ha.zookeeper.quorum</name>
<value>zk1.example.com:2181,zk2.example.com:2181,zk3.example.com:2181</value>
</property>
이는 ZooKeeper 서비스를 실행하는 host-port 쌍을 나열합니다.
이 문서의 앞부분에서 설명한 파라미터들과 마찬가지로, 이 설정들은 구성 키에 nameservice ID를 접미사로 붙여 nameservice별로 구성할 수 있습니다. 예를 들어 페더레이션이 활성화된 클러스터에서 dfs.ha.automatic-failover.enabled.my-nameservice-id를 설정해 nameservice 중 하나에 대해서만 자동 장애 조치를 명시적으로 활성화할 수 있습니다.
자동 장애 조치 동작을 제어하기 위해 설정할 수 있는 다른 여러 구성 파라미터도 있습니다. 그러나 대부분의 설치에는 필요하지 않습니다. 자세한 내용은 구성 키 관련 문서를 참고하세요.
ZooKeeper에서 HA 상태 초기화
구성 키가 추가된 후 다음 단계는 ZooKeeper에서 필요한 상태를 초기화하는 것입니다. NameNode 호스트 중 하나에서 다음 명령을 실행해 수행할 수 있습니다.
[hdfs]$ $HADOOP_HOME/bin/zkfc -formatZK
이것은 자동 장애 조치 시스템이 데이터를 저장하는 ZooKeeper 안에 znode를 만듭니다.
start-dfs.sh로 클러스터 시작
구성에서 자동 장애 조치가 활성화되었으므로 start-dfs.sh 스크립트는 이제 NameNode를 실행하는 모든 머신에서 ZKFC 데몬을 자동으로 시작합니다. ZKFC가 시작될 때 자동으로 NameNode 중 하나를 active가 되도록 선택합니다.
클러스터를 수동으로 시작
클러스터의 서비스를 수동으로 관리한다면 NameNode를 실행하는 각 머신에서 zkfc 데몬을 수동으로 시작해야 합니다. 다음을 실행해 데몬을 시작할 수 있습니다.
[hdfs]$ $HADOOP_HOME/bin/hdfs --daemon start zkfc
ZooKeeper 접근 보호
보안 클러스터를 실행 중이라면 ZooKeeper에 저장된 정보도 보호되도록 하고 싶을 것입니다. 이는 악의적인 클라이언트가 ZooKeeper의 메타데이터를 수정하거나 잠재적으로 가짜 장애 조치를 트리거하는 것을 방지합니다.
ZooKeeper의 정보를 보호하려면 먼저 core-site.xml 파일에 다음을 추가합니다.
<property>
<name>ha.zookeeper.auth</name>
<value>@/path/to/zk-auth.txt</value>
</property>
<property>
<name>ha.zookeeper.acl</name>
<value>@/path/to/zk-acl.txt</value>
</property>
이 값들의 '@' 문자에 주목하세요. 이는 구성이 인라인이 아니라 디스크의 파일을 가리킨다는 것을 지정합니다. 인증 정보는 CredentialProvider를 통해서도 읽을 수 있습니다(hadoop-common 프로젝트의 CredentialProviderAPI Guide 참고).
첫 번째로 구성된 파일은 ZK CLI가 사용하는 형식과 동일한 형식의 ZooKeeper 인증 목록을 지정합니다. 예를 들어 이렇게 지정할 수 있습니다.
digest:hdfs-zkfcs:mypassword
여기서 hdfs-zkfcs는 ZooKeeper의 고유 사용자 이름이고, mypassword는 비밀번호로 사용되는 고유 문자열입니다.
다음으로 이 인증에 해당하는 ZooKeeper ACL을 다음 같은 명령으로 생성합니다.
[hdfs]$ java -cp $ZK_HOME/lib/*:$ZK_HOME/zookeeper-3.4.2.jar org.apache.zookeeper.server.auth.DigestAuthenticationProvider hdfs-zkfcs:mypassword
output: hdfs-zkfcs:mypassword->hdfs-zkfcs:P/OQvnYyU/nF/mGYvB/xurX8dYs=
이 출력에서 '->' 문자열 뒤의 부분을 복사해 "digest:" 문자열을 접두사로 붙여 zk-acls.txt 파일에 붙여넣습니다. 예:
digest:hdfs-zkfcs:vlUvLnd8MlacsE80rDuu6ONESbM=:rwcda
이 ACL이 적용되도록 위에서 설명한 대로 zkfc -formatZK 명령을 다시 실행해야 합니다.
그 후 ZK CLI에서 다음과 같이 ACL을 검증할 수 있습니다.
[zk: localhost:2181(CONNECTED) 1] getAcl /hadoop-ha
'digest,'hdfs-zkfcs:vlUvLnd8MlacsE80rDuu6ONESbM=
: cdrwa
자동 장애 조치 검증
자동 장애 조치가 설정되면 그 작동을 테스트해야 합니다. 그러려면 먼저 active NameNode를 찾습니다. NameNode 웹 인터페이스를 방문하면 어떤 노드가 active인지 알 수 있습니다. 각 노드는 페이지 상단에 HA 상태를 보고합니다.
active NameNode를 찾았다면 그 노드에 실패를 일으킬 수 있습니다. 예를 들어 kill -9 <pid of NN>를 사용해 JVM 충돌을 시뮬레이션할 수 있습니다. 또는 머신의 전원을 껐다 켜거나 네트워크 인터페이스를 뽑아 다른 종류의 중단을 시뮬레이션할 수 있습니다. 테스트하려는 중단을 트리거한 후 다른 NameNode가 몇 초 안에 자동으로 active가 되어야 합니다. 실패 감지와 장애 조치 트리거에 필요한 시간은 ha.zookeeper.session-timeout.ms의 구성에 따라 다르지만 기본값은 5초입니다.
테스트가 성공하지 않으면 잘못 구성되었을 수 있습니다. zkfc 데몬과 NameNode 데몬의 로그를 확인해 문제를 더 진단하세요.
자동 장애 조치 FAQ
ZKFC와 NameNode 데몬을 특정 순서로 시작하는 것이 중요한가요?
아니요. 주어진 노드에서 ZKFC를 해당 NameNode보다 먼저 또는 나중에 시작해도 됩니다.
어떤 추가 모니터링을 배치해야 하나요?
NameNode를 실행하는 각 호스트에 모니터링을 추가해 ZKFC가 계속 실행 중인지 확인해야 합니다. 예를 들어 일부 유형의 ZooKeeper 실패에서 ZKFC가 예기치 않게 종료될 수 있으며, 시스템이 자동 장애 조치를 위해 준비되도록 재시작되어야 합니다.
추가로 ZooKeeper 쿼럼의 각 서버도 모니터링해야 합니다. ZooKeeper가 충돌하면 자동 장애 조치가 작동하지 않습니다.
ZooKeeper가 다운되면 어떻게 되나요?
ZooKeeper 클러스터가 충돌하면 자동 장애 조치가 트리거되지 않습니다. 그러나 HDFS는 아무 영향 없이 계속 실행됩니다. ZooKeeper가 재시작되면 HDFS는 문제 없이 다시 연결됩니다.
NameNode 중 하나를 기본/선호로 지정할 수 있나요?
아니요. 현재 이것은 지원되지 않습니다. 먼저 시작되는 NameNode가 active가 됩니다. 선호하는 노드가 먼저 시작되도록 클러스터를 특정 순서로 시작하도록 선택할 수 있습니다.
자동 장애 조치가 구성되어 있을 때 수동 장애 조치를 시작하려면 어떻게 하나요?
자동 장애 조치가 구성되어 있어도 동일한 hdfs haadmin 명령으로 수동 장애 조치를 시작할 수 있습니다. 조정된 장애 조치를 수행합니다.