하둡 (Apache Hadoop) 2. 하둡 완전 분산 모드 구현하기

2021. 1. 7. 03:02빅데이터 플랫폼 (Bigdata Platforms)/아파치 하둡 (Apache Hadoop)


시작하면서

저번 포스팅에서 HDFS는

3. 여러 개로 분산된 저장소를 하나의 파일 시스템처럼 사용하며 원격으로 접속할 수 있다.

고 했습니다.

이는 분산된 장치(하드웨어)의 여러 사용자가 하나의 파일 시스템을 공유하는 것과 마찬가지인데요.

이번 포스팅에서 하둡을 설치하면서, 위의 기능을 설명드리겠습니다.

 


설치 개요

하둡 공식 사이트를 방문하면, 총 3가지 모드의 설치법이 존재합니다.

  1. 싱글 노드 모드(Single node cluster mode)
  2. 의사 분산 모드(Pseudo-Distributed cluster mode)
  3. 완전 분산 모드(Fully-Distributed cluster mode)

싱글 모드 설치법부터 완전 분산 모드 설치법까지 공식 사이트에 나와있습니다.

하지만 여러분의 시간을 아껴주고, 제 자신의 지식을 되새김질 하는 차원에서 처음부터 친절히 가이드하도록 하겠습니다.

 

하둡을 완전 분산 모드에서 가장 기초적으로 설치하는 단계는 아래와 같습니다.

 

  1. 클러스터를 만들 컴퓨터들을 고른다.
  2. 한 라우터로 컴퓨터들을 접속시킨다.
  3. SSH 접속 시 로그인이 필요없도록 한다.
  4. 자바를 설치한다.
  5. 하둡을 다운로드한다.
  6. 환경 변수를 설정한다.
  7. 하둡을 설정한다.
  8. 실행한다.
try { ... } catch {
    print("사실 잘 기억은 안나요...")
}

 

저는 이미 옛날에 고통의 시간(?)을 보내고 클러스터를 구축하였지만, 그 시절의 저는 기록을 좋아하지 않아서 그냥 머리 속에 잠재되어 있어요.
차근히 따라했는데도 불구하고 만일 오류가 났다면, 댓글로 알려주세요.

 

 


1. 클러스터를 만들 컴퓨터들을 고른다.

이미지에 나온대로, 3대의 컴퓨터 dim, oim, jim을 소유하고 있는 각 사용자 denny, park, jong을 가정했어요.

원래 각 노드(컴퓨터)를 부를 때, 마스터(master)와 슬레이브(slave)라고 구분하는 데, slave 라는 말이 안 좋게 들리는 경향이 있어, 앞으로 세컨더리(secondary)라고 바꿔서 부르도록 할게요.

모든 컴퓨터의 운영체제는 Ubuntu 18.04 LTS 입니다.

 

 


2. 한 라우터로 컴퓨터들을 접속시킨다.

크게 어려운 건 없습니다. 한 공유기에 세 컴퓨터를 모두 접속시키면 됩니다.

다만 주의할 점은 만약 컴퓨터의 로컬 ip 주소가 주기적으로 바뀐다면, 각 컴퓨터에 고정 아이피를 할당하는 작업이 필요합니다.

 

대부분 192.168.1.1 로 접속하면 공유기를 설정할 수 있는 GUI가 등장하며, 대부분 LAN -> DHCP (Dynamic Host Configuration Protocol) 와 같은 장소에 접속하면 고정 아이피를 할당할 수 있는 장소가 등장합니다.

아수스 공유기의 경우, 다음과 같이 접속해 DHCP 리스트에서 수동으로 ... 에서 등록하면 됩니다.

접속이 끝났다면 아래와 같이 ifconfig를 실행하여 inet 주소가 192.168.* 까지 동일한 지 확인합니다.

jong@jim:~$ ifconfig
enp2s0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 192.168.1.11  netmask 255.255.255.0  broadcast 192.168.1.255
        ... 생략

처음 이 명령어를 수행하는 경우, net-tools 패키지가 없다는 에러를 만날 수 있습니다. 그럴때는 'sudo apt-get install net-tools'를 실행하여 해당 패키지를 설치해줍니다.

 

반드시 할 필요는 없지만, 저는 편의상 위 inet 주소를 도메인 이름으로 변경합니다. 예를 들어 172.217.25.100 가 www.google.com 인 것처럼 말이죠.

jong@jim:~$ vim /etc/hosts

파일에서 아래처럼 jim, oim, dim 줄을 추가합니다.

127.0.0.1       localhost
192.168.1.11    jim
192.168.1.132   oim
192.168.1.6     dim
(:wq 누르고 엔터 입력으로 저장 후 나가기)

이제 192.168.1.132 를 치는 것 대신 oim 을 사용할 수 있습니다.

 


3. SSH 접속 시 로그인이 필요없도록 한다.

SSH(Secure SHell) 은 원격 접속 시스템입니다. 하둡이 데이터를 공유할 때, 기본적으로 SSH를 사용합니다.
해당 포스팅은 빠르게 완전 분산 모드를 구현하는 것이므로, 보안 과정은 생략하고 ssh 공유 키를 교환함으로 추가 인증없이 원격 접속할 수 있는 환경을 만들겠습니다.

 

먼저 다음 명령어를 3개 장치 모두 수행하여 각 컴퓨터에서 ssh 비대칭 키 두 개를 생성해야 합니다.

jong@jim:~$ ssh-keygen -t rsa
(계속 엔터 누르기)
park@oim:~$ ssh-keygen -t rsa
(계속 엔터 누르기)
denny@dim:~$ ssh-keygen -t rsa
(계속 엔터 누르기)

각 컴퓨터의 홈 디렉토리에서 .ssh 디렉토리를 방문하면, id_rsa 파일과 id_rsa.pub 파일을 볼 수 있습니다. 헷갈리지 않기 위해 각자 컴퓨터에서, id_rsa.pub 파일의 이름을 본인의 컴퓨터 이름으로 바꾸어봅니다.

jong@jim:~$ cd ~/.ssh
jong@jim:~$ mv id_rsa.pub jim_rsa.pub
(oim과 dim도 앞에 이름만 바꿔서 동일하게 수행)

 

이제 .pub 파일을 서로 공유하면 됩니다. 아래는 간단한 이유입니다.

 

해당 방식에 대해 조금 더 자세한 설명은 여기를 참조해주세요.
키 교환을 쉽게하기 위해 scp 명령어를 사용했습니다.

jong@jim:~$ scp ~/.ssh/jim_rsa.pub park@oim:/home/park/.ssh
(비밀번호를 입력하세요.)
jong@jim:~$ ssh park@oim
(비밀번호를 입력하세요.)
park@oim:~$ cat ~/.ssh/jim_rsa.pub >> authorized_keys
park@oim:~$ logout
jong@jim:~$ ssh park@oim
(비밀번호 없이 바로 접속되는 지 확인)
park@oim:~$

위 과정을 jong -> denny도 진행하고, park과 denny 모두 동일하게 공유합니다. (총 공유 횟수는 6번이겠네요)

모든 사용자가 어떤 컴퓨터라도 접속할 수 있다면 성공입니다!

denny@dim:~$ ssh jong@jim
jong@jim:~$ ssh park@oim
park@oim:~$ ssh denny@dim

 


4. 자바를 설치한다. (1.8.0_2xx version)

여기를 눌러 리눅스 버전의 자바를 다운로드 합니다. (사실 최근에 접속해보니 1.8.0_271 버전이 있었는데, 어차피 1.8.0_2xx 버전이 필요하므로 앞 버전이 맞다면 그냥 설치해줘도 무방할 것 같아요.)

 

그리고 아래 명령어를 통해 설치합니다.

rpm -ivh 다운로드한 파일.rpm

자바는 모든 컴퓨터가 설치되어 있어야 하므로 다른 컴퓨터도 반복해서 수행해주세요.

 


5. 하둡을 설치한다. (3.3.0 version)

여기를 눌러 타르볼 파일을 다운로드 합니다.

 

설치 경로는 /usr/local/ 입니다. 마스터(master)가 될 컴퓨터만 아래 과정을 정확히 따라해주세요.

(실수하지 않기를 바래요.)

denny@dim:~$ cd Downloads/
denny@dim:~/Downloads$ tar -xf hadoop-3.3.0.tar.gz
denny@dim:~/Downloads$ sudo mv hadoop-3.3.0/ /usr/local/hadoop
denny@dim:~/Downloads$ sudo chown -R denny:denny /usr/local/hadoop
denny@dim:~/Downloads$ ls /usr/local/hadoop
(bin, share 등 디렉토리가 있는지 확인한다.)

 

 


6. 환경 변수를 설정한다.

새로운 터미널 창을 열고 ~/.bashrc 에 환경 변수들을 등록하도록 합니다.

denny@dim:~$ gedit ~/.bashrc
... 생략, 최하단에 아래 내용을 작성한다.
# JAVA #
export JAVA_HOME=/usr/lib/jvm/java-8-oracle
export PATH=$PATH:$JAVA_HOME:$JAVA_HOME/bin

# HADOOP #
export HADOOP_HOME=/usr/local/hadoop
export HADOOP_MAPRED_HOME=$HADOOP_HOME
export HADOOP_COMMON_HOME=$HADOOP_HOME
export HADOOP_HDFS_HOME=$HADOOP_HOME
export YARN_HOME=$HADOOP_HOME
export PATH=$PATH:$HADOOP_HOME/bin:$HADOOP_HOME/sbin:$HADOOP_HOME

 

ctrl+s 를 눌러 저장한 뒤, 종료하고 아래 명령어를 통해 자바 버전을 확인합니다. (저는 옛날에 미리 설치해서 231이 뜹니다.) 만약 버전 정보가 출력된다면 정상입니다.

denny@dim:~$ source ~/.bashrc
denny@dim:~$ java -version
java version "1.8.0_231"
Java(TM) SE Runtime Environment (build 1.8.0_231-b11)
Java HotSpot(TM) 64-Bit Server VM (build 25.231-b11, mixed mode)

위 과정을 모든 컴퓨터에 동일하게 진행해주세요.

 


7. 하둡을 설정한다.

이제 거의 다 왔어요.

여기서부터는 정말 주의깊게 따라해야 합니다.

시작하기 전, 발생할 오류 해결에 대해 팁을 알려드리면 하둡 홈 디렉토리에 있는 logs 디렉토리에서 로그 정보를 확인하세요.

하둡을 설정하는 건 크게 마스터와 세컨더리로 나뉩니다. 그리고 각 컴퓨터는 core-site.xml, hdfs-site.xml, mapred-site.xml, yarn-site.xml 설정 파일을 수정하게 될 것입니다.

 

그 전에 먼저, 필수 디렉토리 경로를 만들겠습니다.

 

지금부터 작성하는 것은 '모든 컴퓨터'에서 동일하게 수행되어야 합니다.

먼저 임시 파일 저장소와 데이터노드와 네임노드가 저장될 경로를 만듭니다.

$ mkdir /tmp/hdfs
$ sudo mkdir /hdfs
(비밀번호를 입력하세요)
$ sudo chown 사용자이름:사용자이름 /hdfs
$ mkdir /hdfs/namenode
$ mkdir /hdfs/datanode

다음 호스트 이름과 worker를 등록합니다.

$ mkdir /usr/local/hadoop/pids/
$ vim /usr/local/hadoop/pids/dfs.hosts
denny@dim
park@oim
jong@jim
(:wq 누르고 엔터 입력으로 저장 후 나가기)
$ vim /usr/local/hadoop/etc/hadoop/workers
denny@dim
park@oim
jong@jim
(:wq 누르고 엔터 입력으로 저장 후 나가기)

 

지금부터 작성하는 것은 '마스터'에서 수행되어야 합니다.

우선 마스터가 dim 이므로, dim의 /usr/local/hadoop/etc/hadoop 에 방문합니다.

그리고 아래처럼 설정 파일을 수정합니다.

core-site.xml

<configuration>
  <property>
    <name>fs.defaultFS</name>
    <value>hdfs://192.168.1.6:9000</value>
    <description>마스터의 ip 주소 및 9000 포트를 입력합니다.</description>
  </property>
  <property>
    <name>io.file.buffer.size</name>
    <value>204800</value>
  </property>
  <property>
    <name>hadoop.tmp.data</name>
    <value>/tmp/hdfs</value>
  </property>
</configuration>

hdfs-site.xml

<configuration>
  <property>
    <name>dfs.replication</name>
    <value>2</value>
  </property>

  <property>
    <name>dfs.http.address</name>
    <value>dim:50070</value>
  </property>
  <property>
    <name>dfs.namenode.secondary.http-address</name>
    <value>dim:50090</value>
  </property>

  <property>
    <name>dfs.blocksize</name>
    <value>268435456</value>
  </property>
  <property>
    <name>dfs.namenode.handler.count</name>
    <value>100</value>
  </property>
  <property>
    <name>dfs.hosts</name>
    <value>/usr/local/hadoop/pids/dfs.hosts</value>
  </property>
  <property>
    <name>dfs.namenode.name.dir</name>
    <value>/hdfs/namenode</value>
  </property>
  <property>
    <name>dfs.datanode.data.dir</name>
    <value>/hdfs/datanode</value>
  </property>
  <property>
    <name>dfs.webhdfs.enabled</name>
    <value>true</value>
  </property>
</configuration>

mapred-site.xml

<configuration>
  <property>
    <name>mapred.job.tracker</name>
    <value>dim:9001</value>
  </property>
  <property>
    <name>yarn.app.mapreduce.am.resource.mb</name>
    <value>1024</value>
  </property>

  <property>
      <name>mapreduce.map.memory.mb</name>
      <value>512</value>
  </property>

  <property>
      <name>mapreduce.reduce.memory.mb</name>
      <value>2048</value>
  </property>

  <property>
    <name>mapreduce.reduce.java.opts</name>
    <value>-Xmx1536m</value>
  </property>
</configuration>

yarn-site.xml

<configuration>
  <property>
    <name>yarn.acl.enable</name>
    <value>0</value>
  </property>
  <property>
    <name>yarn.resourcemanager.address</name>
    <value>0.0.0.0:8032</value>
  </property>
  <property>
    <name>yarn.resourcemanager.scheduler.address</name>
    <value>0.0.0.0:8030</value>
  </property>
  <property>
    <name>yarn.resourcemanager.hostname</name>
    <value>0.0.0.0</value>
  </property>
  <property>
    <name>yarn.nodemanager.aux-services</name>
    <value>mapreduce_shuffle</value>
  </property>
  <property>
    <name>yarn.nodemanager.resource.memory-mb</name>
    <value>8192</value>
  </property>

  <property>
      <name>yarn.scheduler.maximum-allocation-mb</name>
      <value>40960</value>
  </property>

  <property>
      <name>yarn.scheduler.minimum-allocation-mb</name>
      <value>256</value>
  </property>

  <property>
      <name>yarn.nodemanager.vmem-check-enabled</name>
      <value>false</value>
  </property>
</configuration>

 

작성이 끝났으면, 본인 컴퓨터 사양에 맞춰서 메모리 값을 변경해야 됩니다.

일단 파라미터 설명은 추후 작성될 포스팅에서 진행하도록 하고, 위 설정값은 8코어 CPU에 8GB 메모리를 할당하기 위해서 정했으므로 지금은 단지 8코어와 8GB에 비례해서 임의로 값을 넣어주세요.

 

 

그리고 아직 세컨더리가 남았어요

scp 명령어를 이용해 dim으로부터 oim, jim에게 hadoop 디렉토리를 통째로 건네줍니다.

denny@dim:~$ scp -r /usr/local/hadoop park@oim:/usr/local/
(다 진행될 때까지 기다림)
denny@dim:~$ scp -r /usr/local/hadoop jong@jim:/usr/local/
(다 진행될 때까지 기다림)

 

그리고 두 세컨더리들 내 하둡 디렉토리를 방문해서 hdfs-site.xml와 yarn-site.xml에서 필요없는 파라미터를 지우고, yarn-site. xml와 mapred-site.xml 내 메모리 할당값을 변경하여야 합니다.

hdfs-site.xml

<configuration>
    <property>
        <name>dfs.replication</name>
        <value>2</value>
    </property>
    <property>
        <name>dfs.namenode.name.dir</name>
        <value>/hdfs/namenode</value>
    </property>
    <property>
        <name>dfs.datanode.data.dir</name>
        <value>/hdfs/datanode</value>
    </property>    
     <property>
        <name>dfs.datanode.max.xcievers</name>
        <value>4096</value>
      </property>
    <property>
        <name>dfs.namenode.secondary.http-address</name>
        <value>dim:50090</value>
    </property>
    <property>
        <name>dfs.webhdfs.enabled</name>
        <value>true</value>
      </property>
</configuration>

yarn-site.xml

<configuration>
  <property>
    <name>yarn.acl.enable</name>
    <value>0</value>
  </property>
  <property>
    <name>yarn.resourcemanager.hostname</name>
    <value>dim</value>
  </property>
  <property>
    <name>yarn.nodemanager.aux-services</name>
    <value>mapreduce_shuffle</value>
  </property>
  <property>
    <name>yarn.nodemanager.resource.memory-mb</name>
    <value>2048</value>
  </property>
  <property>
      <name>yarn.scheduler.maximum-allocation-mb</name>
      <value>2048</value>
  </property>
  <property>
      <name>yarn.scheduler.minimum-allocation-mb</name>
      <value>128</value>
  </property>
  <property>
      <name>yarn.nodemanager.vmem-check-enabled</name>
      <value>false</value>
  </property>
</configuration>

그리고 yarn-site.xml와 mapred-site.xml를 방문하여 메모리 할당값을 알맞게 변경해주세요.

이제, 하둡 설치가 끝났습니다. 실행해볼게요.



8. 실행한다.

먼저 HDFS 부터 실행해보겠습니다. 터미널을 새롭게 열고 아래 명령어를 마스터에서 작성해주세요.

denny@dim:~$ start-dfs.sh
Starting namenodes on [dim]
Starting datanodes
Starting secondary namenodes [dim]
denny@dim:~$ jps
(DataNode, NameNode, SecondaryNamenode가 있는 지 확인한다.) 

만일 jps를 실행하고 4개가 출력되지 않았다면, 상기 과정을 다시 한번 확인해보시고 재실행하세요.

 

그 다음 yarn을 실행하겠습니다.

denny@dim:~$ start-yarn.sh
Starting resourcemanager
Starting nodemanagers
denny@dim:~$ jps
(DataNode, NameNode, SecondaryNamenode와 더불어 NodeManager, ResoureManager가 있는 지 확인한다.)

만일 jps를 실행하고 6개가 출력되지 않았다면, 상기 과정을 다시 한번 확인해보시고 재실행하세요.

 

그러나 jps 포함 6개가 정상적으로 출력되었다면 이제 여러분은 하둡 클러스터를 보유하고 계신 겁니다!

 

이제 간단하게 디렉토리를 만들고, 파일을 저장하고 다시 가져오는 예제를 수행해보겠습니다.

먼저, 하둡 파일시스템을 사용하기 위해서는 네임노드를 포맷하는 과정이 필요합니다.

$ hdfs namenode -format 

이후 하둡 파일시스템의 루트에 test 디렉토리를 생성해보겠습니다.

하둡은 CLI(Command Line Interface)를 지원합니다. hdfs dfs -h 를 실행하면 명령어 도움말이 출력됩니다.

$ hdfs dfs -mkdir /test
$ hdfs dfs -ls /
(test 디렉토리를 확인한다)

그리고 로컬 파일시스템에서 데이터를 전송하기 위해 임시로 hello.txt 파일을 생성하고 HDFS의 /test 디렉토리에 저장합니다. 그리고 로컬에 있는 hello.txt 파일을 제거하고 다시 HDFS로부터 해당 파일을 읽어옵니다.

$ echo "Hello world! 누구" > hello.txt
$ hdfs dfs -put hello.txt /test
$ rm hello.txt
$ hdfs dfs -get /text/hello.txt .
$ cat hello.txt
Hello world! 누구

'Hello world! 누구'를 보셨다면 설치가 다 끝났습니다!

 


끝내면서

여기까지 따라오시느라 고생 많으셨습니다.

 

물론 위 설치법은 2020년 12월 31일을 기점으로 되는 것을 확인해보았지만, 사실 부수적인 부분은 이미 구현이 되어 있기 때문에 처음 시작하는 사람이라면 오류를 적잖이 볼 수 있을지도 모르겠습니다.

지금 막 기술하지는 못하더라도, 제 머리 속에는 이러한 오류를 해결한 기억이 있으니 발생하는 모든 문제에 대해 로그를 분석했음에도 해결책을 찾기 어렵다면 댓글을 달아주세요.

 

 

그리고 사실 물 흐르듯 지나쳤지만 YARN은 매우 중요한 요소입니다.

설치가 끝나고 더욱 더 많은 내용을 알려드려야 하지만, YARN을 먼저 설명드리고 나머지를 설명하는 것이 더 유익할 것 같아 다음으로 미뤘습니다.

 

다음 포스팅에서는 하둡을 설치하면서 지나쳤던 YARN에 대해 집중 탐구해보는 시간을 갖겠습니다.

def next_chapter(current) :
	if current == "HDFS1" : 
		return "하둡 파일시스템을 직접 구현해보자"
	elif current == "HDFS2" :
		return "YARN은 무엇일까?"

 

 


Errors

 

1. JAVA_HOME을 찾지 못할 때

oim: ERROR: JAVA_HOME is not set and could not be found.

 

하둡 설치 경로/etc/hadoop/hadoop-env.sh 에 'export JAVA_HOME=자바 경로' 를 작성해주면 된다.

 

 

2. datanode process에 대한 priority를 설정하지 못할 때

coa@cim: ERROR: Cannot set priority of datanode process 2411

 

우선 마스터에서 dfs 프로세스를 종료해준다.

stop-dfs.sh

 

그리고 아래 명령어를 작성한다.

sudo chmod -R 777 /hdfs
sudo chmod -R 777 /tmp/hdfs
하둡 설치 경로/bin/hdfs namenode -format

 

 

까지만 하면 될 줄 알았는데, 여전히 문제가 발생한다면... 하둡 설치 경로/logs/에 방문하여 datanode 관련 log 파일을 확인해야 한다.

필자의 경우는 

WARN org.apache.hadoop.hdfs.server.common.Storage: Failed to add storage directory [DISK]file:/hdfs/datanode
java.io.IOException: Incompatible clusterIDs in /hdfs/datanode: namenode clusterID = CID-c0105003-671f-4de6-81b0-6a85374086aa; datanode clusterID = CID-1b234e31-d1b4-42f5-820f-b2a4b5a639c1

였는데, 실제 비교해보니 clusterID가 서로 달랐다.

$ cat /hdfs/namenode/current/VERSION 
...
namespaceID=719294450
clusterID=CID-c0105003-671f-4de6-81b0-6a85374086aa
cTime=1659020319198
...
$ cat /hdfs/datanode/current/VERSION
...
storageID=DS-465bd48e-58f2-4cb4-9f2f-667d37693e2c
clusterID=CID-1b234e31-d1b4-42f5-820f-b2a4b5a639c1
cTime=0
...

동일하게 맞춰줘도 되지만, 귀찮다면 그냥 current 디렉터리를 삭제하고 다시 hdfs namenode -format 명령어를 실행해도 된다.

 

 

간혹 그래도 여전히 문제가 발생한다면... 각 세컨더리들의 /hdfs 접근 권한을 한 번 확인해보면 좋다. ls -al /hdfs 로 보았을 때 만일 소유자와 그룹이 모두 root라면, 

sudo chown -R 사용자명:그룹명 /hdfs

으로 바꿔준다.