7-5 하둡

1. 하둡이란?

하둡은 2006년 야후의 더그 커팅이 '넛치'라는 검색엔진을 개발하는 과정에서
대용량의 비정형 데이터를 기존의 RDB 기술로는 처리가 힘들다는 것을 깨닫고,
새로운 기술을 찾는 중 구글에서 발표한 GFS와 MapReduce 관련 논문을 참고하여 개발하였습니다.
이후 아파치 재단의 오픈 소스로 공개 되었습니다.

하둡은 하나의 성능 좋은 컴퓨터를 이용하여 데이터를 처리하는 대신
적당한 성능의 범용 컴퓨터 여러 대를 클러스터화하고, 큰 크기의 데이터를 클러스터에서 병렬로 동시에 처리하여
처리 속도를 높이는 것을 목적으로 하는 분산처리를 위한 오픈소스 프레임워크라고 할 수 있습니다.

2. 하둡의 구성 요소

1) Hadoop Common
하둡의 다른 모듈을 지원하기 위한 공통 컴포넌트 모듈

2) Hadoop HDFS
분산저장을 처리하기 위한 모듈
여러개의 서버를 하나의 서버처럼 묶어서 데이터를 저장
파일을 저장하는 방식
데이터가 어느정도 쌓이면 저장
실시간처리보다는 배치처리를 위해 설계

3) Hadoop YARN
병렬처리를 위한 클러스터 자원관리 및 스케줄링 담당

4) Hadoop Mapreduce
분산되어 저장된 데이터를 병렬 처리할 수 있게 해주는 분산 처리 모듈

3. 하둡의 장단점

장점
오픈소스로 라이선스에 대한 비용 부담이 적음
시스템을 중단하지 않고, 장비의 추가가 용이(Scale Out)
일부 장비에 장애가 발생하더라도 전체 시스템 사용성에 영향이 적음(Fault tolerance)
저렴한 구축 비용과 비용대비 빠른 데이터 처리
오프라인 배치 프로세싱에 최적화

단점
HDFS에 저장된 데이터를 변경 불가
실시간 데이터 분석 같이 신속하게 처리해야 하는 작업에는 부적합
너무 많은 버전과 부실한 서포트
설정의 어려움

4. 하둡 진화 과정

1) 하둡 v1
분산저장, 병렬처리 프레임워크를 정의

분산저장(HDFS)
네임노드, 데이터 노드가 처리
병렬처리(MapReduce)
잡트래커, 태스트 트래커가 처리
클러스터당 최대 4000개의 노드를 등록
작업 처리를 슬롯(slot) 단위로 처리
맵, 리듀스 슬롯을 구분하여 처리

2) 하둡 v2
2012년 정식 발표된 하둡 v2는 v1의 잡트래커의 병목현상을 제거하기 위하여 YARN 아키텍처를 도입

클러스터 관리
리소스 매니저, 노드 매니저
작업 관리
애플리케이션 마스터, 컨테이너
MR 외 Spark, Hive, Pig 등 다른 분산 처리 모델도 수행 가능
클러스터당 1만개 이상의 노드 등록 가능
작업 처리를 컨테이너(container) 단위로 처리

3) 하둡 v3
이레이져 코딩 도입
기존의 블록 복제(Replication)를 대체하는 방식으로 HDFS 사용량 감소
YARN 타임라인 서비스 v2 도입
기존 타임라인 서비스보다 많은 정보를 확인 가능
스크립트 재작성및 이해하기 쉬운 형태로 수정
오래된 스크립트를 재작성하여 버그 수정
JAVA8 지원
네이티브 코드 최적화
고가용성을 위해 2개 이상의 네임노드 지원
하나만 추가할 수 있었던 스탠바이 노드를 여러개 지원가능 스탠바이 노드
Ozone 추가
오브젝트 저장소 추가

5. HDFS

HDFS(Hadoop Distributed File System)는 비싼 하드디스크가 아닌 일반적인 하드디스크에서
장애 복구성을 가지는 분산 파일 시스템을 목표로 합니다.

HDFS는 실시간 처리보다는 배치처리를 위해 설계되었습니다.
따라서 빠른 데이터 응답시간이 필요한 작업에는 적합하지 않습니다.
또한 네임노드가 단일 실패 지점(SPOF)이 되기 때문에 네임노드 관리가 중요합니다.

1) 특징
(1) 블록 단위 저장
HDFS는 데이터를 블록 단위로 나누어서 저장합니다.
블록사이즈보다 작은 파일은 기존 파일의 사이즈로 저장하고, 블록 사이즈보다 큰 크기의
데이터파일은 블록단위 나누어 저장하기 때문에 단일 디스크의 데이터보다 큰 파일도 저장할 수 있습니다.
블록단위가 256MB일 때 1G파일은 4개의 블록으로 나누어 저장되고, 10MB파일은 하나의 블록으로 저장됩니다.

(2) 블록 복제를 이용한 장애 복구
HDFS는 장애 복구를 위해서 각 블록을 복제하여 저장합니다.
블록의 기본 복제 단위는 3입니다. 하나의 블록은 3개의 블록으로 복제되고,
같은 랙(Rack)의 서버와 다른 랙(Rack)의 서버로 복제되어 저장됩니다.
블록에 문제가 생기면 복제한 다른 블록을 이용해서 데이터를 복구 합니다.

1G데이터를 저장할 때 데이터가 복제되어 3G의 저장공간이 필요합니다.

(3) 읽기 중심
HDFS는 데이터를 한 번 쓰면 여러 번 읽는 것을 목적으로 합니다. 따라서 파일의 수정은 지원하지 않습니다.
파일의 수정을 제한하여 동작을 단순화하고 이를 통해 데이터를 읽을 때 속도를 높일 수 있습니다.

(4) 데이터 지역성
맵리듀스는 HDFS의 데이터 지역성을 이용해서 처리 속도를 증가시킵니다.
처리 알고리즘이 있는 곳에 데이터를 이동시키지 않고,
데이터가 있는 곳에서 알고리즘을 처리하여 네트워크를 통해 대용량 데이터를 이동시키는 비용을 줄일 수 있습니다.

2) 구조
HDFS는 마스터 슬레이브 구조로 하나의 네임노드와 여러 개의 데이터노드로 구성됩니다.
네임노드는 메타데이터를 가지고 있고, 데이터는 블록 단위로 나누어 데이터노드에 저장됩니다.
사용자는 네임노드를 이용해 데이터를 쓰고, 읽을 수 있습니다.

(1) 네임노드
메타데이터 관리와 데이터노드를 관리

메타데이터는 파일이름, 파일크기, 파일생성시간, 파일접근권한, 파일 소유자 및 그룹 소유자, 파일이 위치한 블록의 정보 등으로 구성됩니다. 
각 데이터노드에서 전달하는 메타데이터를 받아서 전체 노드의 메타데이터 정보와 파일 정보를 묶어서 관리합니다.
메타데이터는 사용자가 설정한 위치(dfs.name.name.dir)에 보관됩니다. 
네임노드가 실행 될 때 파일을 읽어서 메모리에 보관합니다. 
운영중에 발생한 수정사항은 네임노드의 메모리에는 바로 적용되고, 데이터의 수정사항을 다음 구동시 적용을 위해서 주기적으로 Edist 파일로 저장합니다.


메타데이터 파일 종류
Fsimage 파일
	네임스페이스와 블록 정보
Edits 파일
	파일의 생성, 삭제에 대한 트랜잭션 로그
	메모리에 저장하다가 주기적으로 생성

(2) 데이터 노드
데이타노드는 파일을 저장하는 역할
파일은 블록단위로 저장됩니다. 데이타노드는 주기적으로 네임노드에 하트비트와 블록리포트를 전달합니다. 
하트비트는 데이타노드의 동작여부를 판단하는데 이용됩니다. 
네임노드는 하트비트가 전달되지 않는 데이터노드는 동작하지 않는 것으로 판단하여 더이상 데이터를 저장하지 않도록 설정합니다. 
블록리포트로 블록의 변경사항을 체크하고, 네임노드의 메타데이터를 갱신합니다.

블록 파일 저장형태
	사용자가 설정한 위치(dfs.data.dir)에 저장됩니다.

  [1] 데이터 노드 상태
    ㄱ. 활성상태
	활성 상태는 데이터노드가 Live 상태인지 Dead 상태인지를 나타냅니다. 
	데이터노드가 하트비트를 주기적으로 전달하여 살아 있는지 확인되면 Live 상태입니다. 
	데이터노드에 문제가 발생하여 지정한 시간동안(dfs.namenode.stale.datanode.interval)하트비트를 받지 못하면 
	네임노드는 데이터노드의 상태를 Stale 상태로 변경합니다. 이후 지정한 시간동안 응답이 없으면 Dead 노드로 변경합니다.


	ㄴ. 운영 상태
	운영 상태는 데이터노드의 업그레이드, 패치 같은 작업을 하기 위해 서비스를 잠시 멈추어야 할 경우 블록을 안전하게 보관하기 위해 설정하는 상태
	NORMAL: 서비스 상태
	DECOMMISSIONED: 서비스 중단 상태
	DECOMMISSION_INPROGRESS: 서비스 중단 상태로 진행 중
	IN_MAINTENANCE: 정비 상태
	ENTERING_MAINTENANCE: 정비 상태로 진행 중
	


  [2] 파일 읽기/쓰기
  HDFS의 파일에 접근하는 가장 간단한 방법은 HDFS 명령행 인터페이스를 이용하는 것입니다. 	
  또한 Java, C API를 제공하여 이를 구현해서 접근하면 됩니다.


	ㄱ. 파일 읽기
	네임노드에 파일이 보관된 블록 위치 요청
	네임노드가 블록 위치 반환
	각 데이터 노드에 파일 블록을 요청
	노드의 블록이 깨져 있으면 네임노드에 이를 통지하고 다른 블록 확인


	ㄴ. 파일 쓰기
	네임노드에 파일 정보를 전송하고, 파일의 블록을 써야할 노드 목록 요청
	네임노드가 파일을 저장할 목록 반환
	데이터 노드에 파일 쓰기 요청
	데이터 노드간 복제가 진행

3) 명령어
https://hadoop.apache.org/docs/r3.2.2/hadoop-project-dist/hadoop-common/FileSystemShell.html

(1) 사용자
hdfs dfs -[서브명령어]	or	hadoop fs -[서브명령어]
자주 사용하는 서브 명령어
	ls		안에 내용물 확인
	rm -r	삭제
	mkdir	디렉토리만들기
	cat		내용물보기
	mv		이동
	cp		복사
	du 		hdfs내부의 특정 file이나 디렉토리의 사이즈를 보여줌
	du -s : 각각의 파일의 size의 sum값을 보여줌
	-stat %b  용량을 바이트 단위로 본다
	-stat %o  차지한 블록사이즈 보기(실제 용량과 블록사이즈는 다를 수 있음)
	-stat %r  복사본이 몇개있나 확인
	copyFromLocal 로컬에서 하둡으로 업로드
	copyToLocal 하둡에서 로컬로
	hdfs dfs -get /user/data1.txt ./                      # 파일을 로컬에 복사
	hdfs dfs -get -f /user/data1.txt ./                   # 파일을 로컬에 복사, 동일한 파일이 있으면 덮어 씀.

	hdfs dfs -put ./data1.txt /user/                      # 로컬 파일을 hdfs에 복사
	hdfs dfs -put -f ./data1.txt /user/                   # 로컬 파일을 hdfs에 복사, 동일한 파일이 있으면 덮어 씀.
    

(2) 관리자

[1] Rack Awareness
블록을 저장할 때 2개의 블록은 같은 랙에, 나머지 하나는 다른랙에 저장하도록 구성

[2] HDFS 세이프모드
데이터의 저장 및 삭제가 불가능한 상태, 읽기 전용 상태
네임노드에 문제가 생겨서 정삭적인 동작을 할 수 없을 때 자동으로 세이프 모드로 전황

관리자가 설정할 수도 있고 복구할 수도 있음

[3] 커럽트 블록
HDFS는 하트비트를 통해 전달받은 리포트로 자동으로 복구하지만 모든 복제 블록에 문제가 생겨 복구하지 못하게되면 커럽트 상태가 됨, 파일 복구 불가
hadoop fsck 명령으로 확인 가능

[4] 휴지통
HDFS는 삭제 시 바로 영구적으로 삭제하지 않고 휴지통 기능을 이용할 수 있음

[5] 이용량 제한 설정
특정 디렉토리의 용량 제한을 설정할 수 있음

[6] 밸런스
서로 다른 사양의 컴퓨터로 데이터 노드들을 구성하면
한 쪽에는 용량이 남고 한 쪽에는 용량이 부족한 일이 발생할 수 있음
이 때 밸런스를 조절해서 사용

6. 하둡에 데이터 옮기는 명령어

@@먼저 패스설정을 해야함

PATH=$PATH:/opt/hadoop-3.2.2/bin
그후 hdfs dfs 를 붙이면 mkdir ls rm 될거임

hdfs dfs -mkdir /dir
hdfs dfs -ls /
@@-ls / 한칸띄고 /임
hdfs dfs -put [저장할파일] /[저장할경로]/
hdfs dfs -ls /dir 저장확인

워커에서는
/data/hdfs/datanode 또는

cd /tmp/hadoop-hdfs/dfs/data/current/로 가면 저장된 데이터 확인가능

root@worker1:/tmp/hadoop-hdfs/dfs/data/current# ls
하면 내가 넣은 파일들이 분산되어서 보일거임

hdfs dfs -ls /dir2
내 우분투의 ip:9870 으로 들어가는 하둡 사이트에서 utilities를 누르면
directory가 뭐뭐 있는지 볼수느 있지만 잘 사용 x

7. 맵리듀스

구글에서 발표한 알고리즘
크게 맵핑하는 작업 리듀싱 하는 작업 두가지로 나뉨
맵핑 : 결과물을 모아서 집계
데이터를 가져와서 키와 값 하나의 쌍으로 묶는 작업
리듀스 : 줄여주는거
묶여진 데이터들을 다시 원하는 형태의 키와 값으로 재조립하는 작업

1) 작업 단위
하둡 v1의 작업 단위는 잡(job)이고, 하둡 v2의 작업 단위는 애플리케이션(application) 입니다.
YARN 아키텍처가 도입되면서 이름은 변경되었지만 동일하게 관리됩니다.

하둡 잡이 생성되면 아이디가 job_xxx_xxx 로 생성됩니다. 
이 아이디로 잡의 상태, 로그를 확인할 수 있습니다. YARN에서는 application_xxx_xxx 로 확인할 수 있습니다. 
접두어는 다르지만 같은 작업입니다.

잡에서 생성되는 맵태스크와 리듀스태스크는 아이디가 attempt_xxx_xxx_m_000000_0으로 생성됩니다. 
맵태스크는 중간아이디가 m으로 생성되고, 리듀스 태스크는 r로 생성됩니다.

2) 처리 단계

입력
	데이터를 입력하는 단계
	텍스트, csv, gzip 형태의 데이터를 읽어서 맵으로 전달

@@ 중요
맵(Map)
	입력을 분할하여 키별로 데이터를 처리

컴바이너(Combiner)
	네트워크를 타고 넘어가는 데이터를 줄이기 위하여 맵의 결과를 정리
	로컬 리듀서라고도 함
	컴바이너는 작업의 설정에 따라 없을 수도 있음

파티셔너(Partitoner)
	맵의 출력 결과 키 값을 해쉬 처리하여 어떤 리듀서로 넘길지를 결정
	셔플(Shuffle)
	각 리듀서로 데이터 이동

정렬(Sort)
	리듀서로 전달된 데이터를 키 값 기준으로 정렬
    @@ 정렬과 셔플은 둘 중 하나만 있어도 됨

@@ 중요 
리듀서(Reduce)
	리듀서로 데이터를 처리하고 결과를 저장

출력
	리듀서의 결과를 정의된 형태로 저장

3) YARN

하둡1에서는 잡트래커가 애플리케이션의 라이프 사이클 관리와 클러스터 리소스 관리를 모두 담당하여 병목 현상이 발생하였습니다.

잡트래커 한대가 클러스터의 모든 노드를 관리해야 하고, 모든 애플리케이션의 관리 하였기 때문에 
잡트래커에 많은 메모리를 할당 해야 했고, 최대 4000대의 노드까지 관리 할 수 있었습니다.

잡트래커는 슬롯 단위로 리소스를 관리하여 시스템의 전체 자원을 효율적으로 사용할 수 없었습니다. 
슬롯 단위 리소스 관리는 클러스터의 메모리, CPU 자원을 분할하여 슬롯단위로 구분합니다. 
예를 들면 100GB의 메모리를 가지는 클러스터를 1G로 구분하여 100개의 슬롯을 만들고, 60개의 맵 슬롯, 40개의 리듀서 슬롯으로 구분합니다. 
슬롯은 각각의 역활에 맞게 동작할 수 있습니다. 
따라서 맵 슬롯이 동작하는 동안 리듀서 슬롯은 대기하게 됩니다. 
맵 슬롯에 더 많은 일을 하게 되더라도 리듀서 슬롯은 대기하게 됩니다.


잡 트래커의 애플리케이션은 맵리듀스 작업만 처리할 수 있어서 유연성이 부족하였습니다. 
맵리듀스 API를 구현한 작업만 처리할 수 있었기 때문에 SQL 기반 작업의 처리나, 인메모리 기반의 작업의 처리에 어려움이 있었습니다.

이런 단점을 극복하기 위하여 YARN 아키텍처가 도입되었습니다.

(1) YARN 구성
YARN은 잡트래커의 기능을 분리하여 자원 관리는 리소스 매니저와 노드매니저가 담당
애플리케이션 라이프 사이클 관리 기능은 애플리케이션 마스터와 컨테이너가 담당하도록 하였습니다.


(2) YARN App
YARN에서는 맵리듀스로 구현된 프로그램 외에도 다양한 애플리케이션을 실행할 수 있습니다.
리듀스, 피그, 스톰, 스파크 등 하둡 에코시스템의 다양한 데이터 처리 기술을 이용할 수 있습니다.

4) 맵 리듀스 해보기 예제

텍스트 파일을 하둡에 보내놓기
ex) file1이라는 파일안에 아무거나 적어 놓고 하둡안에 dir2안에 보내기
hdfs dfs -put file1 /dir2

hadoop  jar  /opt/hadoop-3.2.2/share/hadoop/mapreduce/hadoop-mapreduce-examples-3.2.2.jar wordcount [HDFS에 있는 대본 파일]  /result
hadoop  jar  /opt/hadoop-3.2.2/share/hadoop/mapreduce/hadoop-mapreduce-examples-3.2.2.jar wordcount /dir2/file1  /result
dir2/file1의 wordcount를 한뒤 /result에 저장한다.


맨밑처럼 맵과 리듀스가 뜨면 성공


part-r-00000안에 데이터가 담김


cat으로 확인하면 사진처럼 글자마다 몇번 사용되었는지 세줌

hadoop fs -get /result/part-r-00000를 사용해서 로컬로 가져오면

로컬에서 -ls 명령어로 확인 가능

@ 하둡 wordcount 오류 해결법들
1) 민수님과 선민님의 경우 : 메모리부족
yarn-site.xml의


<configuration>
	<property>
		<name>yarn.nodemanager.aux-services</name>
		<value>mapreduce_shuffle</value>
	</property>
	<property>
		<name>yarn.resourcemanager.hostname</name>
		<value>master</value>
	</property>
	<property>
		<name>yarn.nodemanager.resource.memory-mb</name>
		<value>1024</value>   ----- 이부분의 메모리를 늘려준다.
	</property>
	<property>
		<name>yarn.nodemanager.resource.cpu-vcores</name>
		<value>1</value>
	</property>
	<property>
		<name>yarn.nodemanager.env-whitelist</name>        
		<value>JAVA_HOME,HADOOP_COMMON_HOME,HADOOP_HDFS_HOME,HADOOP_CONF_DIR,CLASSPATH_PREPEND_DISTCACHE,HADOOP_YARN_HOME,HADOOP_MAPRED_HOME</value>
	</property>
</configuration>

수정했으니 stop all.sh 하고 다시 스타트

2) PATH 설정오류
패스가 풀리거나 아예 설정이 바껴버린경우

PATH=$PATH:/opt/hadoop-3.2.2/bin

3) hadoop java.net.connectexception:연결이 거부됨

stop all.sh 하고 다시 스타트

4) 재리님의 경우 Hadoop: Connecting to ResourceManager failed

13/12/14 20:12:06 INFO client.RMProxy: Connecting to ResourceManager at /0.0.0.0:8032
13/12/14 20:12:06 INFO client.RMProxy: Connecting to ResourceManager at /0.0.0.0:8032
13/12/14 20:12:07 INFO ipc.Client: Retrying connect to server: 0.0.0.0/0.0.0.0:8032. Already tried 0 time(s); retry policy is RetryUpToMaximumCountWithFixedSleep(maxRetries=10, sleepTime=1 SECONDS)
13/12/14 20:12:08 INFO ipc.Client: Retrying connect to server: 0.0.0.0/0.0.0.0:8032. Already tried 1 time(s); retry policy is RetryUpToMaximumCountWithFixedSleep(maxRetries=10, sleepTime=1 SECONDS)
13/12/14 20:12:09 INFO ipc.Client: Retrying connect to server: 0.0.0.0/0.0.0.0:8032. Already tried 2 time(s); retry policy is RetryUpToMaximumCountWithFixedSleep(maxRetries=10, sleepTime=1 SECONDS)

hadoop jar hadoop-mapreduce-examples-2.2.0.jar wordcount someFile.txt /out
이 명령어 후에 jps로 확인하면 Resourcemanager가 사라짐

해결방법 : 우분투 자체의 메모리 용량을 늘려서 해결함

5) 파이썬 코드로 만들어보기
(1) mapper.py
#!/usr/bin/env python
import sys

for line in sys.stdin:
sys.stdin - 여러줄을 입력받는다.
words = line.strip().split()
words에 line.strip()을 통해 공백을 제거
words에 line.split()을 통해 공백을 기준으로 나눈다.
결국 공백을 기준으로 나누기때문에 단어단위로 나눠짐
for word in words:
print('{}\t{}'.format(word, 1))
단어와 1의 형태로 print해줌

(2) reducer.py
#!/usr/bin/env python
import sys

def print_output(word, count):
print('{}\t{}'.format(word, count))

word, count = None, 0

for line in sys.stdin:
fields = line.strip().split('\t')
split('\t') - 탭 간격을 기준으로 나눈다 아마 위에서 매핑한것이 탭으로 구분되는듯하다
if fields[0] != word:
if word is not None:
print_output(word, count)
word, count = fields[0], 0
count += 1

print_output(word, count)

좋은 웹페이지 즐겨찾기