main










Cluster : The Beginning - Hadoop 2.9.0 설치


이제 라즈베리파이의 구성은 모두 정리가 되었고 맥미니에 클러스터를 구성할 차례이다.
이 글을 쓰는 시점에는 이미 모든 클러스터 구성이 완료 되었으나 여전히 많은 작업이 남아있다.


하지만 모든 클러스터를 구성하는 것 까지는 초보 수준에서 가장 기초적인 설정만으로 진행하고 있으니
같은 맥락에서 진행을 하도록 하겠다.


맥미니에 설치할 Hadoop ecosystem은 3가지로 Hadoop과 HBase 그리고 Spark이다.
HBase는 Cassandra와 고민을 좀 했는데 아무래도 하둡과의 궁합을 생각해서 HBase를 설치하기로 했다.
Spark의 경우 Spark MLlib 때문에 설치해보기로 했는데 메모리를 이용한 시스템이다보니 가정용 PC의 뻔한
메모리 용량으로 제대로 써먹기나 할지 모르겠다(다른 시스템들도 마찬가지지만…).


하둡 배포판 선정


사실 예전에 하둡 1.4와 HBase를 설치했을 때 여러가지 설정과 배포본을 노드에 카피하는 등 많은 작업들이
매우 번거롭게 느껴져서 이번에는 아주 좋은 툴인 Apache Ambari를 사용하여 설치해볼까하고 시도를 해봤다.
그런데 시작부터 막힌 것이 Mac을 지원하지 않아 WMWare에 설치된 Ubuntu에 Ambari를 설치하게 되었다.



일단 설치는 간단하게 되었는데…정작 웹 콘솔을 시작하고 클러스터를 만드는 과정에서 각 노드에 연결을
하지 못하는 문제가 발생을 하였다. 아무래도 Mac에서 진행을 하다보니 지원이 안되는 부분이 있나보다 하고
과감하게 포기를 하고 다시 맨땅에 헤딩하면서 진행을 할 수밖에 없었다.


우선 설치할 시점에서의 최신 버전인 2.9.0 버전을 다운로드 받아 설치하기로 하였다. 그런데 오늘 가서 보니 그새
3.0.0이 새로 릴리즈가 되어있고 2.6.X, 2.7.X, 2.8.X, 2.9.X, 3.0.X가 각각 업데이트가 진행되는 것 같은데
어떤 기준으로 버전이 나누어지고 또 업데이트가 되는지 잘 모르겠다.


배포버전 참조 링크 : http://hadoop.apache.org/releases.html#Download


어쨌든 나는 2.9.0 버전을 선택하여 설치하였다.


설치 환경 및 모드


일단 앞선 몇 번의 포스팅에서 언급한 것과 같이 현재 내가 보유하고 있는 장비는 총 5대의 Mac mini이다.
즉 5대의 PC에 완전 분산모드로 설치를 진행하게 될 것이다. 5대의 host 이름은 각각 다음과 같다.
괄호 안은 떠있게 될 기본 프로세스다. 


  • NAMENODE.local (Active NameNode, JournalNode, ResourceManager, DFSZKFailoverController)
  • SECONDARY-NAMENODE.local (Standby NameNode, JournalNode, DFSZKFailoverController)
    (과거 1.4 설치 때 secondary namenode였음…)
  • DATANODE1.local (DataNode, JournalNode, NodeManager)
  • DATANODE2.local (DataNode , NodeManager)
  • DATANODE3.local (DataNode , NodeManager)


JournalNode 구성 때문에 1대를 더 영입하려다가 참았다…-.-
이후 작성하는 모든 글에서 각 노드는 위에 적은 호스트명을 사용하도록 하겠다.


설치


앞서 설치한 다른 시스템들과 마찬가지로 다운로드 받은 압축 패키지를 적당한 위치에 풀면 설치 끝이다…-.-
나는 현재 모든 시스템들을 /opt 아래에 설치 중이다. 따라서 hadoop의 경로는 /opt/hadoop이고 
버전 정보는 과감하게 빼버렸다.




사전 준비


하둡을 설치하기 전에 한 가지 준비할 것이 있는데 하둡은 마스터(NameNode)와 슬레이브(Datanode)간에
통신을 하는데 SSH를 이용하게 된다. 이 때 SSH 접근 시 비밀번호 인증을 거치게 되면 정상적으로 통신을 할 수
없기 때문에 먼저 비밀번호 인증 없이 접속을 하기 위해 다음과 같은 절차로 준비를 해야 한다.


일반적으로 사용자 계정의 홈 디렉토리에 있는 .ssh라는 디렉토리에 SSH 관련 인증키들이 들어있다. 만일 기존에
사용 중인 인증 키(보통 id_rsa, id_rsa.pub이라는 이름) 파일들이 보이면 그 파일들을 이용하면 될 것이고 파일이
없거나 .ssh 디렉토리 자체가 없다면 다음과 같이 SSH 키를 생성해준다. 이 작업은 Active NameNode 서버와
Standby NameNode 서버에서 각각 진행한다. 아래는 Active NameNode 기준으로 기록하였다.


'hadoop@NAMENODE.local$ ssh-keygen -t rasa -f  ~/.ssh/id_rsa

당연한 이야기이겠지만 Standby NameNode에서 할 때는 nn2_id_rsa와 같이 키 파일 이름을 다르게 해야
나중에 DataNode로 복사를 할 때 파일을 덮어쓰는 문제를 피할 수 있다.


이렇게 하면 인증키 파일이 생성이 된다. 이제 이 인증키 파일 중 공개키에 해당하는 id_rsa.pub 파일을 각 
DataNode들로 복사를 해준다.


'hadoop@NAMENODE.local$ scp ~/.ssh/id_rsa.pub hadoop@DATANODE1.local:/Users/hadoop/.ssh/id_rsa.pub 
'hadoop@NAMENODE.local$ scp ~/.ssh/id_rsa.pub hadoop@DATANODE2.local:/Users/hadoop/.ssh/id_rsa.pub 
'hadoop@NAMENODE.local$ scp ~/.ssh/id_rsa.pub hadoop@DATANODE3.local:/Users/hadoop/.ssh/id_rsa.pub 


다음 각각의 DataNode의 ~/.ssh 디렉토리로 이동하여 아래와 같이 인증 키 목록에 NameNode에서 받은
인증키의 내용을 추가해준다.


hadoop@DATANODE1.local$ cat  ~/.ssh/id_rsa.pub >> authorized_keys
hadoop@DATANODE2.local$ cat  ~/.ssh/id_rsa.pub >> authorized_keys
hadoop@DATANODE3.local$ cat  ~/.ssh/id_rsa.pub >> authorized_keys


이렇게 만들어진 authorized_keys 파일을 열어보면 대략 이렇게 생겼다.




마지막으로 ssh-agent를 실행하고 ssh-add를 해준다(예전에도 이런 것을 해줬는지 가물가물한데 해야 한다는
것을 보니 아무래도 예전에 내가 뭘 잘못했던게지…-.-)


hadoop@NAMENODE.local$ eval "$(ssh-agent -s)"  
Agent pid 59566  
hadoop@NAMENODE.local$ ssh-add ~/.ssh/id_rsa


가운데 줄은 첫 줄 실행의 결과다. 주의할 것은 콘솔창에서 이렇게만 실행하면 그 콘솔창의 세션 내에서만 반영이
된다. 즉, 콘솔창을 죽였다가 새로 실행하면 이 작업을 다시 해줘야 비밀번호 인증 없이 ssh 접속이 가능하게 된다.
또한 이 세션은 실행한 계정 내에서만 유효하다.


하둡 1.X vs 2.X


간단하게 예전에 설치했던 하둡 1.4와 비교를 하고 넘어가겠다. 생각외로 변경된 사항 때문에 설정해야 할 것들이
많아져서 가볍게라도 언급을 해두어야 할 것 같다. 우선 아래 그림을 먼저 보자.




중요한 변화를 2가지만 짚어보면


HA(High Availability) Cluster 구성

하둡 1.X에서는 NameNode는 1대만 설치가 가능하였으나 하둡 2.X에서는 2대 이상의 
NameNode를 설치할 수 있는데 이 모든 NameNode가 동시에 작동하는 것이 아니라
이 중 1대만이 Active NameNode로 활성화 되고 다른 NameNode들은 Standby
NameNode로, 말 그대로 대기를 하고 있다가 Active NameNode가 다운되었을 경우 
Active 상태가 되어 NameNode로서의 임무를 수행하게 된다. 

이런 운영이 가능하려면 NameNode들 간에 항상 데이터가 공유되어야 하며 그 방법에는
NFS(NAS와 같은 공유 저장소)를 이용하는 방법과 zookeeper와 JournalNode를 이용하는
방법이 있는데 보통 zookeeper와 JournalNode를 이용하는 방법을 많이 쓴다고 한다.
JournalNode는 3개 이상 홀수로 구성을 해야 한다.


YARN의 등장

기존에 MapReduce의 작동이 JobTracker와 TaskTracker를 통해 이루어지던 것이
YARN의 ResourceManager와 NodeManager를 통해 자원 관리 및 모니터링이
이루어지도록 바뀌었다.


하둡 1.X에서는 Secondary NameNode라는 개념이 있었는데 2.X에서도 여전히 사용 가능하며
다만 HA 클러스터를 구성하는 경우에는 Secondary NameNode를 사용할 수 없다.


이런 변화로 인해 하둡 2.X에서는 zookeeper에 대한 설정을 해야 하며 JournalNode 프로세스를
띄워야 하고 YARN을 구동시켜야 하는 등 1.X에 비해 해야 할 일이 늘었다. 


참고로 zookeeper는 이전에 Kafka 설치 시 라즈베리파이에 함께 설치한 zookeeper를 함께 사용한다. 


아래 이미지는 2.X의 구조를 나타낸 그림이다.




설정


설치는 언급할 것도 없이 매우 간단하였고…이제는 설정이다. 역시나 설정도 필수적인 몇몇 항목만 제대로 
설정을 하면 나머지는 기본값으로 그냥 사용하면 된다. 그리고 경로도 좀 독특해서 아래와 같은 경로에 설정 파일들이 
존재한다.


/opt/hadoop/etc/hadoop


그런데!
다른 시스템들과는 달리 하둡은 설정 파일에 기본 값들이 들어있지 않다! 즉, 파일에 최상위 엘리먼트 태그만
덩그러니 있고 내용은 비어있다. 따라서 일단 잘 설명되어있는 블로그나 사이트로 가서 기본적인 내용을 
복사해와야 한다…ㅠ.ㅠ 내가 설정한 내용은 다음과 같다.


  • core-site.xml
<!-- 필수 설정 -->
<property>
      <name>fs.defaultFS</name>
      <value>hdfs://NAMENODE.local:9090</value>
</property>
<!-- 아래 2개의 설정은 옵션~
<property> 
      <name>io.file.buffer.size</name>
      <value>131072</value>
</property>
<property> 
      <name>hadoop.tmp.dir</name>
      <value>/opt/hadoop/temp</value>
</property>
-->
<!--
HA Cluster를 구성할 때 JournalNode를 관리하기 위한 zookeeper 서버를 설정 
이 서버들은 이전에 포스팅한 Kafka 설치 관련 내용에서 이미 설치해둔 라즈베리파이들이다. 
-->
<property> 
      <name>ha.zookeeper.quorum</name>
      <value>rpi1,rpi2,rpi3</value>
</property>



  • hdfs-site.xml
<!-- 
아래 내용 중 데이터 복제 계수를 의미하는 dfs.replication가 설정되지 않았는데 기본값으로
3이 적용 된다.
-->
<!-- NameNode가 namespace와 transaction 로그를 저장하기 위한 경로 -->
<property>
          <name>dfs.namenode.name.dir</name>
          <value>/Users/hadoop/data/dfs/namenode</value>
</property>
<!-- DataNode 자체 및 클러스터와의 관계에 대한 메타데이터를 저장하기 위한 경로 -->
<property>
          <name>dfs.datanode.data.dir</name>
          <value>/Users/hadoop/data/dfs/datanode</value>
</property>
<!-- JournalNode의 메타데이터를 저장하기 위한 경로 -->
<property>
          <name>dfs.journalnode.edits.dir</name>
          <value>/Users/hadoop/data/dfs/journalnode</value>
</property>
<!-- 이하는 HA Cluster 구성을 위해 필요한 내용 -->
<!-- 클러스터 내의 nameservice를 대표하는 논리적인 이름 -->
<property>
	<name>dfs.nameservices</name>
         <value>mazberrycluster</value>
</property>
<!-- 위에서 설정한 nameservice 내에서 사용될 NameNode들의 논리적 이름 -->
<property>
	<name>dfs.ha.namenodes.mazberrycluster</name>
	<value>nn1,nn2</value>
</property>
<!-- 첫 번째 NameNode(nn1)에서 사용할 RPC 호스트:포트 -->
<property>
	<name>dfs.namenode.rpc-address.mazberrycluster.nn1</name>
	<value>NAMENODE.local:8020</value>
</property>
<!-- 두 번째 NameNode(nn2)에서 사용할 RPC 호스트:포트 -->
<property>
	<name>dfs.namenode.rpc-address.mazberrycluster.nn2</name>
	<value>SECONDARY-NAMENODE.local:8020</value>
</property>
<!-- 첫 번째 NameNode(nn1)에서 사용할 Web UI 호스트:포트 -->
<property>
	<name>dfs.namenode.http-address.mazberrycluster.nn1</name>
	<value>NAMENODE.local:50070</value>
</property>
<!-- 두 번째 NameNode(nn2)에서 사용할 Web UI 호스트:포트 -->
<property>
	<name>dfs.namenode.http-address.mazberrycluster.nn2</name>
	<value>SECONDARY-NAMENODE.local:50070</value>
</property>
<!-- 각 JournalNode에서 공유할 데이터를 저장할 URI -->
<property>
	<name>dfs.namenode.shared.edits.dir</name>
	<value>qjournal://NAMENODE.local:8485;SECONDARY-NAMENODE.local:8485;DATANODE1.local:8485/mazberrycluster</value>
</property>
<!-- 클라이언트가 Active NameNode에 접근할 때 사용할 JAVA 클래스 -->
<property>
	<name>dfs.client.failover.proxy.provider.mazberrycluster</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>
<!-- 위에서 ssh를 사용하기로 했기 때문에 ssh 인증키 경로를 설정해준다. -->
<property>
        <name>dfs.ha.fencing.ssh.private-key-files</name>
        <value>/Users/hadoop/.ssh/id_rsa</value>
</property>
<!-- 자동으로 Failover 처리를 할 것인지 -->
<property>
        <name>dfs.ha.automatic-failover.enabled</name>
        <value>true</value>
</property>



  • slaves
## Slave. 즉, DataNode로 사용할 서버의 호스트명을 적어준다.
DATANODE1.local
DATANODE2.local
DATANODE3.local



  • mapred-site.xml
<!-- Map-Reduce 실행 시 관리 프레임워크로 YARN을 지정 -->
<property>
      <name>mapreduce.framework.name</name>
      <value>yarn</value>
</property>



  • yarn-site.xml
<!-- Map-Reduce 실행시 사용할 셔플 서비스 설정 -->
<property>
      <name>yarn.nodemanager.aux-services</name>
      <value>mapreduce_shuffle</value>
</property>
<!-- 위에 설정한 셔플 수행을 위한 JAVA 클래스 -->
<property>
      <name>yarn.nodemanager.auxservices.mapreduce.shuffle.class</name>
      <value>org.apache.hadoop.mapred.ShuffleHandler</value>
</property>
<!-- 위에 설정한 셔플 수행을 위한 JAVA 클래스 -->
<property>
          <name>yarn.nodemanager.local-dirs</name>
          <value>/opt/hadoop/data/yarn/nm-local-dir</value>
</property>
<!-- ResourceManager 상태가 저장될 경로 -->
<property>
          <name>yarn.resourcemanager.fs.state-store.uri</name>
          <value>/opt/hadoop/data/yarn/system/rmstore</value>
</property>
<!-- ResourceManager가 수행될 노드의 호스트명 -->
<property>
          <name>yarn.resourcemanager.hostname</name>
          <value>NAMENODE.local</value>
</property>
<!-- YARN의 web proxy 주소:포트 -->
<property>
          <name>yarn.web-proxy.address</name>
          <value>0.0.0.0:8089</value>
</property>


휴…이제 설정이 끝난 것 같다.
이렇게 설정이 끝났으면 설치한 하둡 배포판을 모든 노드의 같은 경로에 복사해준다.



마지막으로 데몬 실행 파일들에 보면 실제로 데몬을 실행하는 코드가 모두 nohup으로 시작하는데 Mac에서는
nohup 명령어가 없다. 따라서 파일을 열어 nohup으로 시작하는 명령 코드에서 nohup을 모두 제거해주어야 한다.


실행


상당히 많은 분량의 설정이 있었던 만큼 실행 역시 순탄치 않다.
일단 기본적으로 위에 언급된 것만 해도 NameNode, DataNode, JournalNode, YARN 등이 있다.
게다가 Active와 Standby NameNode를 지정해주기 위한 단계와 Failover 처리를 위한 프로세스도
띄워주어야 한다.


이제부터 차근차근 순서를 밟아 실행을 해보자. 우선 $HADOOP_HOME으로 이동하자.


$ cd /opt/hadoop



  • Failover 컨트롤러 실행을 위해 먼저 zookeeper를 초기화 해주어야 한다.
hadoop@NAMENODE.local$ bin/hdfs zkfc -formatZK



  • JournalNode로 사용할 서버에서 각각 JournalNode 프로세스를 실행한다.
    나의 경우 NAMENODE.local, SECONDARY-NAMENODE.local, DATANODE1.loca의 3대이다.
hadoop@NAMENODE.local$ sbin/hadoop-daemon.sh start journalnode
hadoop@SECONDARY-NAMENODE.local$ sbin/hadoop-daemon.sh start journalnode
hadoop@DATANODE1.local$ sbin/hadoop-daemon.sh start journalnode



  • NameNode를 포맷한다.
hadoop@NAMENODE.local$ bin/hdfs namenode -format



  • Active NameNode를 실행한다.
hadoop@NAMENODE.local$ sbin/hadoop-daemon.sh start namenode



  • zookeeper Failover 컨트롤러를 실행한다.
hadoop@NAMENODE.local$ sbin/hadoop-daemon.sh start zkfc



  • 전체 DataNode를 실행한다 (각각의 DataNode에서 hadoop-daemon.sh로 실행해도 된다.)
hadoop@NAMENODE.local$ sbin/hadoop-daemons.sh start datanode



  • Standby NameNode로 이동하여 Active NameNode의 메타 데이터를 Standby NameNode로 
    복사한다.
hadoop@SECONDARY-NAMENODE.local$ bin/hdfs namenode -bootstrapStandby



  • Standby NameNode를 실행한다.
hadoop@SECONDARY-NAMENODE.local$ sbin/hadoop-daemon.sh start namenode



  • Standby NameNode용 zookeeper Failover 컨트롤러를 실행한다.
hadoop@SECONDARY-NAMENODE.local$ sbin/hadoop-daemon.sh start zkfc



  • 다시 Active NameNode로 돌아와 YARN을 실행한다.
hadoop@NAMENODE.local$ sbin/start-yarn.sh



  • 마지막으로 Map-Reduce를 위한 history 서버를 실행한다.
hadoop@NAMENODE.local$ sbin/mr-jobhistory-daemon.sh start historyserver


이렇게 해서 하둡으로의 긴 여정이 끝이났다…ㅠ.ㅠ


모니터링


하둡을 설치하고 나면 아래와 같이 Active NameNode와 Standby NameNode에서 각각 관리 사이트로
접속을 할 수 있다. 기본 포트는 50070이다.




정리


전체적으로 상당히 긴 과정이었다. 이 것이 그저 꼴랑 5대의 노드로 구성된 클러스터이니 망정이지 수 백, 수 천 대의
노드로 구성된 클러스터라면 정말 관리 시스템의 도움이 없이는 제대로 운영할 수 없을 것이다.


일단 전체 에코시스템 구성에서 가장 큰 고비를 넘긴 것 같다. 이제 정리할 것은 HBase와 Spark만 남겨두고 있다.
하지만 이미 모든 시스템을 설치한 후 각 시스템들을 어떻게 연동하여 데이터를 다룰 것인지에 대해 고민을 하다보니
이후가 더 어려울 것 같다는 생각이 든다.


그래도 차근차근 끝까지 가봐야겠다.






블로그 이미지

마즈다

이미 마흔을 넘어섰지만 아직도 꿈을 좇고 있습니다. 그래서 그 꿈에 다가가기 위한 단편들을 하나 둘 씩 모아가고 있지요. 이 곳에 그 단편들이 모일 겁니다...^^

티스토리 툴바