Hadoop1 시절에는 NameNode가 SPOF(SinglePointOfFailure)였음.
그때도 체크포인팅 주기를 조절하는 등 나름대로의 FailOver 노력이 있었으나,
Hadoop2 부터는 정식으로 고가용성(HighAvailability)을 보장하는 세팅이 가능함.
아래는 QJM(QuorumJournalManager)로 HA를 구성한 HDFS 구성도. (YARN관련은 제외)
각 프로세스별 동작은 아래와 같음.
Zookeeper는 네임서비스별 active/standby NameNode의 정보를 저장.
DFSZKFailoverController는 NameNode를 모니터링 하고 있다가 active NameNode가 죽으면,
standby NameNode를 active로 전환시키고 죽은 active NameNode를 클러스터에서 뽑아내고,
Zookeeper에 정보를 갱신.
JournalNode는 namespace가 변경될 때 발생하는 edit log를 저장함.
최소 3대 이상 홀수로 실행되어야 하며, (N/2)+1 이상의 JournalNode가 살아있어야 정상동작이 보장됨.
NameNode(active)는 edit log를 JournalNode에 기록. (active만 기록 가능)
NameNode(standby)는 JournalNode에서 edit log를 읽어와 fsImage 갱신.
DataNode는 active/standby NameNode 모두에 Block 정보와 HeartBeat 보냄.
NameNode HA 구성 예제.
기존 구성이 아래와 같다고 가정함. (YARN 관련 프로세스 제외)
server01: NameNode
server02: SecondaryNameNode, DataNode
server03: DataNode
server04: DataNode
server05: DataNode
HA 구성은 아래처럼 할 예정. (YARN 관련 프로세스 제외)
server01: QuorumPeerMain(zookeeper), JournalNode, DFSZKFailoverController, NameNode(active)
server02: QuorumPeerMain(zookeeper), JournalNode, DFSZKFailoverController, NameNode(standby)
server03: QuorumPeerMain(zookeeper), JournalNode, DataNode
server04: DataNode
server05: DataNode
신규설치가 아니라 기존 non-HA NameNode를 HA NameNode로 컨버팅하는 예제임에 주의.
그래봐야 hdfs namenode -format 정도가 대체되는 수준이지만..
또 하나 주의할 점은 Failover 상황시 standby NameNode가 active NameNode로 전환되면서 이 서버 저 서버 집적거려야 하므로,
server02 도 클러스터 내부 서버들을 인증없이 ssh 로 들락거릴 수 있도록 세팅해야 함. (server01은 이미 되어있을테고)
우선 zookeeper 설치.
server01 에서 아래처럼 설치.
// 다운로드
[root@server01]# cd /home
[root@server01]# wget http://mirror.apache-kr.org/zookeeper/zookeeper-3.4.6/zookeeper-3.4.6.tar.gz
// 압축해제, 설정
[root@server01]# tar xvfz zookeeper-3.4.6.tar.gz
[root@server01]# mv zookeeper-3.4.6 zookeeper
[root@server01]# cd zookeeper
[root@server01]# cp conf/zoo_sample.cfg conf/zoo.cfg
[root@server01]# vi conf/zoo.cfg
// 아래처럼 설정하고 저장
;;zoo.cfg
tickTime=2000
initLimit=10
syncLimit=5
dataDir=/home/zookeeper/data
clientPort=2181
maxClientCnxns=0
maxSessionTimeout=180000
server.1=server01:2888:3888
server.2=server02:2888:3888
server.3=server03:2888:3888
// 데이터 디렉토리 생성, myid 세팅
[root@server01]# mkdir -p /home/zookeeper/data
[root@server01]# echo 1 > /home/zookeeper/data/myid
// 여기까지 한 다음 /home/zookeeper를 압축해서 scp 등으로 server02, server03 에 전송
// 그리고 server02, server03 서버에서 /home/zookeeper/data/myid 파일 내용을 각각 2, 3으로 저장
[root@server02] # echo 2 > /home/zookeeper/data/myid
[root@server03] # echo 3 > /home/zookeeper/data/myid
// 이제 server01~03 에서 zookeeper 서버 실행
[root@server01]# /home/zookeeper/bin/zkServer.sh start
[root@server02]# /home/zookeeper/bin/zkServer.sh start
[root@server03]# /home/zookeeper/bin/zkServer.sh start
// jps 실행해서 QuorumPeerMain이 떠있으면 성공.
[root@server01]# jps
25051 QuorumPeerMain
// 서버 상태 확인 (Mode가 leader 아니면 follower로 나올것임)
[root@server01]# /home/zookeeper/bin/zkServer.sh status
JMX enabled by default
Using config: /home/zookeeper/bin/../conf/zoo.cfg
Mode: follower
이제 Hadoop 세팅.
Hadoop은 /home/hadoop 경로에 설치되어 있다고 가정함.
NameNode HA 에서는 SecondaryNameNode란 게 사라지므로,
/home/hadoop/etc/hadoop 경로의 설정파일 중 masters 파일은 이제 쓸모없게 됨.
나머지 설정정보는 그대로 두고 아래 파일들만 설정을 바꿔주면 됨.
core-site.xml
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>
<configuration>
<!-- 기본 파일시스템 명 -->
<property>
<name>fs.defaultFS</name>
<value>hdfs://my-hadoop-cluster</value>
</property>
<!-- zookeeper 서버 리스트 -->
<property>
<name>ha.zookeeper.quorum</name>
<value>server01:2181,server02:2181,server03:2181</value>
</property>
</configuration>
hdfs-site.xml (설정할 게 좀 되므로 HA와 관계없는 설정들은 제외함)
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>
<configuration>
<!-- 저널노드가 edit logs를 저장할 경로 -->
<property>
<name>dfs.journalnode.edits.dir</name>
<value>/home/hadoop/data/dfs/journalnode</value>
</property>
<!--
네임서비스 리스트. 콤마(,)로 구분하여 여러개 설정가능.
HDFS Federation 등을 위한 부분인데, 일단 core-site.xml에서 fs.defaultFS로 지정한 이름 하나만 지정함.
-->
<property>
<name>dfs.nameservices</name>
<value>my-hadoop-cluster</value>
</property>
<!-- my-hadoop-cluster 네임서비스의 NameNode ID -->
<property>
<name>dfs.ha.namenodes.my-hadoop-cluster</name>
<value>nn1,nn2</value>
</property>
<!-- nn1 NameNode의 RPC 포트 -->
<property>
<name>dfs.namenode.rpc-address.my-hadoop-cluster.nn1</name>
<value>server01:8020</value>
</property>
<!-- nn2 NameNode의 RPC 포트 -->
<property>
<name>dfs.namenode.rpc-address.my-hadoop-cluster.nn2</name>
<value>server02:8020</value>
</property>
<!-- nn1 NameNode의 Web UI 포트 -->
<property>
<name>dfs.namenode.http-address.my-hadoop-cluster.nn1</name>
<value>server01:50070</value>
</property>
<!-- nn2 NameNode의 Web UI 포트 -->
<property>
<name>dfs.namenode.http-address.my-hadoop-cluster.nn2</name>
<value>server02:50070</value>
</property>
<!-- NameNode가 edit log를 쓰고 읽을 JournalNode URI -->
<property>
<name>dfs.namenode.shared.edits.dir</name>
<value>qjournal://server01:8485;server02:8485;server03:8485/my-hadoop-cluster</value>
</property>
<!-- HDFS 클라이언트가 active NameNode에 접근할 때 사용되는 Java class -->
<property>
<name>dfs.client.failover.proxy.provider.my-hadoop-cluster</name>
<value>org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider</value>
</property>
<!-- Failover 상황에서 기존 active NameNode를 차단할 때 사용할 방법 지정 -->
<property>
<name>dfs.ha.fencing.methods</name>
<value>sshfence</value>
</property>
<!--
ha.fencing.method를 sshfence로 지정했을 경우 ssh를 경유해 기존 active NameNode를 죽이는데,
이때 passphrase를 통과하기 위해 SSH private key file을 지정해야 함.
-->
<property>
<name>dfs.ha.fencing.ssh.private-key-files</name>
<value>/home/USERNAME/.ssh/id_rsa</value>
</property>
<!-- 장애복구를 자동으로 한다고 지정 -->
<property>
<name>dfs.ha.automatic-failover.enabled</name>
<value>true</value>
</property>
</configuration>
여기까지 설정하고 설정파일 압축해서 서버 전체에 배포.
이제 본격적으로 실행.
// zookeeper 초기화
[root@server01]# /home/hadoop/bin/hdfs zkfc -formatZK
// 초기화 확인을 위해 zookeeper 접속
[root@server01]# /home/zookeeper/bin/zkCli.sh
// /hadoop-ha 아래에 dfs.nameservices 지정한 nameserviceID 노드가 있으면 성공.
ls /hadoop-ha
[my-hadoop-cluster]
// 빠져나오자
[zk: localhost:2181(CONNECTED) 1] quit
// server01~03 에서 JournalNode 실행
[root@server01]# /home/hadoop/sbin/hadoop-daemon.sh start journalnode
[root@server02]# /home/hadoop/sbin/hadoop-daemon.sh start journalnode
[root@server03]# /home/hadoop/sbin/hadoop-daemon.sh start journalnode
// 저널 초기화
[root@server01]# /home/hadoop/bin/hdfs namenode -initializeSharedEdits
// active NameNode 실행
[root@server01]# /home/hadoop/sbin/hadoop-daemon.sh start namenode
// active NameNode용 ZKFC 실행
[root@server01]# /home/hadoop/sbin/hadoop-daemon.sh start zkfc
// 확인
[root@server01]# jps
1096 NameNode
1650 DFSZKFailoverController
1456 JournalNode
25051 QuorumPeerMain
// 전체 DataNode 실행 (server03 ~ 05)
[root@server03]# /home/hadoop/sbin/hadoop-daemon.sh start datanode
[root@server04]# /home/hadoop/sbin/hadoop-daemon.sh start datanode
[root@server05]# /home/hadoop/sbin/hadoop-daemon.sh start datanode
// server02에서 standby NameNode 준비
[root@server02]# /home/hadoop/bin/hdfs namenode -bootstrapStandby
// standby NameNode 실행
[root@server02]# /home/hadoop/sbin/hadoop-daemon.sh start namenode
// standby NameNode용 ZKFC 실행
[root@server02]# /home/hadoop/sbin/hadoop-daemon.sh start zkfc
// 여기까지 하면 NameNode HA 설정완료.
// 이제 나머지 YARN, JobHistoryServer를 실행
[root@server01]# /home/hadoop/sbin/start-yarn.sh
[root@server01]# /home/hadoop/sbin/mr-jobhistory-daemon.sh start historyserver
여기까지 하면 완료.
잘 돌아가는지 확인하고 싶으면 http://server01:50070 혹은 http://server02:50070 으로 접속해도 되고,
아래처럼 haadmin 명령어로 확인도 가능함.
// 각 NameNode 상태확인
[root@server01]# /home/hadoop/bin/hdfs haadmin -getServiceState nn1
active
[root@server01]# /home/hadoop/bin/hdfs haadmin -getServiceState nn2
standby
이제 진짜 Failover가 되는지 테스트.
// NameNode의 active/standby 상태는 위처럼 nn1이 active, nn2가 standby라고 가정.
// active NameNode를 죽여보자.
[root@server01]# jps
1456 JournalNode
25051 QuorumPeerMain
1096 NameNode
1650 DFSZKFailoverController
26058 JobHistoryServer
1911 ResourceManager
[root@server01]# kill -9 1096
// active NameNode가 죽은 후 standby였던 nn2의 상태를 확인해보면 active로 바뀐 걸 확인할 수 있음.
[root@server01]# /home/hadoop/bin/hdfs haadmin -getServiceState nn2
active
// 기타 나머지 dfs 관련 명령어도 아무 문제 없이 잘 되는 것을 확인해 보자.
// 이제 죽었던 namenode를 다시 살리고
[root@server01]# /home/hadoop/sbin/hadoop-daemon.sh start namenode
// 죽었다 살아난 namenode는 이제 standby
[root@server01]# /home/hadoop/bin/hdfs haadmin -getServiceState nn1
standby
ps. 혹시나 삽질할 사람이 있을까 걱정되어 사족을 남기는데, 내 경험에 의하면 Hadoop 1.0.0 에서 2.6.0 으로 업그레이드 할 때 한방에 HA로는 안되었음.
일단 non-HA 로 업그레이드하고 나서 HA 로 컨버팅하는 것을 권장함.
나는 어떻게든 되지 않을까 싶어서 삽질하다가 시간만 옴팡지게 낭비했음.
[참고]
'Hadoop' 카테고리의 다른 글
[Hadoop] HDFS - Short Circuit Local Reads (0) | 2015.04.02 |
---|---|
[Hadoop] YARN - ResourceManager HA (HighAvailability) (2) | 2015.04.01 |
[Hadoop2] YARN - NodeManager 추가/삭제 (0) | 2015.03.31 |
[Hadoop2] pid 파일 저장경로 설정 (hadoop pid dir configuration) (0) | 2015.03.30 |
[Hadoop] 웹 인터페이스에 인증 달기 (Securing Hadoop Web UI) (0) | 2015.03.25 |