ii. hadoop¹…데이터1031_6x9_9... · 그런데 이때 nutch 가 가져오는 방대한...

55
II. Hadoop 1. Hadoop 개요 (1) Hadoop배경 2002 미국의 프로그래머인 Doug Cutting Mike Cafarella Lucene 이라는 텍스트 검색엔진 개발 프로젝트를 진행하면서 Nutch 라는 하위 프로젝트를 통해 파서(Parser) 크롤러 (Crawler) 1 개발하고 있었다. 그런데 이때 Nutch 가져오는 방대한 데이터를 처리할 길이 없어 난감해 하던 차에 2004 Google 발간한 GFS 논문과 MapReduce 논문 2 보고 이를 기초로 프로그래밍에 들어갔다. 3~4 개월의 프로그래밍을 통해 HDFS 파일시스템을 만든 위에 Nutch 이식했으며 이후 실제 클러스터까지 구축하여 운영했다. 3 이후 2004 년부터 2008 년까지 추가의 개발이 진행되었다. 특히 2006 년에는 Yahoo 입사하고 Hadoop 오픈소스화 했는데 이후 상당히 많은 Yahoo 프로그래머들이 참여하면서 개발도 활발히 진척되었고 활용 면에서도 Yahoo 기간업무에서 핵심적 역할을 하게 되었다고 한다. 이후 프로그램의 안정화, 성능개선 등과 함께 Facebook 등에서도 적극 참여하였고 결국 2006 년부터는 Apache 프로젝트로 등재되어 세계의 많은 개발자가 참여하게 되었다. 재미있는 것은 Google 에서도 자신들의 MapReduce GFS 소스코드를 공개하지 않는 폐쇄형 (closed) 솔루션이었던 관계로 신입사원의 교육에서는 Hadoop MapReduce 대신 이용했다고 한다. 1 Parser 는 문장을 정해진 규칙(문법)에 의거해서 분석하는 것을 말한다. 이때 문법이란 언어상의 문법일 수도 있고 프로그래밍 언어상의 문법도 포함된다. 한편 크롤러(crawler)란 웹 페이지를 뒤져가며 방문해서 정보를 수집해오는 프로그램을 말한다. 2 http://research.google.com/archive/gfs.html http://research.google.com/archive/mapreduce.html 3 다만 비용상의 문제로 초기에는 4 대, 그리고 이후에는 약 30 대 까지만 확장되어 운영하였다고 한다.

Upload: lamdien

Post on 23-Apr-2018

223 views

Category:

Documents


6 download

TRANSCRIPT

Page 1: II. Hadoop¹…데이터1031_6x9_9... · 그런데 이때 Nutch 가 가져오는 방대한 데이터를 처리할 길이 없어 난감해 하던 차에 2004년 Google이 발간한

II. Hadoop

1. Hadoop 개요

(1) Hadoop의 배경

2002 년 미국의 프로그래머인 Doug Cutting 과 Mike Cafarella 은 Lucene 이라는 텍스트 검색엔진 개발

프로젝트를 진행하면서 Nutch 라는 하위 프로젝트를 통해 파서(Parser) 및 크롤러 (Crawler)1 를

개발하고 있었다. 그런데 이때 Nutch 가 가져오는 방대한 데이터를 처리할 길이 없어 난감해 하던 차에

2004 년 Google 이 발간한 GFS 논문과 MapReduce 논문2 을 보고 이를 기초로 프로그래밍에 들어갔다. 약

3~4 개월의 프로그래밍을 통해 HDFS 파일시스템을 만든 후 이 위에 Nutch 를 이식했으며 이후 실제

클러스터까지 구축하여 운영했다.3

이후 2004 년부터 2008 년까지 추가의 개발이 진행되었다. 특히 2006 년에는 Yahoo 에 입사하고

Hadoop 을 오픈소스화 했는데 이후 상당히 많은 Yahoo 의 프로그래머들이 참여하면서 개발도 활발히

진척되었고 활용 면에서도 Yahoo 의 기간업무에서 핵심적 역할을 하게 되었다고 한다. 이후 프로그램의

안정화, 성능개선 등과 함께 Facebook 등에서도 적극 참여하였고 결국 2006 년부터는 Apache 프로젝트로

등재되어 전 세계의 수 많은 개발자가 참여하게 되었다. 재미있는 것은 Google 에서도 자신들의

MapReduce 와 GFS 가 소스코드를 공개하지 않는 폐쇄형 (closed) 솔루션이었던 관계로 신입사원의

교육에서는 Hadoop 의 MapReduce 를 대신 이용했다고 한다.

1 Parser 는 문장을 정해진 규칙(문법)에 의거해서 분석하는 것을 말한다. 이때 문법이란 언어상의 문법일 수도 있고

프로그래밍 언어상의 문법도 포함된다. 한편 크롤러(crawler)란 웹 페이지를 뒤져가며 방문해서 정보를 수집해오는 프로그램을

말한다.

2 http://research.google.com/archive/gfs.html 과 http://research.google.com/archive/mapreduce.html

3 다만 비용상의 문제로 초기에는 4 대, 그리고 이후에는 약 30 대 까지만 확장되어 운영하였다고 한다.

Page 2: II. Hadoop¹…데이터1031_6x9_9... · 그런데 이때 Nutch 가 가져오는 방대한 데이터를 처리할 길이 없어 난감해 하던 차에 2004년 Google이 발간한

한편 흥미로운 것은 Google 은 당초 함수형 (functional) 프로그래밍 기법으로서의 Map & Reduce 에

대해 특허를 획득했었다는 점이다. 물론, 이에 대해 반론도 만만치 않아서 Google 이전에도 많은 학자와

프로그래머들 사이에 상당한 논의와 구현이 있었기 때문에 특허의 대상이 될 수 없다고 하는 논란이

많았었다. 이러한 논란 속에서 2010 년 최종적으로 특허를 획득한 후 3 개월만에 Google 은 Apache 에

대해 특허침해로 문제삼지 않겠다고 선언함으로써 모든 논의에 종지부를 찍었다. 이제 완벽한 오픈소스로서

세상사람에게 공개된 것이다.

Page 3: II. Hadoop¹…데이터1031_6x9_9... · 그런데 이때 Nutch 가 가져오는 방대한 데이터를 처리할 길이 없어 난감해 하던 차에 2004년 Google이 발간한

(2) Hadoop의 version

가. Hadoop의 라이선스

Apache 프로젝트로서의 Hadoop 은 Apache 라이선스 조건4을 따르므로 Linux 에서와 마찬가지로

다양한 판본(배포판)이 존재할 수 있다. (Linux 에 Red Hat, Ubuntu, Suse 등의 배포판이 존재하는 것과

마찬가지 논리) 게다가 Hadoop 과 연계되는 여러 종류의 프로젝트가 존재하기 때문에 이들 상호간의

조합에 따른 버전별 테스트 또한 만만치 않은 작업이다. 이에 따라 많은 회사에서 Hadoop 관련 배포판을

제공하고 있는데 대표적인 것이 Cloudera 와 Hortonworks 이다.5 Hadoop 은 일반적으로 RPM, tar, deb

등 다양한 형태의 설치파일이 제공되는데 배포판 별로 bundle 되는 도구는 다를 수 있고 이를 테스트 한 후

bundle 하므로 자신에 맞는 배포판을 고르는 것이 편리하다.

배포판 설명

Apache

http://hadoop.apache.org

Hadoop 의 원본 Source 역할을 하며 tar

ball 로만 패키징. 별다른 부가도구는 제공치

않음.

Cloudera

www.cloudera.com

선두주자 이며 Hadoop 클러스터 관리도구가

우수

오픈소스/상용 모델 병행 (클러스터 규모에

따름)

HortonWorks

www.hortonworks.com

Apache Hadoop 을 충실히 따름

각종 관리도구 제공. 오픈소스

MapR

www.mapr.com

(HDFS 대신) 자체의 파일시스템 제공

관리도구와 HA 기능 (미러링, snapshot, 기타)

WANdisco

www.wandisco.com

hadoop version 2 기반

관리도구. Free / Premium 모델 병행

Intel

http://hadoop.intel.com

Encryption 지원

4 Apache License 는 미국의 Apache 재단 (ASF: Apache Software Foundation)에서 자신들의 프로젝트를 대상으로

설정했던 공개소프트웨어 라이센스 조건이다. Apache License 에서는 해당 라이센스의 조건과 저작권만 명기하면 얼마든지

자유롭게 사용, 배포 및 수정이 가능하도록 하고 있다. (http://www.apache.org/licenses/ )

5 Cloudera 는 Hadoop 개발자인 Doug Cutting 이 CTO 로 있는 회사로서 마치 Linux 에서의 Red Hat 이 점하는 위치를

가져가려고 노력하고 있다. 한편 Yahoo 의 Hadoop 개발팀은 Hortonworks 의 핵심요원이 되었다.

Page 4: II. Hadoop¹…데이터1031_6x9_9... · 그런데 이때 Nutch 가 가져오는 방대한 데이터를 처리할 길이 없어 난감해 하던 차에 2004년 Google이 발간한

배포판 설명

성능개선 위해 하드웨어 가속 및 S/W stack

추가

나. Hadoop version의 경과

2006 년 Apache 프로젝트에 등재된 이래로 0.1 부터 0.14 까지 매달 새로운 버전이 발표 하였고

0.15 부터 0.20 까지는 분기별로 새 버전을 발표했다. 0.20 은 2009 년 발표하였다.

Hadoop-0.20 은 현재의 안정판의 근간이 되었는데 2011 년 12 월에 version 1.0.0 이 탄생하였다.

실제로 대부분의 배포판들이 이 버전에 의거하고 있다. (예: Apache Hadoop 0.20.x, CDH3.*, HDP1.*

등)

현재 시점(2013 년 8 월)을 중심으로 보면 1.2.1 의 안정버전과 2.x 버전의 베타버전이 진행 중이다.

0.21 – hadoop 1.0이 되었으며 2013.9월 현재 안정버전은 ver. 1.2.1

0.23 – Trunk에서 파생되어 Hadoop 2.0 이 됨.

Page 5: II. Hadoop¹…데이터1031_6x9_9... · 그런데 이때 Nutch 가 가져오는 방대한 데이터를 처리할 길이 없어 난감해 하던 차에 2004년 Google이 발간한

(3) 특징

가. 설계상의 특징

우리가 전혀 새롭게 빅데이터 처리를 위한 솔루션을 개발한다고 가정해보자. 아마도 다음의 몇 가지

요구사항이 제시될 것이다.

슈퍼컴퓨터 같은 비싼 서버 대신 저가 서버를 이용하자. 이들 서버를 수십 ~ 수백 ~ 수천대로 클러스터

구성하면기존의 슈퍼컴퓨터를 훨씬 적은 비용으로 대체할 수 있을 것이다.

대규모 클러스터를 구성할 경우 시스템 장애는 불가피하다. 따라서 장애극복을 위해 데이터를 여러 곳에

복제(replicate)하고 사용하자.

이렇게 복잡한 클러스터 환경에서는 기존의 분산컴퓨팅에서 요구되었던 시스템 상의 각종 관리기능

(marshalling)은 과감하게 생략하자. 그러면서도 외부에서는 이들 모두가 하나의 파일시스템 이미지로

보이도록 해야 한다.

복잡한 시스템 프로그램을 효율적으로 구현하기 위해서는 functional 프로그래밍 기법을 동원한다. 즉,

분산처리를 함수 중심의 프로그램 기법으로 구현하자.

대형파일이 많으므로 여러 파일로 나누어 처리하되 이들 각각 (split)의 블럭 크기는 가급적 크게 (수십

~수백 MB) 하는 것이 좋겠다.

속도를 개선하기 위해서는 write-once, read may, immutable 타입을 기준으로 하자.

대규모 작업을 위해서 node단위뿐만 아니라 rack단위 또는 스위치 단위로 확장할 수 있도록 한다.

바로 이러한 요구사항이 2000 년대 초의 Google 이 당면한 문제였었다. 그리고 이에 대한 해답이

Google 의 Map Reduce 이고 이를 구현하여 오픈소스화 한 것이 Hadoop 인 것이다.

Google 의 MapReduce 그리고 오픈소스 버전으로서의 Hadoop 은 설계사상에 있어 기존 방법론과 다른

뚜렷한 특징을 가진다.

프로그램 모델의 단순화

데이터 중심의 사고 (Moving Computation to Data)

우선 첫째 항목을 보자면 Hadoop 의 설계사상은 기존 방식에 비해 매우 단순하다. 기존의

병렬컴퓨팅에서는 대용량 데이터 처리를 분산환경에서 진행함에 따라 분산된 컴퓨터 내지 프로그램

(프로세스) 상호간의 통신과 제어 (특히 socket 통신 또는 marshalling6 등)이 중요했다. 그런데 이러한

상호제어는 또 다른 오버헤드가 되어 복잡성이 끝없이 증대되는 요인이 되었다. Hadoop 에서는 뒤에서 보는

6 marshalling 은 메모리 상의 객체를 스토리지에 저장 또는 네트워크 상에서 전송할 수 있도록 변환하는 것을 말한다. 흔히

여러 컴퓨터에서 원격의 객체 (remote object) (또는 데이터)를 전달할 때 사용된다. Marshalling 은 이처럼 프로세스 간 또는

thread 간에 서로 데이터를 주고 받고자 하지만 제공하는 remote procedure call (RPC)의 방식이 다를 때 주로 이용된다.

Page 6: II. Hadoop¹…데이터1031_6x9_9... · 그런데 이때 Nutch 가 가져오는 방대한 데이터를 처리할 길이 없어 난감해 하던 차에 2004년 Google이 발간한

바와 같이 가능한 모든 관리 커뮤니케이션을 과감하게 생략해서 각각의 컴퓨터 (이를 node 라고 한다)가

독립적으로 작업을 실시하도록 하였다.

Hadoop 의 둘째 특징은 컴퓨터로 하여금 자신과 가장 가까이 있는 데이터를 직접 처리하도록 하는 점이다.

일견 당연해 보이지만 우리가 과거 해오던 방식과는 정 반대임을 알 수 있다. 과거에는 데이터 분석작업 시

외곽에 있는 데이터를 중앙 컴퓨터로 가지고 와서 작업하였다. 즉, 데이터를 컴퓨터가 있는 곳으로 가져와서

작업했던 것이다.

반면 Hadoop 에서는 데이터를 중앙의 서버에 전달하여 처리하는 대신 데이터의 소스로부터 입력을 받는

즉시 다수 node 컴퓨터에게 일괄적으로 (무작위적으로) 배분시켜 주고 각각의 컴퓨터는 자신이 할당 받은

데이터에 대해 (앞서 말한 것처럼 중앙의 관리시스템의 간섭이나 다른 컴퓨터와의 통신이 없이) 독자적으로

지정된 임무를 수행하게 된다. 다음 그림은 이러한 과정을 잘 보여주고 있다.7

7 위 그림 및 HDFS, MapReduce 설명에서의 일부 그림은 Yahoo 에서의 Hadoop Tutorial 의 그림을 일부 인용하였다.

Yahoo 의 Hadoop tutorial (http://developer.yahoo.com/hadoop/tutorial/)은 Hadoop 의 원리를 상세하고 친절하게

소개하고 있다, 당초 Yahoo 는 Doug Cutting 을 영입한 뒤 별도의 전담팀을 두고 Hadoop Core 를 개발, 이용하였으며 이를

Apache Foundation 에 오픈소스로 공개한 바 있다.

Page 7: II. Hadoop¹…데이터1031_6x9_9... · 그런데 이때 Nutch 가 가져오는 방대한 데이터를 처리할 길이 없어 난감해 하던 차에 2004년 Google이 발간한

이처럼 단순성을 중시하면서도 데이터를 중심에 놓는 사고방식의 전환의 결과 Hadoop 은 거의 선형

(linear) 형태의 확장성을 가지게 되었다. 즉, 10 대로 하던 작업을 동일한 성능의 20 대 컴퓨터를 적용할 때

2 배의 성능향상을, 그리고 100 대의 컴퓨터를 적용하면 거의 10 배의 성능향상이 가능해진 것이다.

무엇보다 이때의 각각의 컴퓨터는 고가의 장비일 필요 없이 일반적인 중저가 서버로도 충분해져서 전체적인

총소유비용 (TCO: Total Cost of Ownership)이 획기적으로 절감되었다.

나. 사용상의 특징

Hadoop 은 대규모 데이터 처리용 응용 프로그램을 분산환경에서 수행시킬 수 있도록 해주는 오픈소스

프레임워크로서 다음과 같은 특징을 가진다.

손쉽게 적용이 가능하다 —독립적으로 환경구축 할 경우 아주 저가의 컴퓨터도 고성능 컴퓨팅 환경을 충

분히 이용 가능하며 클라우드 컴퓨팅 환경을 이용할 경우 한시적 이용 또는 점진적 증설도 가능하다.

안정적 운용이 가능하다 — 설계 자체가 저가 컴퓨터 활용을 염두에 두었고 장애를 극복하기 위한 장치

를 가능한 소프트웨어로 구현하였다. 즉, 기존 고가 슈퍼컴퓨터의 대체를 주된 목적의 하나로 삼으면서

미래 유연성 확보에 주력하였다.

확장성이 좋다 — 성능확장이 필요할 경우 수평적으로 기존 (저가) 컴퓨터를 추가시키면 그 대수만큼 성

능확장이 되도록 하였다. 현재 Hadoop기반으로 약 4만대의 서버를 연결한 클러스터가 일상적으로 운영

될 정도로 규모가 확장되었다.

Page 8: II. Hadoop¹…데이터1031_6x9_9... · 그런데 이때 Nutch 가 가져오는 방대한 데이터를 처리할 길이 없어 난감해 하던 차에 2004년 Google이 발간한

2. Hadoop의 아키텍처

(1) 개요

Hadoop 에서 실제 로직의 처리는 Map Reduce 방식으로 한다. 즉, 흐트러뜨려서 (분산하여) 처리한 후

각각의 결과만 다시 모으는 방식이다. 단, 이라한 처리과정은 모두 프레임워크에서 자동화한다.

Hadoop 은 빅데이터 처리를 위해 여러 대의 컴퓨터로 클러스터를 구성하는데 클러스터란 특정한

기능수행을 위해 여러 대의 컴퓨터가 네트워크로 연결한 것을 말한다. 이때 클러스터를 구성하는 개별

컴퓨터를 노드(node)라고 한다. (이하에서는 node 라 칭한다)

Hadoop 은 이처럼 물리적으로는 node 를 연결하고 그 위에서 다양한 소프트웨어 기법을 동원하여 거대한

프레임워크를 구축하였다. 이하에서 Hadoop 의 아키텍처를 다양한 측면에서 살펴 본다.

가. 사용자 차원

사용자 차원에서 분석가가 분석 모델링을 한 후 프로그래머에게 프로그램 작성을 요청한다. 프로그래머는

Hadoop 프레임워크에 맞추어 프로그램을 작성한 후 이를 실행한다. 한편 클러스터 환경에서의 데이터와

시스템의 관리는 컴퓨터 운영관리자가 담당한다. 분석가는 실제 분석작업을 진행하여 사업상의 중요한

정보를 찾아낸다. 복잡한 모델링이 필요치 않은 일상적 분석의 경우에는 Pig 및 Pig Latin 과 같은 Hadoop

내 하위 프로젝트에서 제공하는 간편한 질의어를 이용하는 것이 그림에 표현되어 있다.

나. 물리적 차원

Hadoop 클러스터는 한 대의 네임노드 (NameNode)서버와 여러 대의 데이터노드 (DataNode)서버로

구성된다.

Page 9: II. Hadoop¹…데이터1031_6x9_9... · 그런데 이때 Nutch 가 가져오는 방대한 데이터를 처리할 길이 없어 난감해 하던 차에 2004년 Google이 발간한

다. 논리적 차원

Hadoop 프레임워크는 여러 개의 데몬 (daemon) 프로그램으로 구성된다. 데몬 프로그램이란 서버의

메인메모리 상에서 백그라운드로8 수행되는 여러 가지 프로그램을 말한다. 이때 여러 개의 데몬 프로그램이

상호 동작하는 방식으로서 Hadoop 은 master-slave 의 형태를 취하는데 Master 란 작업수행을 지시 및

관리하고 Slave 는 Master 의 관리하에 실제 부여된 작업을 수행하는 것을 말한다.

라. 기능적 차원

Hadoop 은 핵심모듈(core module)과 관련 프로젝트로 구성된다.

HDFS (Hadoop Distributed Filesystem) – 파일시스템으로서 데이터를 저장하고 이를 Hadoop 프레

임워크에 입력하는 역할을 한다.

MapReduce – Hadoop의 대표적인 프로그래밍 모델이다. (뒤에서 자세히 설명한다.)

8 백그라운드 작업(background job) 이란 이용자의 특별한 작업 없이 배후에서 시스템이 자체적으로 수행하는 프로세스를

말한다.

Page 10: II. Hadoop¹…데이터1031_6x9_9... · 그런데 이때 Nutch 가 가져오는 방대한 데이터를 처리할 길이 없어 난감해 하던 차에 2004년 Google이 발간한

기타의 데몬 프로그램 – HDFS와 MapReduce를 보조하여 전체적인 운영효율을 높여주는 각종의 유틸

리티 소프트웨어이다.

결국 Hadoop 프레임워크는 주로 (데이터 관리 layer 로서의) HDFS 와 (프로그래밍 모델로서의)

MapReduce 의 2 가지로 구성되며 이들 (HDFS 와 MapReduce) 모두 각각 master 기능을 하는 데몬

프로그램과 slave 역할을 하는 데몬 프로그램으로 나뉘어진다. 즉, Hadoop 에서의 서버 노드에서는 각각

다음의 여러 가지 데몬 프로세스9를 수행한다.

NameNode (및 Secondary NameNode)

DataNode

JobTracker

TaskTracker

이중 NameNode 와 DataNode 는 HDFS 에 대한 기능을 하는 데몬 프로그램인 반면 JobTracker 와

TaskTracker 데몬 프로그램은 MapReduce 에 대한 기능을 하는 데몬이다.

9 프로세스란 프로그램이 수행되고 있는 상태를 말한다. 데몬 프로세스는 이 중에서 사용자가 별도의 수행명령을 내리는지

여부에 상관없이 (메인메모리에서) 항상 수행되면서 대기하고 있는 것을 말한다. 서비스 프로그램이라고도 한다.

Page 11: II. Hadoop¹…데이터1031_6x9_9... · 그런데 이때 Nutch 가 가져오는 방대한 데이터를 처리할 길이 없어 난감해 하던 차에 2004년 Google이 발간한

그리고 NameNode (및 Secondary NameNode)와 JobTracker 는 master node 에서만 수행되는 반면

JobTracker 와 TaskTracker 데몬 프로그램은 나머지 여러 대의 slave node 에서 수행되게 된다.

Master node

(서버)

Slave node

(서버)

클라이언트 PC

(작업자)

HDFS NameNode

(Secondary node 가

있을 수 있다)

DataNode Master node 에게

지시하고

진행상황을

출력한다. MapReduce JobTracker TaskTracker

달리 말하면 Hadoop 은 논리적 아키텍쳐 상에서 “저장을 위한 계층 (HDFS layer)”과 “실제 작업을 위한

계층 (Computation layer 즉, MapReduce layer)”의 2 개 레이어로 구성된다. 이들 각각에서는 해당되는

여러 데몬 프로그램이 수행되면서 사용자의 명령을 기다린다.

명령은 명령어 줄(command-line)을 이용할 수도 있으나 주로 데이터 흐름을 염두에 두고 필요한

알고리즘을 구현하는 프로그래밍 (Data Flow Programming)방식을 이용하는 것이 일반적이다.

(2) Hadoop의 처리 흐름도

Page 12: II. Hadoop¹…데이터1031_6x9_9... · 그런데 이때 Nutch 가 가져오는 방대한 데이터를 처리할 길이 없어 난감해 하던 차에 2004년 Google이 발간한

Hadoop 에서는 데이터가 그 중심 역할을 한다. 따라서 여기서는 데이터와 그 처리 흐름을 중심으로 살펴

본다.

MapReduce에서:

하나의 master node (JobTracker)가 여러 개의 작업 node (TaskTrackers)를 운용, 관리한다.

클라이언트 PC는 job을 JobTracker에게 submit한다

JobTracker는 각각의 job을 task별로 분할한다 (map/reduce)

필요에 따라 task를 TaskTrackers 에게 배분한다.

HDFS (Hadoop Distributed File System)에서

하나의 name node와 여러 개의 data node를 운용한다.

데이터는 고정길이(64 MB)의 블록으로 나누어서 처리한다

HDFS에서는 입력작업을 map 처리하고 그 출력작업을 reduce 한다.

Page 13: II. Hadoop¹…데이터1031_6x9_9... · 그런데 이때 Nutch 가 가져오는 방대한 데이터를 처리할 길이 없어 난감해 하던 차에 2004년 Google이 발간한

3. Hadoop의 기능요소 – HDFS와 MapReduce

(1) HDFS (Hadoop Distributed File System)

가. HDFS 설계원칙

앞서도 언급했지만 데이터를 많은 사용자가 네트워크 환경에서 이용하기 위해 개발된

분산파일시스템으로는 NFS (Network File System)가 대표적이다. 그러나 NFS 는 하나의 기기에 보관된

하나의 논리볼륨 (logical volume) 만을 원격에서 액세스한다는 제한점을 가진다. HDFS 는 이러한 NFS 의

한계를 극복하기 위해 고안되었고 설계원칙 상 다음 특징을 가진다.

HDFS는 대용량 데이터 (terabyte 또는 petabyte)를 저장하도록 고안되었다. 이를 위해서 데이터를 여러

대의 컴퓨터에 나누어 저장시킨다. 즉, NFS보다 훨씬 큰 파일도 지원한다.

HDFS에서 데이터 저장의 신뢰성이 훨씬 높아서 개별 컴퓨터가 이상을 일으켜도 데이터를 이용할 수 있다.

HDFS는 데이터 액세스의 성능개선도 용이하다. 클러스터에 node만 추가하면 이용가능한 클라이언트 숫자

는 계속 늘어날 수 있다.

HDFS는 Hadoop의 MapReduce와 잘 통합된다.

반면 HDFS 의 성능은 개선되었지만 설계원칙 상 불가피하게 특정 응용프로그램에는 적합하지 않은

결과를 초래한다. 즉, NFS 만큼 범용은 아니라는 뜻이다.

HDFS 를 이용 시에는 다음의 상충되는 요소들을 함께 고려해야 한다.

HDFS는 파일을 순차적 스트리밍 방식으로 읽는 (long sequential streaming reads) 응용프로그램을

전제로 하였다. 따라서 무작위로 random access하는 경우에는 탐색시간 (seek time)이 길어지는 단

점이 있다.

HDFS는 한번 기록한 후 읽기를 여러 번 반복하는 것(write-once, read-many)을 기준으로 하였다.

(파일에 데이터를 추가하는 기능이 Hadoop 0.19부터 지원되기는 하지만 성능상 한계가 있다.)

작업 대상 파일의 크기가 크고 읽기 작업이 순차적으로 이루어지다 보니 HDFS에서는 데이터의 캐싱

(local caching)을 하지 않는다. 실제로 캐싱작업에서는 시스템의 부담이 커지므로 차라리 데이터의 소

스로부터 읽기작업을 다시 실행하는 것이 오히려 더 나은 경우가 많다.

개별 기기가 장애를 일으키는 일이 빈번할 뿐 아니라 여러 대의 기기가 동시에 문제를 발생시키는 경우

도 있으므로 (예: rack 의 장애로 인해 여러 대 컴퓨터가 동시에 동작하지 않는 경우) 클러스터는 이러

한 것들을 견딜 수 있도록 해야 한다. 이 때 비록 일부 기기의 성능이 저하되는 한이 있더라도 시스템 전

체가 느려지거나 데이터를 이용할 수 없는 결과가 초래되지 않도록 대책을 세워야 한다.

당초 HDFS 는 GFS 를 기초로 설계된 블록 기반의 (block-structured) 파일시스템이다. 따라서 각각의

파일을 일정한 크기의 블록으로 나눈 후 클러스터 내의 여러 기기에 분산 저장하는데 이때의 개별 기기에는

DataNode 라는 파일시스템 데몬이 동작한다. 이때 Hadoop 은 이들 각각의 블록을 보관하는 컴퓨터를 블록

별로 (on a block-by-block basis) 무작위로 선택한다. 그 결과 파일을 이용하는 때에는 여러 컴퓨터

Page 14: II. Hadoop¹…데이터1031_6x9_9... · 그런데 이때 Nutch 가 가져오는 방대한 데이터를 처리할 길이 없어 난감해 하던 차에 2004년 Google이 발간한

사이의 협력이 필요해지는 단점이 있는 대신 단일기기용 분산파일시스템보다는 지원되는 파일의 크기가

훨씬 커지는 장점이 있다.

파일을 이용하는데 여러 대 컴퓨터가 협력한다는 점에서는 이들 중 한 대만 고장을 일으켜도 파일작업을

할 수 없게 된다는 문제가 발생하는데 HDFS 에서는 각각의 블록을 여러 대의 컴퓨터에 중복하여 저장하는

방식으로 이 문제를 해결한다. (이때의 중복 저장하는 숫자를 중복인자 (replication factor)라 하며 3 을

기본으로 하되 조정이 가능하다)

DataNode들이 여러 파일의 블록들을 저장한다. 여기서는 replication factor가 2이고 NameNode는 파일이름과

그 파일의 block id를 대응시킨다.

대부분의 파일시스템에서 블록의 크기는 4KB 또는 8 KB 이다. 반면 HDFS 에서의 기본 (default)

블록사이즈는 64MB 로서 훨씬 큰데 이는 파일 당 필요한 메타데이터는 작아지게 하는 잇점을 제공한다

(파일 당 필요한 블록의 개수 자체가 줄어든다).

또한 HDFS 에서는 데이터를 순차방식으로 고속 stream read 하므로 대용량 데이터를 효율적으로 읽어

들일 수 있다. NTFS 또는 EXT 같은 일반 파일시스템에서는 평균크기가 작은 파일을 전제로 하지만

HDFS 는 크기가 큰 파일을 전제로 한다. 그 결과 예컨대 100MB 크기의 파일이라고 해도 블록 2 개면

충분하다. PC 의 경우 파일 크기도 작고 이곳 저곳의 내용을 random 하게 액세스하는 경우가 대부분이지만

HDFS 는 프로그램이 블록을 처음부터 끝까지 읽어 들인다고 가정하였으며 이로 인해 MapReduce 스타일의

프로그래밍이 편리해진다.

HDFS 에서 데이터 파일을 처리하는 주된 기준은 레코드 단위이다. 즉, 입력파일을 레코드를 기준으로

절단(split)하며 각 프로세스는 HDFS 파일의 위치에 따라 (이를 지역성(locality)이라 한다) 할당된

레코드만 처리한다. 이는 얼핏 당연해 보이지만 실제로는 기존 데이터처리 방식과는 정 반대이다. 즉,

기존에는 작업대상 파일 (즉, 스토리지)을 전산시스템의 중앙부에 놓고 – 이때 관리효율을 높이기 위해 SAN

내지 NAS 를 이용함 – 모든 컴퓨터 node 는 이들 중앙의 데이터 중 필요한 부분을 가져와서 작업하고

결과를 다시 중앙 스토리지에 반환/저장하는 방식을 취하였다. 그러나 과정을 유기적으로 조정하기 위해

socket 프로그램 내지 응용프로그램에서의 marshalling 등 많은 통신 오버헤드가 과도하게 발생하였다.

Page 15: II. Hadoop¹…데이터1031_6x9_9... · 그런데 이때 Nutch 가 가져오는 방대한 데이터를 처리할 길이 없어 난감해 하던 차에 2004년 Google이 발간한

그러나 Hadoop 에서는 데이터를 중앙에 모으는 대신 이를 처리할 컴퓨터에게 보내준다10는 (Moving

computation to the data) 발상의 전환을 통해 기존방식에서의 관리부담이 원천적으로 사라지게 되었다.

Hadoop 의 프로그래밍 프레임워크에서 데이터는 논리적 차원에서 레코드 단위로 처리(record-

oriented)된다. 따라서 각각의 입력파일은 여러 개의 줄 (line) 또는 별도로 응용프로그램의 로직에 의해

지정된 나름의 형식으로 분해된다. 클러스터 내의 각 node 에서 수행되는 프로세스들 역시 이들 레코드

단위로 작업을 수행한다.

구체적으로는 대상 데이터 세트(dataset)11를 블록단위로 나누고 중복적으로 slave node 에게 분배하는

한편 이들에 대한 MapReduce 의 작업 결과를 읽거나 파일에 기록하는 일련의 파일작업을 포함한다.

다만, HDFS 는 일반 Linux 의 파일시스템과는 독립된 것이므로 반드시 Hadoop 명령어를 통해서만 이를

관리할 수 있다. 일반적으로 Hadoop 에서는 데이터파일을 Linux 파일로 생성한 후 이를 HDFS 로 복사해

와서 작업하는 방식을 취한다. 그리고 그 파일 대해서 응용프로그램을 통해 MapReduce 작업을 수행할 때도

모든 작업은 HDFS 파일을 직접 다루기 보다는 MapReduce 를 통해 (key/value)의 쌍으로 이루어진

record 단위로 작업을 수행하는 방식을 취한다. 즉, 대부분의 경우 HDFS 파일에 대해 직접 기록하거나 읽는

대신 응용 프로그램에서의 MapReduce 를 통해 파일작업이 진행되는 것이다.

나. HDFS에서의 데몬 프로그램

NameNode

HDFS 에서 master 인 NameNode 는 분산환경에서 저장기능을 담당한다. 즉, 실제 작업의 대상이 되는

파일을 블록 단위로 나누어서 slave node 들에게 분배할 뿐만 아니라 전체적인 (분산) 파일시스템의 이상

유무도 체크하고 slave 컴퓨터인 DataNode 에서의 데이터 입출력 작업 (low-level I/O tasks)을 지휘한다.

이러한 작업은 메모리 소모도 크고 입출력도 빈번하므로 NameNode 에 이상이 발생하면 Hadoop

클러스터는 전체가 동작을 멈추게 된다.

10 HDFS 는 입력 데이터가 들어오면 즉시 그 파일을 쪼개서 각각의 node 에 분배한다. 이때 하나의 파일로부터 만들어진 여러

개 조각을 각각 chunk 라고 부른다. 특기할 것은 이들 chunk 를 각각의 노드에 분배할 때 여러 개로 복제하여 분배한다는 점이다.

즉, A 라는 이름의 파일을 3 조각 내었다면 (이들 각각을 A0, A1, A2라면) 이들 각각의 chunk 는 여러 개 (통상 3 개 이상)로

복제하여 즉, A0’/A0’’/A0’’’, A1’/A1’’/A1’’’, A2’/A2’’/A2’’’의 여러 복제본을 node 에 분배한다.

한 걸음 나아가 이들 각각의 복제된 조각에 대해 이를 분배받은 node 는 아무런 차별 없이 동일하게 지시 받은 작업을

수행한다. 따라서 특정 node 에 장애가 발생하였을 경우 각 chunk 가 다른 node 에 존재할 뿐만 아니라 이미 동시에 수행되고

있는 상태여서 얼마든지 장애 node 의 내용을 다른 node 에서의 동일내용 chunk 로 대체할 수 있는 것이다. 물론 이처럼 장애에

대처하기 위해서 전체적인 상황을 감독하는 컴퓨터 (monitoring system)는 데이터를 re-replicate 하는 등 끊임없이

관리작업을 수행한다.

11 원래 dataset 는 특히 행과 열 형식으로 체계화된 데이터를 말하지만 여기서는 (즉, Hadoop 에 관한 논의 전체에서)

Hadoop 의 응용프로그램의 작업대상이 되는 데이터를 뜻한다고 보면 된다.

Page 16: II. Hadoop¹…데이터1031_6x9_9... · 그런데 이때 Nutch 가 가져오는 방대한 데이터를 처리할 길이 없어 난감해 하던 차에 2004년 Google이 발간한

파일시스템에서 메타데이터 관리의 신뢰성도 중요하다. 특히 데이터 파일은 “write once, read many”

형태를 취하지만 메타데이터 (예: 파일 및 디렉토리 이름 등)만큼은 여러 클라이언트 컴퓨터가 동시에

수정하려 시도할 수 있으므로 동기화 기능이 중요하기 때문에 NameNode 가 별도의 컴퓨터에서 관리한다.

NameNode 는 파일시스템의 모든 메타데이터를 관리하는데 파일당 메타데이터의 크기가 작으므로 (파일명,

사용권한, 각각의 블록의 위치 정도만 관리) 이들 메타정보는 NameNode 기기의 메인메모리에 상주시켜

이용한다. 이처럼 한 클러스터에는 단 한 개의 NameNode 가 존재하고 master node 로 지정된 컴퓨터가

NameNode 를 전담관리하며 다른 작업은 일체 하지 않는다.

작업 시 클라이언트는 NameNode 에 대한 질의를 통해 (특정 파일의 블럭의 목록 등의 정보 등에 대한)

메타데이터를 메인메모리로부터 가져온다. 하지만 이후의 작업은 NameNode 의 간섭 없이

DataNode 로부터 병렬로 직접 read 작업을 통해 수행한다. 이처럼 NameNode 의 관여없이 데이터를

통째로 가져오기 때문에 효율이 더욱 높아진다.

개별 DataNode 가 장애를 일으키는 경우에도 전체적인 시스템의 이용이 가능하지만 NameNode 에

장애가 발생하면 시스템 전체의 이용이 불가능해진다. 다만 일상적인 작업현장에서는 (DataNode 와는

달리) NameNode 는 주도적 역할을 하지 않기 때문에 장애의 위험성은 매우 낮다. 만전을 기하기 위해

NameNode 를 이중으로 가져가려는 노력이 있을 수 있는데 그 방법이 secondary NameNode 의

이용이다.12

DataNode

Hadoop 에서는 데이터를 읽어 들임과 동시에 각 노드에 데이터가 분배된다. HDFS 는 큰 데이터 파일을

여러 개로 분리시키고 각각의 node 가 이를 처리하게 하는데 이들 각각의 조각(chunk)은 여러 대 컴퓨터에

중복적으로 복제되어서 한 컴퓨터에 장애가 발생해도 다른 컴퓨터를 통해 데이터를 이용할 수 있다. 또한

모니터링 시스템을 통해 저장된 데이터의 일부에 문제가 발견될 때에는 이를 다시 복제하도록 조처할한다.

이때 이들 모든 파일조각들은 하나의 namespace 를 공유하므로 클러스터 내의 모든 노드들이 이를 이용할

수 있다. slave 기기는 DataNode 데몬을 통해 분산파일의 read/write 작업을 수행한다. 그리고 이때

DataNode 데몬 프로그램은 다른 DataNode 와 통신하면서 자신의 데이터 블럭을 복제하기도 하고 직접

처리작업을 수행하기도 한다.

HDFS 의 분산파일시스템에서의 읽기 및 쓰기 작업은 대상파일을 random 하게 블록 단위로 나누어

진행하는데 이들 DataNode 작업은 수시로 NameNode 에 보고되고 그 내역은 NameNode 에

메타데이터의 형식으로 저장된다.

12 단, secondary NameNode 의 작업은 실제 HDFS 에 대해 이루어지는 것이 아니고 NameNode 와의 연락만을 유지한다.

즉, 주기적으로 HDFS 의 메타데이터를 유지관리함으로써 유사시 NameNode 가 제 역할을 하지 못할 경우를 대비한다. 그러나

실제로 이상 시에는 관리자가 직접 secondary NameNode 를 구동시켜 주어야 한다.

Page 17: II. Hadoop¹…데이터1031_6x9_9... · 그런데 이때 Nutch 가 가져오는 방대한 데이터를 처리할 길이 없어 난감해 하던 차에 2004년 Google이 발간한

다. HDFS 명령어

HDFS 는 일반 Unix/Linux 의 파일시스템과는 전혀 별개이다. DataNode 데몬을 수행하는 기기에서 ls

명령을 수행하면 일반 Linux 파일시스템의 내용은 보이지만 HDFS 의 파일은 보이지 않는다. 마찬가지로

fopen() 또는 fread()같은 표준의 읽기/쓰기 작업도 불가능하다. 요컨대 파일시스템으로서의 각종 작업에

대해서 HDFS 는 HDFS 나름의 독자적인 명령어와 shell 구조를 가지고 있다는 말이다. 이러한 현상은

HDFS 가 별도의 독립된 namespace 를 가지기 때문이다. HDFS (정확히는 HDFS 를 구성하는 블록) 내의

파일은 DataNode 서비스가 관리하는 별도의 디렉토리에 저장된다. 그리고 이들 파일은 block id 로만

표시된다. HDFS 에 저장된 파일에 Linux 의 일반 파일수정방식을 (예: ls, cp, mv, etc) 적용할 수도 없다.

대신 HDFS 는 자체의 파일관리 방식을 가지는데 그 모습은 기존의 방식과 매우 유사하다.

한편 HDFS 파일시스템을 이용하려면 처음 한 차례에 한해 다음 HDFS 명령어를 통해 포맷팅이 되어야

한다. (단, $ 프롬프트 이후의 것들이 명령어와 option 임)

user@namenode:hadoop$ bin/hadoop namenode -format

이하에서는 이러한 선행작업이 되었다고 전제한다.

한편 Hadoop 의 작업에서는 일반적으로 데이터 파일이 Hadoop 이외의 곳에서 생성되는 것을 전제로

하는 경우가 많다. 즉, 별도의 텍스트 파일이 있다거나, 또는 각종의 log 파일이 외부에서 이미 생성되었다고

보고 이를 HDFS 로 복사하는 방식으로 읽어 들이는 것이다. 그리고 파일을 HDFS 로 읽어 들인 후에도

MapReduce 프로그램이 이를 처리할 때는 MapReduce 응용프로그램에서 직접 읽는 대신 Hadoop 의

MapReduce 프레임워크를 통해 HDFS 파일을 (key/value pair 형태의) 개별 레코드 형식으로

파싱(parsing)하여 사용한다.

기본적인 파일 shell 명령어

Hadoop 의 파일 명령어의 표준형은 다음과 같다.

Page 18: II. Hadoop¹…데이터1031_6x9_9... · 그런데 이때 Nutch 가 가져오는 방대한 데이터를 처리할 길이 없어 난감해 하던 차에 2004년 Google이 발간한

hadoop fs –cmd <args>

여기서 cmd 는 구체적인 명령어를 그리고 <args>는 매개변수(argument)를 나타낸다.

다만 명령어 cmd 는 일반 Unix/Linux 의 명령어와 그 형태가 매우 유사하다. 예를 들어서 특정 디렉토리

내에서의 파일의 목록을 보려면:

hadoop fs –ls

라고 하면 된다.

HDFS 의 디폴트 작업 위치는 /usr/$USER 이지만 (단, $USER 는 login 한 사용자 이름을 뜻함)

그렇다고 그 디렉토리가 자동 생성되지는 않으므로 다음의 명령어를 통해 이를 직접 만들어 주어야 한다.

hadoop fs –mkdir /user/hkyoon

Linux/Unix 에서 로컬파일을 HDFS 로 복사해 오는 명령어는 다음과 같다.

hadoop fs –put example.txt

앞서 ls 명령을 재귀적으로 사용하여 하위 디렉토리 내의 목록까지 함께 보려면 lsr 명령어를 이용한다.

$ hadoop fs -lsr /

drwxr-xr-x - hkyoon supergroup 0 2013-01-14 10:23 /user

drwxr-xr-x – hkyoon supergroup 0 2013-01-14 11:02 /user/hkyoon

-rw-r--r-- 1 hkyoon supergroup 264 2013-01-14 11:02 /user/hkyoon/example.txt

위 목록에서 마지막 줄의 소유자 이름 (hkyoon) 앞의 1 이란 숫자가 복제본 개수(replication factor)를

나타낸다.

앞서의 put 과 반대로 HDFS 로부터 로컬시스템의 파일로 가져오는 명령으로 get 이 있다. 한편 파일의

내용을 보려면 cat 이라는 명령어를 사용한다. Unix/Linux 의 catalog 에 해당한다. 다음에서는 여기에

head 라는 Linux 명령을 pipeline 으로 연결하여 적용했다.

hadoop fs -cat example.txt | head

이외에도 다음과 같은 다양한 HDFS 의 파일명령어가 제공된다.

cat chgrp chmod chown

copyFromLocal copyToLocal cp du

dus expunge get getmerge

ls lsr mkdir movefromLocal

mv put rm rmr

setrep stat tail test

text touchz

Page 19: II. Hadoop¹…데이터1031_6x9_9... · 그런데 이때 Nutch 가 가져오는 방대한 데이터를 처리할 길이 없어 난감해 하던 차에 2004년 Google이 발간한

이들 명령어에 대한 구체적 용법에 대해서는

http://hadoop.apache.org/docs/r0.18.3/hdfs_shell.html 참조하면 된다.

프로그램을 이용한 HDFS 파일의 이용

Hadoop 에서는 각종의 작업을 위한 HDFS API 가 제공된다. 이를 위해 우선 org.apache.hadoop.fs 의

package 와 함께 필요한 API 를 프로그램에서 이용하는데 각 API 의 세부 내용은 Hadoop api 는

hadoop.apache.org/docs/current/api/ 를 참조하면 된다.

아래에서는 hadoop.txt 라는 이름의 파일을 만든 후 "My First Hadoop API call!\n"라는 문자열을

기록하고 다시 이를 읽어서 화면에 출력하는 프로그램이다. 13

13 단, 프로그램은 전체 흐름의 이해를 위해 주석 및 package import 부분은 생략하였다.

Page 20: II. Hadoop¹…데이터1031_6x9_9... · 그런데 이때 Nutch 가 가져오는 방대한 데이터를 처리할 길이 없어 난감해 하던 차에 2004년 Google이 발간한

public class HDFSExample {

public static final String FileName = "hadoop.txt";

public static final String message = "My First Hadoop API call!\n";

public static void main (String [] args) throws IOException {

Configuration conf = new Configuration();

FileSystem fs = FileSystem.get(conf);

Path filenamePath = new Path(theFilename);

try {

if (fs.exists(filenamePath)) {

fs.delete(filenamePath);

}

FSDataOutputStream out = fs.create(filenamePath);

out.writeUTF(message);

out.close();

//Open Config file to read

FSDataInputStream in = fs.open(filenamePath);

String messageIn = in.readUTF();

System.out.print(messageIn);

in.close();

} catch (IOException ioe) {

System.err.println("IOException ~~~: " + ioe.toString());

System.exit(1);

}

}

}

(2) MapReduce

가. MapReduce 기본개념

MapReduce는 Hadoop 의 프로그래밍 패러다임으로서 입력 데이터 리스트를 출력 리스트로 변형시킴에

있어 과정 전체를 한번에 처리하지 않고 크게 두 덩어리로 나눈 후 한 단계의 작업이 완료되면 그 다음의

단계로 이어지도록 하는 것을 말한다. 마치 Unix/Linux 에서의 pipeline 이 여러 개의 명령어를 연결시켜서

차례로 수행하도록 하는 것처럼 MapReduce 프로그램은 데이터 처리작업을 Map 과 reduce 라는 두 번에

걸쳐 실시한다. 그리고 이 과정에서 partitioning 과 shuffling 작업이 보조적으로 수행된다.

입력 list의 각 항목에 Map함수를 적용해서 새 출력 list가 만들어짐.

Page 21: II. Hadoop¹…데이터1031_6x9_9... · 그런데 이때 Nutch 가 가져오는 방대한 데이터를 처리할 길이 없어 난감해 하던 차에 2004년 Google이 발간한

프로그래머가 mapper 와 reducer 에 필요한 작업내용을 지정한 후 Hadoop 에서 수행시키면 이들

mapper 와 reducer 가 partitioning 및 shuffling 의 지원을 받아가면서 분산 처리되는 것이다. 예를 들면

mapper 단계에서 먼저 입력 파일을 분할하여 여러 node 에 (중복) 배분한 후 각각 할당된 데이터를

처리한다.

Reducer 는 mapper 의 처리결과를 넘겨받은 후 이들을 종합하여 최종결과물을 만들어 내다. 결국 같은

key 를 가진 value 는 하나로 통합된다. (다음 그림에서는 색깔 별로 각각의 key 를 나타낸다고 가정)

다음의 예에서는 몇 가지 단어가 수록된 입력파일을 분석해서 단어별 빈도수를 조사하는 모습을 그림으로

표현하였다.

Haddop의 데이터 타입

MapReduce 에서는 사용자가 임의로 타입을 지정하거나 또는 Java 의 기본 데이터 타입을 그대로 이용할

수 없며 반드시 MapReduce 프레임워크가 지원하는 데이터 타입을 이용해야 한다. Hadoop 에서 key 와

value 에 대해 적용할 수 있는 데이터 타입의 규칙은 다음과 같다.

Writable interface를 실행하는 class는 value가 될 수 있다.

WritableComparable<T> interface를 실행하는 class는 key 또는 value 모두가 될 수 있다.

Page 22: II. Hadoop¹…데이터1031_6x9_9... · 그런데 이때 Nutch 가 가져오는 방대한 데이터를 처리할 길이 없어 난감해 하던 차에 2004년 Google이 발간한

(참고로 WritableComparable<T> interface 는 Writable 과 java.lang.Comparable<T> interface 를

합한 것이다.)

이처럼 key 를 정의할 때 비교가능성(comparability)이 필요한 것은 value 와는 달리 이들이 reduce

단계에서 정렬되기 때문이다.

다음은 Hadoop 이 기본으로 제공하는 데이터 타입인데 이들은 Java 표준 데이터타입에 대한

wrapper 로서 WritableComparable interface 를 구현하며 key/value pair 로 많이 이용된다.

BooleanWritable ByteWritable DoubleWritable

FloatWritable IntWritable LongWritable

Text NullWritable

필요 시 위 interface 를 구현하여 자신만의 데이터타입을 만들 수 있다.

Mapper 함수와 Reducer 함수

Mapper 로 사용하기 위해서 해당 class 를 작성할 때는 Mapper interface 를 구현하면서 MapReduce

base class 를 확장하는 방식으로 구현한다. MapReduce 는 mapper 및 reducer 의 base class 로 2 개

method 를 가진다.

void configure(JobConf job)

void close( )

Mapper interface 는 map() 이라는 단 하나의 method 를 가지는데 그 signature 는 다음과 같다.

void map(K1 key,

V1 value,

OutputCollector<K2,V2> output,

Reporter reporter

) throws IOException

다음은 Hadoop 에서 미리 제공하는 Mapper 의 실행 class 이다. (각각의 의미는

http://hadoop.apache.org/docs 참조할 것.)

IdentityMapper<K,V> InverseMapper<K,V>

RegexMapper<K> TokenCounterMapper<K>

Reducer 역시 MapReduce base classs 를 확장하면서 Reducer interface 를 구현해야 한다. Reducer

interface 역시 reduce() method 를 가지며 그 signature 는 다음과 같다.

void reduce(K2 key,

Iterator<V2> values,

OutputCollector<K3,V3> output,

Reporter reporter

) throws IOException

Page 23: II. Hadoop¹…데이터1031_6x9_9... · 그런데 이때 Nutch 가 가져오는 방대한 데이터를 처리할 길이 없어 난감해 하던 차에 2004년 Google이 발간한

다음은 Hadoop 에서 미리 제공하는 Reducer 의 실행 class 이다. (http://hadoop.apache.org/docs

참조.)

IdentityReducer<K,V> LongSumReducer<K>

Word Count의 예

이제 구체적인 예제 프로그램을 살펴 본다. 텍스트 파일의 내용을 분석하여 출현하는 단어 별 빈도를

출력하는 것이다. 이 프로그램은 Hadoop 을 설치하면 함께 따라오는 것으로서 그 위치는

src/examples/org/apache/hadoop/examples/WordCount.java 이다. 다만, 여기서는 한글 데이터

파일을 대상으로 하는 것으로 가정하였고 프로그램은 대폭 단순화 하였다.

우선 아래의 시(詩)를 내용으로 하는 파일이 있다고 가정한다.

때로 마주친 책과 사람들에게서..

주눅이 들게 하는 글을 만납니다..

주눅이 들게 하는 사람을 만납니

다..

이 시에 나오는 단어 별

빈도는 오른쪽과 같다.14

때로 1

마주친 1

책과 1

사람들에게서 1

주눅이 2

들게 2

글을 1

만납니다 2

사람을 1

이러한 단어의 빈도분석 프로그램의 기본로직은 다음과 같다.

define WordFrequency as FrequencyTable;

for each document in documentSet {

T = tokenize(document);

for each token in T {

WordFrequency [Word]++;

}

}

display(WordFrequency);

위에서는 빈도결과를 저장할 WordFrequency 라는 테이블을 지정한 후 각각의 문서 (여기는 하나의

문서)에 대해 분석을 실시하였다. Tokenize 는 문장을 단어별로 분절해 주는 함수로서 각각의 단어가 발견될

때마다 WordFrequency[Word]를 1 씩 증가시켰다.

14 문장에서 단어를 추출하는 것을 tokenize 한다고 하는데 이는 검색을 위한 색인추출 (indexing)의 핵심과정이다. 다만

실제로는 어근과 어미의 분리, 단수형과 복수형 처리 및 현재형/과거형/미래형의 처리 등 형태소 분석 문제가 발생할 수 있지만

여기서는 이를 생략하였다. 논의의 주제를 해칠 수 있기 때문이다.

Page 24: II. Hadoop¹…데이터1031_6x9_9... · 그런데 이때 Nutch 가 가져오는 방대한 데이터를 처리할 길이 없어 난감해 하던 차에 2004년 Google이 발간한

이제 이러한 작업을 각각 500 페이지인 책 1,000 권에 대해 수행한다고 하자. 이런 단순한 작업만도

웬만한 컴퓨터로 며칠씩 걸릴 것이다. 심지어 데이터가 수시로 추가/변경되거나 또는 더 복잡하고 세련된

분석을 하고자 한다면 뭔가 다른 방법을 강구하지 않으면 안 된다. 이 경우 위 로직을 프로그램을 여러 대의

컴퓨터에서 동시에 수행시킨 후 결과를 취합하면 수행시간이 수 십분의 1 로 줄게 된다. 이를 위해 다음과

같이 수정한다.

(분배처리 단계)

define WordFrequency as FrequencyTable;

for each document in documentSubset {

T = tokenize(document);

for each Word in T {

WordFrequency[Word]++;

}

}

partition_and_sort(WordFrequency);

sendToSecondPhase(WordFrequency);

(결과합산 단계)

define totalWordFrequency as FrequencyTable;

for each WordFrequency received from firstPhase {

FrequencyTableAdd (totalWordFrequency, WordFrequency);

}

여기서는 Partition_and_sort()을 통해 앞의 처리결과 WordFrequency[Word] 를 가/나/다/… 순서로

나눈 후 정렬하고 (중간합산 하는 등의 추가작업은 생략하였다.) 그 결과를 다음 단계에 전달하였다. 그리고

합산단계에서는 이들을 전체목록 (totalWordFrequency)에 추가하였다.

위 “분배처리 단계”가 MapReduce 에서의 mapping 단계에 해당하고, “결과합산 단계”는 reducing

단계에 해당한다. 결국 mapping 단계는 변환 및 필터(filter)의 단계이고 reducing 단계는 종합(합산)의

단계이다.

한편 mapper 와 reducer 그리고 partitioning 과 shuffling 의 제반 작업이 매끄럽게 이루어지려면 이들

각각을 처리한 후 다음 단계로 넘겨지는 데이터가 일정한 구조를 가지는 것이 필요하다. 실제로 이들

mapping 단계와 reducing 단계에 각각은 물론이고 이들 여러 단계의 연결과정에서도 모든 데이터는

(key/value)의 list 로 처리된다. 대상 데이터 내용이 어떠하든, 그리고 mapper, reducer 에 지정된

업무로직이 어떠하든 그 작업이 효율적으로 수행되기 위해서는 MapReduce 에서 주된 데이터 포맷(data

primitive)으로 list 와 (key/value) pair 를 이용하는 것이다. 다시 말하면 MapReduce 에서는 그 어떤

값도 독립해서 존재하지 않는다. 모든 값에는 자신에 적용되는 key 가 존재하며 또한 모든 Key 는 관련된

값을 식별해준다. 다음 그림에 단계별로 전달되는 데이터의 (key/value) pair 의 형태와 그 설명과 함께

나타나 있다.

얼핏 보면 매우 복잡해 보이지만 우리는 여기서 기본 규칙을 발견할 수 있다. 즉, 데이터 처리 작업을

map 과 reduce 의 단계로 나눈 후 각각의 처리 로직을 Hadoop 이 지정한 API 를 이용하여 프로그램

Page 25: II. Hadoop¹…데이터1031_6x9_9... · 그런데 이때 Nutch 가 가져오는 방대한 데이터를 처리할 길이 없어 난감해 하던 차에 2004년 Google이 발간한

작성한다. 이때 데이터에 대해서는 포맷을 (key/value) pair 로 하되 이들이 단계별로 이동할 때 미리 정한

규칙을 따르게 하면 이후의 전반적인 처리는 Hadoop 의 MapReduce 에서 관리하고 조정한다. 즉,

개발자가 이들 규칙에 충실히 프로그램을 작성하면 하나의 작업을 수백, 수천 대 컴퓨터에 동시병렬적으로

처리할 수도 있고 결과적으로 전체적인 처리성능은 무한히 커질 수 있는 것이다.

다음은 WordCount 프로그램의 작업 로직을 좀 더 MapReduce 규칙에 부합하는 용어로 (여전히 pseudo

코드로) 작성한 것이다.

Page 26: II. Hadoop¹…데이터1031_6x9_9... · 그런데 이때 Nutch 가 가져오는 방대한 데이터를 처리할 길이 없어 난감해 하던 차에 2004년 Google이 발간한

map(String filename, String document) {

for each document in documentSets{

line = readLine(document)

List<String> T = tokenize(document);

for each token in T {

emit ((String)token, (Integer) 1);

}

}

}

reduce(String token, List<Integer> values) {

Integer sum = 0;

for each value in values {

sum = sum + value;

}

emit ((String)token, (Integer) sum);

}

map()과 reduce()함수 모두 출력물이 리스트 형태를 가진다는 점만 유념한다면 이 코드는 앞서의 것과

매우 유사함을 알 수 있다.

이제 실제 Hadoop 에서의 Java 코드를 본다. (단, 가독성을 위해 package import, exception 및

컴파일러 annotation 을 생략했다.)

public class WordCount extends Configured implements Tool {

public static class WordCountMap

extends Mapper<LongWritable, Text, Text, IntWritable>{

private final static IntWritable one = new IntWritable(1);

private Text word = new Text();

public void map(LongWritable key,Text value,Context context){

String line = value.toString();

StringTokenizer tokenizer=new StringTokenizer(line);

while(tokenizer.hasMoreTokens()){

word.set(tokenizer.nextToken());

context.write(word, one);

}

}

}

Page 27: II. Hadoop¹…데이터1031_6x9_9... · 그런데 이때 Nutch 가 가져오는 방대한 데이터를 처리할 길이 없어 난감해 하던 차에 2004년 Google이 발간한

public static class WordCountReducer

extends Reducer<Text, IntWritable, Text, IntWritable>{

public void reduce(Text key,Iterable<IntWritable> values,

Context context){

int sum = 0;

for(IntWritable value: values){

sum += value.get();

}

context.write(key, new IntWritable(sum));

}

}

public int run(String[] args) {

Job job = new Job(getConf());

job.setJarByClass(WordCount.class);

job.setJobName("wordcount");

job.setOutputKeyClass(Text.class);

job.setOutputValueClass(IntWritable.class);

job.setMapperClass(WordCountMap.class);

job.setCombinerClass(WordCountReducer.class);

job.setReducerClass(WordCountReducer.class);

job.setInputFormatClass(TextInputFormat.class);

job.setOutputFormatClass(TextOutputFormat.class);

FileInputFormat.setInputPaths(job, new Path(args[0]));

FileOutputFormat.setOutputPath(job, new Path(args[1]));

boolean success = job.waitForCompletion(true);

return success ? 0: 1;

}

public static void main(String[] args) {

int result = ToolRunner.run(new WordCount(), args);

System.exit(result);

}

}

Hadoop 의 모든 MapReduce 프로그래밍은 실제로 위와 같은 모습을 가지므로 실제 작업에 있어서는

프로그램별로 일일이 새로 작성하지 않고 앞에서와 같은 프로그램 template 을 변형하여 이용하는 것이

보통이다. 다른 예로서 여러 대 자동차의 시간별 속도정보가 log 파일에 담겼다고 하자. 아마도 번호판을

key 로 하고 관련된 정보가 기록되어 있을 것이다..

나-1263 65kph, 12:00pm

노-7489 50kph, 12:02pm

허-4123 70kph, 12:05pm

라-4656 65kph, 12:15pm

...

Hadoop 에서의 mapping 및 reducing 함수는 값(values)만을 받을 수는 없고 언제나 (key, value) 의

pair 를 받는다. 이들 각각의 함수의 출력 역시 동일한 원칙이 적용되며 이들 모두 key 와 value 가 다음

단계의 데이터 흐름에서의 list 형태로 산출(emitted)된다.

Page 28: II. Hadoop¹…데이터1031_6x9_9... · 그런데 이때 Nutch 가 가져오는 방대한 데이터를 처리할 길이 없어 난감해 하던 차에 2004년 Google이 발간한

다만 MapReduce 에서는 Mapper 과 Reducer 의 동작방식이 다른 언어보다는 덜 엄격하다. 함수형

언어에서는 하나의 mapper 가 반드시 각각의 입력 항목에 대해 하나의 출력 항목을 산출하고 reducer 역시

하나의 입력 리스트에 대해 하나의 출력항목만을 만들어야 한다. 그러나 MapReduce 에서는 각 단계에서

임의의 수의 (0,1, 또는 심지어 수 백개의) 값들이 산출될 수 있다. reducer 도 마찬가지로 임의의 수의 값을

출력할 수 있다. 단계별 처리과정에서 Key 를 기준으로 reduce space 가 분할되며 reducer 함수는 많은

값들의 list 를 하나의 값으로 변환시킨다.

나. MapReduce의 주요 데몬

JobTracker

MapReduce 데몬들도 HDFS 와 마찬가지로 master-slave 의 구조를 가진다. 이 때 JobTracker 는

master 의 역할을, 그리고 TaskTracker 는 slave node 의 역할을 담당한다.

JobTracker 는 응용프로그램과 Hadoop 사이의 중간연락을 하는 데몬으로서 파일처리를 위한 실행계획,

node 할당, task monitoring 등을 담당한다. 즉, 프로그램을 수행시키면 JobTracker 가 대상 파일을 찾아낸

후 각각의 node 에게 작업할 내용을 할당하고 이것이 제대로 수행되고 있는지 감독한다. 그리고 이 과정에서

작업이 실패하면 다른 노드에게 재 작업을 지시한다. JobTracker 는 master node 가 이를 수행하는데

Hadoop 클러스터 내에는 단 1 개의 JobTracker 데몬이 존재한다.

TaskTracker

JobTracker 가 MapReduce 의 마스터 기능을 수행하는 것에 대응하여 TaskTracker 는 JobTracker 가

지시한 사항을 성실하게 집행한다. 그리고 (HDFS 에서의 NameNode 와 DataNode 와 마찬가지로) 이들

TaskTracker 는 JobTracker 와 지속적으로 통신하면서 정상적인 동작 유무를 확인하는데 이상이 발생하면

JobTracker 는 해당 작업을 클러스터 내의 다른 node 에게 중복하여 수행하도록 지시한다. 특기할 것은

각각의 slave node 에는 한 개의 TaskTracker 가 존재하지만 이 하나의 TaskTracker 는 여러 개의

JVM 을 생성시켜서 각각의 slave node 내에서 여러 개의 map task 와 reduce task 를 병렬적으로

수행시키게 된다는 점이다.

다음 그림은 1 대의 master (NameNode 와 JobTracker 가 수행됨)와 4 대의 slave node (DataNode 와

TaskTracker 가 수행됨)가 이용되는 모습으로서 백업용의 secondary NameNode 가 존재함을 알 수 있다.

이들 master 와 slave node 들 상호간 통신에서는 SSH 채널이 이용된다.

Page 29: II. Hadoop¹…데이터1031_6x9_9... · 그런데 이때 Nutch 가 가져오는 방대한 데이터를 처리할 길이 없어 난감해 하던 차에 2004년 Google이 발간한

그동안 논의된 Map/Reduce 전체를 정리한 그림은 다음과 같다.

앞의 그림을 간단히 살펴 본다.

HDFS 클러스터에 파일이 적재됨으로써 MapReduce 입력이 시작된다. 이들 파일은 전체 node에 균등

하게 배분되는데 이에 대해 MapReduce 프로그램이 수행되면서 node에서는 mapping task가 시작된

다.

Mapping작업에서 각각의 task는 동등한 것으로서 서로 구별되지 않으며 각 mapper는 그 어떤 입력파

일도 처리 가능하다. 각각의 mapper는 자신 컴퓨터 근처에 존재하는 파일을 적재한 후 곧바로 처리에

들어간다.

mapping 이 끝나면 중간산출물로서의 intermediate (key, value) pair가 각 컴퓨터 사이에서 교환되

고 같은 key를 가지는 모든 value들은 하나의 reducer에게 보내진다.

Reducer에서 여러 개 mapper로부터의 출력이 하나로 병합된다.

Page 30: II. Hadoop¹…데이터1031_6x9_9... · 그런데 이때 Nutch 가 가져오는 방대한 데이터를 처리할 길이 없어 난감해 하던 차에 2004년 Google이 발간한

끝으로 2004 년 Google 에서 발표한 MapReduce 논문

(http://research.google.com/archive/mapreduce-osdi04.pdf )의 그림을 소개한다. 번호별 설명을

통해 내용을 이해할 수 있을 것이다.

다. MapReduce의 데이터 흐름

Hadoop 에서의 MapReduce 의 중요성을 감안하여 작업 프로세스가 아닌 데이터의 흐름을 중심으로

정리하여 본다. 아래 그림에서는 각 단계에서의 데이터 흐름을 pipeline 으로 보여주고 있다.

Hadoop MapReduce의 데이터 흐름에 대한 상세한 모습

Page 31: II. Hadoop¹…데이터1031_6x9_9... · 그런데 이때 Nutch 가 가져오는 방대한 데이터를 처리할 길이 없어 난감해 하던 차에 2004년 Google이 발간한

입력 파일:

MapReduce task 용 데이터는 보통 HDFS 상에 존재한다. 파일 포맷은 그때 그때 다른데 line 기반의 log

파일, binary 포맷, multiline 의 입력 레코드 등 그 어떤 것도 가능하다. 다만, 용량은 매우 클 것이다.

InputFormat:

입력파일의 분할 방식이나 읽어 들이는 방식을 정의하는 클래스이다.

입력으로 사용될 파일 또는 기타의 object를 선택한다.

파일을 task로 분해할 InputSplits 을 정의한다.

파일을 읽기 위한 RecordReader 를 생성하는 factory를 제공.

Hadoop 은 여러 개의 InputFormat 관련 클래스를 제공한다. FileInputFormat 라는 이름의 abstract

type 이 존재해서 파일을 대상으로 하는 모든 InputFormat 은 이 클래스로부터 파생된다. Hadoop 의

job 을 수행하기 시작할 때 FileInputFormat 에 읽으려는 파일의 경로를 제시하면 FileInputFormat 이 이

디렉토리에 있는 모든 파일을 읽어 들인다. 그런 후 각각의 파일을 여러 개의 InputSplit 으로 분해한다.

개발자는 입력파일에 어떤 InputFormat 을 적용할지를 JobConf object 의 setInputFormat() method 를

호출하는 방식으로 정의한다. 표준 InputFormat 이 다음 표에 나와 있다.

InputFormat 설명 Key Value

TextInputFormat 디폴트 포맷이며

텍스트 파일의 각

줄을 읽어들임.

각 line 의

byte offset

line 의

내용

KeyValueInputFormat 각 line 을 key, val

pair 로

parse 한다.

첫째 tab

문자까지의

모든 내용

line 의

나머지

내용

SequenceFileInputFormat Hadoop 고유의

고성능 바이너리

포맷

사용자 정의 사용자

정의

TextInputFormat은 입력 파일의 각 line을 별개의 레코드로 취급하지만 별도의 parsing작업은 하지

않는다. 이것은 특히 unformatted 데이터 또는 로그파일과 같은 line기반의 레코드 등에 유용하다.

KeyValueInputFormat 역시 입력파일의 각 line을 별개의 레코드로 취급한다. 다만

TextInputFormat이 line 전체를 하나의 값(value)으로 여기는 반면 KeyValueInputFormat은 각

line을 tab 문자를 기준으로 key와 value로 분해한다는 점이 다르다.

SequenceFileInputFormat 은 Hadoop에 특수한 바이너리 파일을 읽어 들이는데 Hadoop mapper

에 고속으로 읽어 들일 수 있는 몇 가지 부가기능이 제공된다.

Page 32: II. Hadoop¹…데이터1031_6x9_9... · 그런데 이때 Nutch 가 가져오는 방대한 데이터를 처리할 길이 없어 난감해 하던 차에 2004년 Google이 발간한

InputSplits:

InputSplit 은 MapReduce 프로그램에서 map task 의 작업단위가 된다. Data set 에 적용되는

MapReduce 프로그램은 이를 총체적으로 Job 이라고 부르는데 이 job 은 수 백 개의 task 로 구성된다.

Map task 는 파일 전체 또는 일부분만도 읽을 수 있다. 디폴트 상태에서 FileInputFormat 과 하위 class 는

파일을 64 MB 단위의 chunk (HDFS 에서의 블록 크기와 동일)로 분할되는데 이 값은 hadoop-

site.xml 에서 mapred.min.split.size 파라미터를 이용하거나 특정 JobConf object 에서 파라미터를

override 하는 방식으로 변경할 수 있다. 파일을 chunk 단위로 처리하면 하나의 파일에 대해 여러 개의

map task 를 병렬 수행할 수 있어서 성능이 획기적으로 높아진다. 또한 각각의 블록을 한 node 에서 다른

node 로 옮길 필요 없이 파일을 구성하는 다양한 블록을 클러스터 내의 여러 node 에 분배하여 해당

node 에서 직접 (locally) 처리할 수 있다. 파일포맷이 chunk 단위로 쪼개기 어려울 경우에는 custom 의

InputFormat 을 작성해서 파일분할의 조건과 방법을 지정할 수도 있다.

RecordReader:

InputSplit 을 통해 일의 단위가 지정되지만 그 액세스 방법은 정의되지 않는다. 데이터를 적재한 후

Mapper 가 읽기 쉬운 (key, value) pair 로 변환하는 일은 RecordReader 클래스가 담당한다.

RecordReader instance 는 InputFormat 에 의해 정의된다. 디폴트의 InputFormat 인

TextInputFormat 은 LineRecordReader 를 제공하는데 여기서는 입력파일의 각각의 line 을 새로운

값으로 취급한다. 각 line 에 대한 key 는 파일에서의 byte offset 이다. 입력 시 InputSplit 전체가 완료될

때까지 RecordReader 는 계속 호출 (invoke)된다. RecordReader 가 호출되면 Mapper 의 map()

method 역시 호출된다.

Mapper

Key 와 value 가 주어지면 map() method 는 (key, value) pair(s)를 Reducer 에게 전달한다. 새로운

Mapper instance 는 각각의 map task (InputSplit)에 대한 별도의 Java 프로세스 속에서 만들어진다.

이러한 map task 는 전체적으로 하나의 job input 을 구성한다. 각각의 mapper 는 다른 mapper 와 어떤

통신도 하지 않는데 따라서 각 map task 의 신뢰성은 로컬 기기의 신뢰성에 전적으로 좌우되게 된다.

map() method 는 key 와 value 이외에 2 개의 파라미터를 전달받는다.

OutputCollector object는 collect() 를 통해 (key, value) pair를 job의 reduce 단계로 전달해 준다.

Reporter object 는 현재 task에 대한 정보를 제공한다. Reporter의 getInputSplit() 는 현재의

InputSplit을 설명하는 object를 반환한다. 또한 map task로 하여금 진행상태에 대한 정보를 시스템

내 다른 요소에게 제공할 수도 있다. setStatus() method 를 통해 사용자에게 상태메시지를 제공할 수

도 있다. incrCounter()를 통해서는 shared performance counter를 증가시킬 수도 있다.

Partition & Shuffle:

첫 번째 map task 가 종료되면 각 node 들이 다른 map task 들을 수행하고 있는 도중에도 map

task 로부터의 중간산출물을 이를 필요로 하는 reducer 에게로 전달하기 시작한다. 이처럼 map 의

산출물을 reducer 에게로 옮기는 것을 shuffling 한다고 하는데 중간단계 key space 의 일부가 각각의

Page 33: II. Hadoop¹…데이터1031_6x9_9... · 그런데 이때 Nutch 가 가져오는 방대한 데이터를 처리할 길이 없어 난감해 하던 차에 2004년 Google이 발간한

reduce node 에 할당된다. 이들 subset (이를 "partition"이라고 함)들은 reduce task 에 입력된다. 각

map task 는 그 어떤 partition 에도 (key, value) pair 를 전달할 수 있다. 하나의 key 에 대한 모든 값은

항상 그 원천이 어떤 mapper 였든 상관없이 병합된다. 따라서 중간산출 데이터의 각 항목을 어디로

보낼지에 대해 map node 는 의견 일치를 보아야 한다. Partitioner 클래스는 주어진 (key, value) pair 가

어떤 partition 으로 갈지를 결정하는데 디폴트 상태에서는 key 에 대한 hash 값에 따라 partition 을

할당한다.

Combiner:

Combiner 를 이용하면 MapReduce job 이 사용하는 대역폭을 절감할 수 있다. Combiner 는 Mapper 와

Reducer 사이에서 진행되는 것으로서 선택적 적용이 가능한데 이 경우 map task 가 수행되는 모든

node 에 대해 Combiner 클래스의 instance 가 적용된다. 각각의 node 에서 Mapper instance 가 산출한

데이터를 입력 받고 Combiner 가 지정된 작업을 하면 그 결과물은 Reducer 에게 보내진다. Combiner 는

일종의 "mini-reduce" 프로세스로서 하나의 단위 컴퓨터에서 생성된 데이터만을 대상으로 한다. 이 밖에

Fault Tolerant 기능과 Checkpoint 기능도 있다.

앞서의 WordCount 프로그램의 경우 각 단어가 발견될 때마다 (word, 1) pair 를 산출했는데 예컨대

"주눅이"라는 단어가 2 번 발견되면 ("주눅이", 1) pair 가 2 번 출력되고 따라서 Reducer 에게도 2 번

전달된다. 그러나, Combiner 를 통하면 이들이 각각의 컴퓨터에서 합산되어서 ("주눅이", 2) pair 가 단

한번만 Reducer 에게 전달된다. 이처럼 모든 노드에서 여러 번 반복해서 전달되던 항목을 중간합산하여 각

단어 당 한번씩만 전달됨으로써 shuffle 프로세스에서 요구되는 대역폭을 획기적으로 줄이게 되고

결과적으로 job 처리속도가 개선된다. 이것 역시 별도의 프로그램 작업 없이 구동 프로그램에 다음의 한

줄만 삽입하면 MapReduce 프레임워크가 자동 진행해 준다.

conf.setCombinerClass(Reduce.class);

Combiner 단계가 MapReduce의 데이터 흐름에 포함되었다.

Page 34: II. Hadoop¹…데이터1031_6x9_9... · 그런데 이때 Nutch 가 가져오는 방대한 데이터를 처리할 길이 없어 난감해 하던 차에 2004년 Google이 발간한

Sort:

각각의 reduce task 는 여러 개의 중간 key 에 관련된 value 를 합산(reduce)한다. 개별 node 에서의

일련의 중간 key 는 Hadoop 이 이를 자동으로 정렬한 후 Reducer 에게 보내진다.

Reduce:

각각의 reduce task 에 대해 Reducer instance 가 만들어진다. Reducer instance 는 사용자가

생성시키는 것으로서 job 별로 중요한 2 번째 단계가 된다. Reducer 에게 할당된 partition 에서의 각각의

key 에 대해 Reducer 의 reduce() method 는 단 한번 호출되는데 이를 통해 key 에 연결된 모든 value 에

대한 iterator 와 key 를 받는다. iterator 에 의해 하나의 key 와 이에 관련된 value 들이 반환될 때 그

순서는 무작위이다. Reducer 는 또한 OutputCollector 와 Reporter object 를 파라미터로 받게 되는데

이들은 map() method 에서와 같은 방식으로 이용된다.

OutputFormat:

OutputFormat 은 Hadoop 이 파일 기록에 이용하기 위해 제공되는 것으로서 일반적인

FileOutputFormat 에서 상속된 것이다.

OutputCollector 에게 제공되는 (key, value) pair 는 출력파일에 기록된다. 이때 실제 기록되는 방식은

OutputFormat 에 따라 다르지만 기본적으로 앞서의 InputFormat class 와 같은 방식으로 동작한다. 즉,

Hadoop 이 제공하는 OutputFormat 의 instance 가 로컬디스크 또는 HDFS 상의 파일에 기록된다. 각각의

Reducer 는 각 파일을 일반적인 출력 디렉토리에 기록될 때 통상 part-nnnnn 라는 이름을 가진다. (여기서

nnnnn 는 reduce task 와 관련된 partition id 이다.)

출력 디렉토리는 FileOutputFormat.setOutputPath() method 에 의해 결정된다.

특별한 OutputFormat 을 사용하려는 경우에는 MapReduce job 을 정의하는 JobConf object 의

setOutputFormat() method 를 통해 지정한다.

OutputFormat 설명

TextOutputFormat Default; line 을 "key \t value" 형태로 기록한다

SequenceFileOutputFormat 뒤에 오는 MapReduce job 으로 읽어 들이기에

적당한 형태의 바이너리 파일로 기록한다.

NullOutputFormat 입력을 무시한다

디폴트 상태의 instance 는 TextOutputFormat 으로서 텍스트파일의 각 line 에 (key, value) pair 를

기록한다. 이를 나중에 MapReduce task 를 통해 KeyValueInputFormat class 로 다시 읽어들일 수

있는데 이는 사람도 읽을 수 있다.

Page 35: II. Hadoop¹…데이터1031_6x9_9... · 그런데 이때 Nutch 가 가져오는 방대한 데이터를 처리할 길이 없어 난감해 하던 차에 2004년 Google이 발간한

MapReduce job 들 상호간에 이용되는 또 다른 포맷이 SequenceFileOutputFormat 인데 이는 임의의

데이터 타입을 파일로 신속하게 serialize 해 주는 기능을 한다. 이에 대응되는 SequenceFileInputFormat

은 파일을 같은 타입으로 deserialize 하고 앞서의 Reducer 가 산출했던 것과 같은 방식으로 다음

Mapper 에게 전달한다.

NullOutputFormat 은 아무런 출력파일을 만들지 않으며 OutputCollector 에 의해 전달받은 (key,

value) pair 를 무시한다. 이는 reduce() method 에서 독자의 출력파일에 기록하고 있어서 Hadoop

프레임워크에 의해 추가의 빈 출력파일이 만들지 않으려는 경우 유용하다.

RecordWriter:

InputFormat 이 실제로 개별 레코드를 RecordReader 실행을 통해 읽는 것과 마찬가지로

OutputFormat 클래스도 RecordWriter object 에 대한 factory 역할을 한다. 이들은 OutputFormat 에

지정된 대로 개별 레코드를 파일에 기록하는데 이용된다. Reducer 에 의해 작성된 출력파일은 HDFS 에

남아있으므로 다른 MapReduce job 또는 별도의 프로그램 또는 사용자의 직접개입을 통해 이용할 수 있다.

라. Task의 투기적 실행

NFS 및 AFS 같은 분산파일시스템에서 간혹 로컬파일시스템보다 오히려 성능이 훨씬 늦은 것처럼 보이는

경우가 있다. 이는 여러 노드와 CPU 간에 cache 메모리의 내용을 동기화 (이를 cache coherence 라고

부른다)하고 데이터 안전을 확보하기 위해 I/O 작업을 조정 (일종의 synchronous I/O)하기 때문이다.

성능을 개선하기 위해 장착된 cache 메모리가 오히려 여러 컴퓨터 간의 내용 동기화 필요성에 따라

부담으로 작용하는 것이다.

Hadoop 에서도 문제가 된 것중의 하나가 task 를 여러 node 가 나누어 실행할 때 처리속도가 늦은 일부

node 가 전체 시스템의 성능을 저하시키는 문제였는데 하드웨어 문제, 소프트웨어 설정 (configuration)의

오류 등 그 이유는 여러가지가 있을 수 있다. 특히 문제가 되는 것은 오히려 프로그램이 정상적으로 종료될

때 이를 찾아내기가 더욱 어려워진다는 점이다.

Hadoop 은 이처럼 task 가 당초 예정된 시간보다 오래 걸릴 경우 아예 새로운 task 를 다시 수행시키는

방법을 취한다. 일종의 백업개념인 셈이다.

예컨대 만약 Hadoop 클러스터 내의 한 node 컴퓨터가 매우 낮은 속도의 디스크 콘트롤러를 가져서 다른

node 에 비해 10% 의 속도밖에 나지 않는다고 하자. 이 경우 다른 99 개의 map task 가 이미 수행을

종료했는데도 마지막 하나의 map task 가 끝나기를 기다리게 될 것이다.

이 경우 추가의 task 를 독립적으로 수행시키고 개별 task 는 자신의 입력이 어디에서 제공되는지를

모르게 한다. Task 들은 단지 Hadoop 플랫폼만을 신뢰하고 자신의 입력과 처리된 출력결과만을

Hadoop 과의 협력하에 제공하게 된다. 결과적으로 동일한 입력이 동시에 여러 번 처리하게 되며 Job 에서의

대부분의 task 가 종료됨에 따라 Hadoop 은 잔여의 task 중 중복된 (redundant) task 를 더 이상 할 일이

없는 나머지 node 에 분배(schedule)한다.

Page 36: II. Hadoop¹…데이터1031_6x9_9... · 그런데 이때 Nutch 가 가져오는 방대한 데이터를 처리할 길이 없어 난감해 하던 차에 2004년 Google이 발간한

이러한 작업 프로세스를 투기적 실행 (speculative execution)이라고 하는데 만약 task 가 완료되면 이

사항을 JobTracker 에게 알린다. 여러 개의 중복된 task 에서 먼저 종료된 task 가 실제 수행자로

확정되는데 이를 definitive copy 라고 부른다. 만약 이때에도 다른 중복 task 가 투기적 실행을 하고 있다면

Hadoop 은 TaskTracker 로 하여금 이들 task 및 그 결과를 포기, 무시하라고 지시한다. Reducer 는 결국

가장 먼저 완료되어 도착하는 Mapper 로부터의 입력사항만 받아들이게 된다.

투기적 실행은 default 상태에서 활성화되어 있지만 JobConf 의 option 중 다음 2 개 항목을 false 로

하여 비활성화 할 수 있다. 이전 버전의 Hadoop 의 경우:

mapred.map.tasks.speculative.execution

mapred.reduce.tasks.speculative.execution

새 버전에서는 JobConf 의 option 중 다음을 false 로 설정하면 된다.

mapreduce.map.speculative

mapreduce.reduce.speculative

Page 37: II. Hadoop¹…데이터1031_6x9_9... · 그런데 이때 Nutch 가 가져오는 방대한 데이터를 처리할 길이 없어 난감해 하던 차에 2004년 Google이 발간한

4. Hadoop 설치운영과 프로그래밍

(1) Hadoop의 설치와 운용

가. 설치

권장 기기 사양

그 동안 소위 저가 하드웨어(commodity server)로 표현되어 왔던 하드웨어에 대해 Hadoop 이 권장

(또는 용인)하는 것은 없다. Hadoop 의 설계원칙을 생각할 때 Linux 를 적용할 수 있는 정도라면 구형

서버나 심지어 PC 도 적용 가능하다. 다만, 전체 시스템의 안정성과 효과적 운영을 생각한다면 Hadoop 의

하드웨어 시스템 역시 최소한의 성능과 안정성을 갖출 필요가 있으므로 다음과 같은 사양을 권장한다.

mid-level rack 타입의 서버

듀얼 socket, ECC RAM 메모리

네트워크 카드: 기가비트 급 Ethernet 권장

단, DataNode 서버에는 RAID 를 적용하지 않아야 한다. HDFS 에서 파일복제와 에러체킹 기능을 이미

구현하고 있으므로 이를 중복 지정할 때 발생되는 혼란을 피하기 위함이다. 다만 NameNode 에는 RAID 와

같은 신뢰성 향상 장치가 얼마든지 허용되고 권장된다.

일반적으로 Xeon processors 1.8-2.0GHz 이상으로 하되 Hadoop job 이 core 당 1 ~ 2 GB RAM 소모.

(Python 등 script 사용 시 메모리 추가 소요)하므로 이에 의거하여 충분한 메모리 장착을 권고한다.

또한 일정한 수 (복수)의 HDD 를 가지는 시스템 여러 대가 바람직하다 Hadoop 은 기본적으로 I/O-

bound job 을 주로 수행하기 때문이다.

설치 요건사항

Java 환경: Sun Java 1.6 이상

운영체제: 가급적 Linux를 권고한다. (cygwin을 설치하면 MS Windows에서도 Hadoop이용이 가능하

긴 하다)

다운로드 및 설치

Hadoop 을 설치하는 방법은 크게 Apache 프로젝트 사이트에서 다운로드하여 설치하는 방법과 Cloudera

또는 Hortonworks 와 같은 독자적 배포판(CDH)을 이용하는 방법이 있다. 이는 마치 Linux 에서

RedHat 의 Enterprise Linux, Fedora, Ubuntu 등의 다양한 배포판이 있는 것과 같은데 모두 동일한

오픈소스 기반이며 단지 Hadoop 관련 프로젝트의 조합과 이에 대한 테스트 절차 및 패키징이 다를 뿐이다.

독자배포판을 이용하는 것이 여러 가지로 편리하지만 여기서는 예시의 목적으로 Apache 프로젝트

사이트에서 다운로드 설치하는 방식을 개략적으로 기술한다.

Page 38: II. Hadoop¹…데이터1031_6x9_9... · 그런데 이때 Nutch 가 가져오는 방대한 데이터를 처리할 길이 없어 난감해 하던 차에 2004년 Google이 발간한

http://hadoop.apache.org/releases.html#Download 에서 다운로드하고 압축을 푼 후(gunzip)

다음과 같이 설치한다.

$ tar -zxf hadoop-1.0.8.tar.gz

$ chmod -R g-w hadoop-1.0.8/

root 권한으로 unpack 된 내용을 적당한 위치 (예컨대 /usr/local)로 옮긴다

$ sudo mv hadoop-1.0.8 /usr/local/

$ cd /usr/local

$ sudo chown -R root:root hadoop-1.0.8/

이제 설치가 완료되었으며 설정사항의 변경이 필요한 경우 conf/hadoop-env.sh 및 hadoop-site.xml 를

이용한다.

HDFS의 환경설정(configuration)

Hadoop 설치 디렉토리 밑의 conf/hadoop-defaults.xml 파일에는 각종 데몬 프로그램의 지정, 복제본

갯수(replication factor)또는 Block size 등 다양한 환경설정 값이 key-value pair 의 형태로 저장되어

있다.

<property>

<name>property-name</name>

<value>property-value</value>

</property>

따라서 설정 값의 변경이 필요하다면 이곳에서 바꾸어주면 된다.

나. Hadoop Cluster의 운영환경

Hadoop 클러스터는 기본적으로 다음 3 가지 운영모드 중 하나를 선택할 수 있는데 이들은 각각

“개발”, ”확산준비(staging)”, “운영(production)”의 3 개 단계에 해당한다고 할 수 있다.

Local (standalone) 모드 – 디폴트 모드로서 아래의 설정파일은 모두 빈 파일로 설치된다. 이때는 파일

시스템도 HDFS를 사용하지 않고 Hadoop의 각종 데몬 프로그램도 수행되지 않을 뿐 아니라 모든 프로

세스는 단 하나의 JVM 위에서 수행된다. Linux 명령어를 이용해서 파일작업을 하게 되는데 주로

MapReduce 프로그램을 처음 개발하거나 디버깅 하는 용도로 사용된다.

Pseudo-distributed 모드 – 정식의 Hadoop 클러스터 모드이지만 단지 물리적으로 서버 한 대에 모아

놓은 것을 말한다. 따라서 Hadoop의 HDFS 파일시스템도 이용되고 모든 데몬도 수행된다. 각각의 데몬

은 별도의 JVM 위에서 수행되며 한대의 서버임에도 불구하고 데몬 상호간에는 SSH 프로토콜로 통신을

한다. 뿐만 아니라 각 서비스 마다 별도의 로그파일이 생성되는 등 한대의 서버 내에서도 마치 이 모든

것들이 분산환경인 것처럼 동작한다.

Fully Distributed 모드 – 완벽한 Hadoop의 분산클러스터 환경이다. 즉, master node와 backup 서

버 그리고 DataNode, TaskTracker 데몬 등이 독립적으로 분산환경에서 동작한다.

한편 이들은 모두 다음 3 개 설정파일의 내용을 변경함으로써 가능하다.

Page 39: II. Hadoop¹…데이터1031_6x9_9... · 그런데 이때 Nutch 가 가져오는 방대한 데이터를 처리할 길이 없어 난감해 하던 차에 2004년 Google이 발간한

core-site.xml

hdfs-site.xml

mapred-site.xml

한편 빅데이터의 Hadoop 클러스터는 상대적으로 매우 큰 시스템으로 운영되는 경우가 많다. 수 십대는

기본이고 수 백대 또는 수 천대에 이르는 경우도 흔하다. 이 때 수 십대 rack 이 동원된다면 rack topology

설계 역시 중요하다. 대규모 환경에서는 가상화 엔진을 적용할 수도 있다. 아래 그림은 이러한 multi-rack

환경을 나타내고 있다.

대규모 Clusters: (수 백 대 이상)의 Multiple Rack 환경

위와 같은 경우 Rack awareness 의 문제가 발생한다. 이러한 것을 rack-aware placement 정책이라고

하며 multi-rack 에서 block 의 replica 의 분산에 따른 데이터 손실이 없도록 하려는 것이다.

Hadoop 에서는 DNSToSwitchMapping 이라는 interface 를 이용해서 rack topology 에 대응하도록

java 프로그램을 작성한다. 또는 사용자 스크립트가 각 노드에서 수행되도록 디폴트 mapper 를 이용한다.

Page 40: II. Hadoop¹…데이터1031_6x9_9... · 그런데 이때 Nutch 가 가져오는 방대한 데이터를 처리할 길이 없어 난감해 하던 차에 2004년 Google이 발간한

(2) Hadoop 프로그래밍

가. 개발도구

Eclipse를 이용

Eclipse 용 MapReduce plugin 을 추가하여 사용할 수 있다.

NetBeans 이용

NetBeans 에도 MapReduce plugin 이 있으므로 이를 사용할 수 있다.

나. Java와 다른 언어의 혼용

Unix/Linux 에서 pipeline 개념은 여러 처리작업(모듈)을 서로 연결(chain)시키는 것을 말한다. 15 또한

이와 관련된 개념으로 Message queue 라는 것도 있는데 이는 하나의 작업을 위해 여러 프로세스가 상호

협력하는 경우 이들 프로세스간의 통신 (IPC: inter-process communication) 방법의 하나로서 이들

(processing primitives) 사이의 동기화를 담당한다. 이 방식을 취할 경우 프로그래머는 자신이 원하는

결과를 얻기 위해 전체적인 처리방식을 먼저 설계한다. 그런 후 이를 몇 개의 작은 처리방식으로 나누고

15 Linux 에서의 pipeline 란 하나의 프로그램에서 처리된 결과물을 다른 프로그램을 넘겨주고 그로 하여금 처리하게 하는

것으로서 pipe 라고도 한다. 예를 들어 다음이 people.txt 라는 이름의 파일이 있다고 가정한다. (즉, 성(성), 이름, 나이,

우편번호, 전화번호 의 4 개의 column 으로 구성됨)

김 철수 38417-941555-1212

Nixon Nixon 26138-705916-5763

신 민아 19407-051246-3457

김 영희 47135-601674-6972

김씨 성을 가진 사람을 모두 모아서 우편번호의 순서로 정렬하고자 하는 경우 다음과 같이 처리할 수 있다.

grep 김 people.txt > grep.out

sort +3 grep.out

rm grep.out

Page 41: II. Hadoop¹…데이터1031_6x9_9... · 그런데 이때 Nutch 가 가져오는 방대한 데이터를 처리할 길이 없어 난감해 하던 차에 2004년 Google이 발간한

순서대로 늘어 놓아 단계적으로 수행하게 된다. 이 때 앞 단계 (producer)의 처리결과를 뒷 단계

(consumer)에게 전달하는 방식이 된다.

다. Hadoop 클러스터의 관리

HDFS에서의 Node 퇴출 (decommissioning)

다음의 절차에 따라 특정 node 를 퇴출하거나 재 등록 할 수 있다.

Step 1: 클러스터 configuration의 excludes 파일을 이용한다. 즉, conf/hadoop-site.xml 파일에

dfs.hosts.exclude 키를 추가하고 NameNode의 파일에 해당하는 경로를 지정한다.

Step 2: decommission할 호스트를 결정한다. 즉, dfs.hosts.exclude에 해당 기기를 등록함으로써

NameNode에 연결되는 것을 방지한다.

Step 3: 설정정보를 reload시키기 위해 다음 명령을 수행한다.

bin/hadoop dfsadmin -refreshNodes.

bin/hadoop dfsadmin –refreshNodes

Step 4: 노드를 Shutdown한다. decommission 후 그 H/W는 shutdown가능하다. 이때

bin/hadoop dfsadmin -report 명령을 이용하면 현재 연결된 노드의 목록을 볼 수 있다.

Step 5: excludes 파일을 재 수정한다. 일단 decommission되면 excludes 파일로부터 다시 제거한

다.

(3) 결론

가. Hadoop 플랫폼

Hadoop 은 많은 관련 프로젝트를 통해 하나의 생태계를 구성했으나 프로젝트 중 몇가지는 보완적인

성격을 가지고 있으며 아울러 다음과 같이 각종 도구간에 직간접적인 연계작업이 가능하도록 되어 있다.

Page 42: II. Hadoop¹…데이터1031_6x9_9... · 그런데 이때 Nutch 가 가져오는 방대한 데이터를 처리할 길이 없어 난감해 하던 차에 2004년 Google이 발간한

나. HPC vs. 빅데이터

슈퍼컴퓨터가 빅데이터에 기여한 만큼이나 차이점 또한 분명하다. 즉, 빅데이터에서는 데이터의 입출력을

효율화하기 위해 컴퓨터 I/O (입출력)에 많은 중점을 두는 반면 수학/과학연산 및 공학계산 등을 중심으로

하는 Technical 컴퓨팅은 분산 시스템만으로는 해결이 어려운 경우가 많다. 고성능의 CPU 동원과 이들의

병렬처리가 불가피하며 이를 위해 Lustre 파일시스템과 같은 병렬파일시스템이 흔히 이용된다. 뿐만 아니라

흔히 이용되는 가상 메모리뿐만 아니라 계산의 효율을 위해 불가피하게 많은 real 메모리가 소요되기도 한다.

최근 병렬 프로세싱에도 빅데이터의 기술을 혼용하려는 여러 가지 노력이 경주되고 있으나 기술의 원천과

개발목적 상 빅데이터 기술과 HPC 상에는 여전히 큰 차이점이 존재하는 것이 사실이다.

다. Hadoop이 적합한 영역

다음의 경우가 Hadoop 을 적용하기에 적합한 대표적인 예이다.

복합형 (Complex) 데이터

데이터의 소스가 여러 곳인 경우

데이터의 양이 많은 경우

Batch 처리가 가능한 경우

병렬처리가 가능한 경우

클러스터 내의 여러 node로 데이터를 분배할 수 있는 경우

실제로 log 파일의 분석, 고객데이터 분석, 검색엔진에서의 index 작업, 텍스트 분석 (text analytics

– 문맥분석, cluster 분석, 문서분류 등) 유전자 배열, 이미지 분석 등에 큰 효과를 보고 있다.

라. Hadoop이 적합하지 않은 영역

수치계산 (예; 구조해석, 시뮬레이션, Fibonacci sequence의 계산 등)과 CPU나 메모리의 집중적 활용

이 요구되는 (좁은 의미의 슈퍼컴퓨터) 영역에서는 큰 효과를 보지 못하고 있다.

정형화된 (Atomic) 데이터를 중심으로 하는 경우에는 일반적인 RDBMS를 이용하는 것이 효율적이다.

(대신 구조화된 데이터를 대상으로 개발된 Hadoop 프로젝트로서 HBase가 있다. 이에 대해서는 뒤에

논의)

결론적으로 볼 때

데이터 중심의 작업 특히 dataset의 변환을 하는 경우에는 두 단계로 나누어 작업하는 것이 효과적이다.

CPU-bound 작업의 경우 분산컴퓨팅의 이점을 크게 발견하기 힘들다.

RDBMS나 DW의 역할은 여전히 남이 있다. 그러나 데이터 중심의 작업에서는 Hadoop이 탁월하다.

Page 43: II. Hadoop¹…데이터1031_6x9_9... · 그런데 이때 Nutch 가 가져오는 방대한 데이터를 처리할 길이 없어 난감해 하던 차에 2004년 Google이 발간한

5. Hadoop과 관련된 프로젝트 (Hadoop 생태계)

Hadoop 이외에도 관련된 프로젝트를 다음과 같이 구별해 볼 수 있다.

Hadoop Core: HDFS와 MapReduce로 구성된 Hadoop솔루션

Hadoop 프로젝트: Apache 프로젝트 중 Hadoop과 직접 관련된 프로젝트. 여기에는 Hadoop외에 Pig,

HBase, ZooKeeper, Chukwa를 포함한 많은 프로젝트가 있다. (계속 늘어나고 있다.)

본 장의 이하에서는 각각의 프로젝트에 대해 간략히 살펴보되 데이터마이닝과 기계학습을 위한 Mahout

에 대해서는 장을 달리하여 보다 세부 설명을 한다.16

(1) Pig

Pig 는 Hadoop 에서의 프로그래밍을 보다 쉽게 만들어주는 데이터흐름 중심의 고급 (High-level)

프로그래밍 언어이다. 17

내부적으로는 Pig 가 병렬처리를 통해 Hadoop 의 확장성, 신뢰성 등 고유한 특성을

그대로 유지하며 MapReduce 의 최적화도 자동으로 수행해서 성능을 유지시켜준다.

Pig 는 크게 2 가지 요소로 구성된다.

고급의 데이터처리 언어인 Pig Latin

16 IV. 빅 데이터의 적용실례 ▶ 1. Mahout 를 이용한 빅데이터 분석을 볼 것.

17 SQL 이 최종 출력결과를 중심으로 사고하게 되어있는 반면 Pig 는 알고리즘 중심의 데이터 흐름에 주안점을 둔다.

즉, Hadoop 이 절차와 알고리즘 중심인 반면 SQL 은 선언적 (Declarative) 방식으로 결과를 출력시키는 것이다.

Page 44: II. Hadoop¹…데이터1031_6x9_9... · 그런데 이때 Nutch 가 가져오는 방대한 데이터를 처리할 길이 없어 난감해 하던 차에 2004년 Google이 발간한

Pig Latin으로 만들어진 스크립트 프로그램을 컴파일 하고 수행해주는 제반 환경

PIG Latin 언어의 예 (WordCount)

A = load './input.txt';

B = foreach A generate flatten(TOKENIZE((chararray)$0)) as word;

C = group B by word;

D = foreach C generate COUNT(B), group;

store D into './wordcount';

Pig 에서는 데이터 변환 작업을 Pig Latin 으로 작성하게 되는데 여기에는 filter, union, group, join 등이

모두 포함된다.

Pig Latin 을 수행하는 방법에는 다음의 3 가지가 있다.

대화형 명령어 방식 (grunt shell)

Pig Latin을 이용하여 스크립트 프로그램의 작성

Java 프로그램에 Pig Latin을 내장하여 사용

Pig Latin 은 상당히 직관적 명령어이고 SQL 질의어와도 상당히 유사하다. 간단한 예를 살펴 본다.

log = LOAD ‘excite-small.log’ AS (user, time, query);

grp = GROUP log BY user;

counter = FOREACH grp GENERATE group, COUNT(log);

DUMP counter;

위 예에서는 excite-small.log 파일을 적재한 후 사용자 별로 분류하고 각 사용자 별 출현빈도를

출력하였다. Pig 는 이처럼 데이터 흐름, 즉, 데이터 처리 알고리즘 구현을 중심으로 한 독자적인 명령어

체계를 가지고 있을 뿐 아니라 자체의 데이터 타입18도 가지며 필요 시 사용자가 별도로 함수를 작성하여

(UDF: user-defined functions) 사용할 수도 있다.

(2) Hive

Hive 는 hadoop 에 기반한 데이터웨어하우스이다. Hive 는 DW 계층이 Hadoop 의

18 Pig 라는 이름은 돼지가 무엇이든 잘 먹는다는 의미에서라고 한다. 어떤 데이터이든 입력 받아서 부지런히 처리할 수 있는

효율적인 언어라는 뜻으로 해석할 수 있겠다.

Page 45: II. Hadoop¹…데이터1031_6x9_9... · 그런데 이때 Nutch 가 가져오는 방대한 데이터를 처리할 길이 없어 난감해 하던 차에 2004년 Google이 발간한

구성모델 (HDFS 및 MapReduce) 위에 탑재된 형태이므로 빅데이터 처리에 최적화되어 있다. 즉,

실행면에서 MapReduce 를, 데이터 저장장치의 측면에서는 HDFS 에 기반하면서 각종의 질의어를 제공한다.

Hive 의 가장 큰 설계원칙은 대규모이면서도 rich data type 의 구조화된 데이터를 관리하는 것이다.19

Hadoop 초기부터 기존 데이터의 방대함과 이미 많은 사람이 익혔던 관계형 DBMS 에서의 SQL 을 어떻게

할 것인가를 두고 많은 논의가 있었다. 그리고 그 결론이 일종의 SQL 파생어 (dialect)로서의 HQL 과 그

하부 DBMS 로서의 Hive 이다. Hive 는 개발자에게 편리하며 HQL 은 분석가가 쉽게 이해할 수 있고 또한

기존 데이터를 이식하는 것도 편리하다. 즉, Hive 의 HiveQL 은 SQL 을 사용해 본 사람이라면 누구나 쉽게

mapper 와 reducer 를 쉽게 이용할 수 있도록 되어 있다.

기본적인 SQL 문 (Select From, Join, Group By, union all 등)과 Join 명령 (Equi-Join, Multi-Table

Insert, Multi-Group-By)은 물론 multitable query 등을 포함하는 SQL primitive 를 제공한다. 나아가

HiveQL 를 확장하여 사용자가 작성하는 aggregation, column 변환, embedded MapReduce script 등도

손쉽게 이용할 수 있다.

외부 인터페이스는 명령어 방식이 중심이지만 필요하다면 브라우저를 통한 WebGUI 도 가능하며 외부

DB 를 JDBC 로 액세스할 수도 있다.

위 그림에서 보듯이 사용자가 (명령어 줄, Web 화면, JDBC/ODBC 등의 외부 데이터베이스 등을 통해)

Hive 에 명령을 주면 Hive 는 이를 해석 (parsing)한 후 메타스토어(metastore)를 참조하여 실행계획을

수립하고 최종적으로 이를 수행한다. Hive 와 함께 배포되는 것이 몇 가지 있는데 CLI, HWI (Hive Web

Interface), JDBC/ODBC, Thrift 서버 등이다. 모든 명령어는 드라이버로 전달되고 여기서 해당명령을

MapReduce job 과 함께 수행한다. 20

19 원래는 Facebook 에서 사용자 및 log 데이터를 분석하려는 목적에서 시작되었는데 Ad hoc 분석, 데이터마이닝, 요약분석,

Spam 탐지 등에 성공적으로 활용되었고 이후 이를 오픈소스화 하였다.

20 Hive 는 다수의 사용자가 이용할 수 있도록 메타데이터를 자체의 관계형 데이터베이스에 저장하고 관리한다. 사실

Hadoop 은 Apache 프로젝트로서 관계형 DBMS인 Derby 를 이용하는데 실제 Hive 의 Metastore 는 metastore_db 라는

이름의 데이터베이스로 관리된다.

Page 46: II. Hadoop¹…데이터1031_6x9_9... · 그런데 이때 Nutch 가 가져오는 방대한 데이터를 처리할 길이 없어 난감해 하던 차에 2004년 Google이 발간한

Hive 는 수행 전과정을 통해 JobTracker 와 통신하고 데이터는 HDFS 에서 관리하지만 테이블

schema 와 기타의 시스템 메타데이터는 MetaStore 라는 별도의 RDB 에 저장하고 관리한다.

Hive 는 다음의 3 가지 데이터 구성요소를 가진다.

Table: Hive 은 RDBMS 에서의 table 과 마찬가지로 row 와 column 으로 구성된다. 그러나

Hive 는 기본적으로 Hadoop HDFS 를 이용하고 단지 필요시 다른 파일 시스템에 존재하는

table 을 가져 올 수 있도록 되어 있다.

Partition: Hive 에서의 table 은 하나 또는 여러 개의 partition 을 지원한다. 이들 partition 은

하위 파일시스템에서의 디렉토리에 대응된다. 예를 들어 autos 라는 이름의 table 이 있다면 key

값이 12345 이고 그 제조업자가 Hyundai 라면 해당 partition 에 대한 경로는

/hivewh/autos/kv=12345/Hyundai 가 된다.

Bucket: 데이터는 여러 개의 bucket 으로 구성된다. Bucket 은 partition 디렉토리 내의

파일로서 저장된다. 이때 bucket 은 테이블 내의 column 에 대한 hash 값에 의거하여 관리된다.

앞서 예에서 Hyundai 라는 이름의 bucket 을 가지게 될 것이고 여기에 관련 자동차의 속성이

간직될 것이다

Hive 의 metadata 는 “metastore”라는 외부에 별도 저장된다. metastore 는 column type, owner,

key 및 해당 데이터 값과 같은 Hive 의 schema 세부사항을 간직하는 관계형 데이터베이스로서 catalog

데이터를 Hadoop 전체 프레임워크 내의 다른 메타데이터 서비스와 동기화시켜주는 역할을 한다.

앞서 MapReduce 설명 시 예제 프로그램으로서 WordCount 예제를 살펴볼 때 MapReduce 로 구현한

우리의 프로그램은 약 50 여 줄을 차지하였다. 이제 이를 Hive 의 질의어인 HQL 로 수행한다면 그 명령은

다음과 같다. 질의어 형태로 단 7 줄의 HQL 로 가능해졌다.

CREATE TABLE docs (line STRING);

LOAD DATA INPATH 'docs' OVERWRITE INTO TABLE docs;

CREATE TABLE word_count AS

SELECT word, count(1) AS count FROM

(SELECT explode(split(line, '\s')) AS word FROM docs) w

GROUP BY word

ORDER BY word;

또 다른 예를 통해 Hive 의 사용법을 보기로 한다.

Hive> CREATE TABLE customer (cust_no INT, order_no INT)

> ROW FORMAT DELIMITED

> FIELDS TERMINATED BY ‘,’

> STORED AS TEXTFILE;

Ok

Time taken: 0.12 seconds

Page 47: II. Hadoop¹…데이터1031_6x9_9... · 그런데 이때 Nutch 가 가져오는 방대한 데이터를 처리할 길이 없어 난감해 하던 차에 2004년 Google이 발간한

이처럼 SQL 문과 유사한 다양한 명령어가 제공된다.

한편 Hive 의 데이터 모델은 일반 데이터베이스와 다른 특징을 가진다. 즉, 각각의 테이블은 디렉토리로서

관리된다. 즉, 위의 ‘customer’라는 이름의 테이블이 있다면 이는 디폴트 디렉토리인

/user/hive/warehouse/customer 라는 형식으로 저장된다. 뿐만 아니라 관계형 DB 에서 column 별로

index 를 설정하는 것과는 달리 Hive 에서는 column 을 partition 별로 나누어서 관리한다. 위의

‘customer’ 테이블이 ‘last_name’과 ‘register_date’라는 2 개의 partition column 으로 구성되어 있다면

Hive 의 디렉토리 구조는 다음과 같이 된다.

/user/hive/warehouse/customer/last_name=kim/register_date=201201

/user/hive/warehouse/customer/last_name=kim/register_date=201202

/user/hive/warehouse/customer/last_name=lee/register_date=201201

/user/hive/warehouse/customer/last_name=lee/register_date=201202

Partitioning 은 이외에도 매우 다양한 방법으로 Hive 에서 활용하고 있다. 또한 bucket 이라는

hashing 기반의 데이터 구분법도 이용함으로써 방대한 데이터의 경우에도 full scan 하지 않도록 함으로써

성능을 극대화시킨다.

한편 Hive 는 엄밀한 의미에서의 데이터베이스라고 할 수 없다는 견해도 있는데 이는 Hadoop 과

HDFS 가 가진 설계사상에 따른 어쩔 수 없는 특징이다.

우선 Hive는 record 단위로 수정, 추가, 삭제를 할 수 없다.

또한 Hadoop이 batch 처리 중심이다 보니 Hive에 대한 질의 시 응답시간 (latency time)이 길어지게

되었다. 이들 각각의 질의에 대해 MapReduce 처리를 하다보니 생기는 오버헤드 때문이다.

Hive에서는 transaction 처리를 지원하지 않는다. 따라서 OLTP에 적용이 어렵고 OLAP에의 이용이 중

심이 된다.

요컨대 Hive 는 데이터웨어하우스 업무 즉, 변경의 필요가 크지 않고 즉각적 응답이 필요하지 않은 정적

데이터 분석 시에 적합하다 하겠다. 다만 일반 DW 와 달리 batch 처리 중심이므로 Hive 는 즉각적 결과도출

보다는 수 분 ~ 몇 시간 정도 소요되더라도 보다 복잡한 분석을 하는 경우에 유용하다. 대신

Hadoop 기반이어서 일반의 DW 보다 훨씬 더 확정성이 크고 매우 견고한 시스템이라 하겠다.

(3) HBase

HBase 는 Google 의 BigTable 을 참조로 개발된 Hadoop 의 HDFS 위에서 실행되는 비관계형

분산데이터베이스이다. HBase 과 Hadoop 은 상호보완적이다. 우선 Hadoop 의 장점을 그대로 이용한다.

장애극복 (Fault tolerance)

확장성

MapReduce를 이용한 Batch처리

Page 48: II. Hadoop¹…데이터1031_6x9_9... · 그런데 이때 Nutch 가 가져오는 방대한 데이터를 처리할 길이 없어 난감해 하던 차에 2004년 Google이 발간한

한편 HDFS 가 가진 random read/write 가 되지 않는다는 단점을 극복한다. 즉, 저장기능으로서의

HDFS 를 이용하면서도 log 기록기능을 구현하고 이를 HDFS 파일에 결합(merge)하는 방식으로 random

read/write 기능을 보완한다.

HBase 에 있는 테이블은 Hadoop 의 MapReduce 작업에 대한 입력 또는 출력항목이 될 수 있다. 또한

Java API 또는 REST, Avro 및 Thrift gateway API 를 통해 HBase 를 접속할 수도 있다.

HBase 자체의 장점을 요약하면 다음과 같다.

데이터 크기가 Giga바이트~Peta바이트급에 이르는 데이터 저장

매우 높은 write throughput

cache 용량이 대폭 증가 – 노드 추가 시 cache 크기가 커진다.

Data layout - key lookup에서 뛰어난 효과, sparse columns에 대해서도 특별한 성능 손실이 없다.

이해를 명확히 하기 위해 HBase 와 RDBMS 를 비교하면 다음과 같다.

Page 49: II. Hadoop¹…데이터1031_6x9_9... · 그런데 이때 Nutch 가 가져오는 방대한 데이터를 처리할 길이 없어 난감해 하던 차에 2004년 Google이 발간한

RDBMS HBase

사용모드 대화형 및 Batch 방식 Batch 방식 중심

데이터 형태 (layout) Row 중심 Column 중심

거래처리

(transactions)

처리에 적합 단일 row 중심 거래처리

(현재)

질의언어 (Query) SQL get/put/scan 등의 명령어

Index 임의의 column 에

적용

Row-key 에만 적용

Schema 정적인 Schema 동적인 Schema

Update 여부 Read & write many

times

Write once, read many

times

보안 Authentication/

Authorization

별도의 보안기능 없음

이용가능한 최대

데이터 크기

Terabyte 급 Petabyte 급 (선형(linear)

확장이 가능하다)

Read/Write 의

throuput 한계치

수 천개 query 처리/초 수 백만개 query 처리/초

HBase 는 현재 많은 오픈소스 프로젝트와 yahoo!, Adobe 를 비롯한 수많은 기관에서 사용하고 있다. 21

SQL에서의 Join

SQL:

INSERT INTO TABLE pv_users

SELECT pv.pageid, u.age

FROM page_view pv JOIN user u ON (pv.userid = u.userid)

21 마찬가지로 BigTable 도 2004 년 Google 에서 개발된 이래로 Google Maps, Gmail, YouTube 등에서 활발하게 사용되고

있다.

Page 50: II. Hadoop¹…데이터1031_6x9_9... · 그런데 이때 Nutch 가 가져오는 방대한 데이터를 처리할 길이 없어 난감해 하던 차에 2004년 Google이 발간한

MapReduce에서의 Join

(4) ZooKeeper

개요

ZooKeeper 는 Google 의 Chubby 를 참조하여 개발한 분산 시스템 자원 조정 (coordination)

서비스로서 설정정보, naming 등에 대한 분산 동기화 및 그룹 서비스를 제공한다.

당초 Yahoo!에서 ZooKeeper 를 개발하게 된 동기는 다음과 같다.

(1) 우선 multithreaded 프로그램에서 수 많은 thread 를 관리하고 조정하기 위해 lock 이 필요하다.

(2) 또한 시스템의 규모가 커지면 lock 을 분산환경에서 관리하도록 할 필요가 있다. 특히 scale-out

환경에서 다음 기능이 중요해진다.

분산 lock

분산 queue

Group membership

Master 의 선출

분산 configuration

기타의 기능:

여기서 기타의 기능이란 다음 기능을 포함한다.

작업을 순서에 따라 진행하도록 관리한다. 분산환경에서 일부 지체되는 task 가 있을 수 있기

때문이다.

Page 51: II. Hadoop¹…데이터1031_6x9_9... · 그런데 이때 Nutch 가 가져오는 방대한 데이터를 처리할 길이 없어 난감해 하던 차에 2004년 Google이 발간한

Update 사항이 atomic 하도록 할 것. 즉, 성공 또는 실패 중 하나만 있을 뿐 부분수정상태는

있을 수 없다. (“either succeed completely or fail completely”)

또한 일단 진행된 변경사항은 지속될 것. 즉, 기기 장애 등의 경우에도 기 발생된 변경사항은

지속 (persist)될 것

ZooKeeper의 데이터 모델 과 znode

계층적 파일시스템 구조를 가지며 계층구조 (tree) 내에서의 Node 를 znode 라고 부른다. 이러한 znode

는 데이터를 가지기도 하고 다른 znode 를 포함하기도 한다. 또한 모든 Znode 는 일정한 경로 상에

위치하고 UNIX 스타일의 경로정보를 가진다. (예: /rock/punk)

한편 znode 의 종류는 다음과 같으며 이는 znode 생성 시에 지정된다.

Persistent 형 - 별도로 삭제하지 않는한 지속된다.

Ephemeral 형 - 자신을 생성한 client 의 session 에 따라 존속유무가 결정된다.

순차적 Znode: Znode 는 선택적으로 sequence 번호를 가질 수 있다. (예: foo-

0000000001) 이러한 sequence 번호를 통해 순서를 매길 수 있게 된다.

ZooKeeper의 주요 API

Node 생성 관련

node 존재여부의 검사 / Access the node

node 삭제 관련

Get / set children 및 Get / set data

상태의 동기화, 권한관리 (ACL) 등

ZooKeeper의 2가지 모드

Standalone 모드 - 하나의 ZooKeeper 데몬이 수행됨

Clustered 모드 – 여러 서버가 존재하며 하나는 leader 가 되고 나머지 서버가 follower 가 된다.

Follower 들은 read 요청만 처리한다.

설치와 운용

zookeeper.apache.org 에서 설치파일을 가져 온 후 tar 로 설치한다.

$ tar -zxvf zookeeper-3.4.3.tar.gz

$ cd zookeeper-3.4.3

$ export PATH=$PATH:`pwd`/bin

또 다른 설치방법으로는 미리 패키지로 만들어진 것을 이용하는 방법이다. 즉, CDH (Cloudera’s

Distribution)에도 포함되어 있으므로 yum 또는 apt-get 등을 이용할 수도 있다.

Page 52: II. Hadoop¹…데이터1031_6x9_9... · 그런데 이때 Nutch 가 가져오는 방대한 데이터를 처리할 길이 없어 난감해 하던 차에 2004년 Google이 발간한

설치 후에는 다음처럼 환경을 설정하거나 설정사항을 변경할 수 있다.

# NOTE: we’re in the zookeeper-3.4.3 directory

$ cp conf/zoo_sample.cfg conf/zoo.cfg

$ vi conf/zoo.cfg

여기서 .cfg 파일의 중요한 설정 파라미터는 다음과 같다.

tickTime: ZooKeeper 에서의 time 단위

dataDir: 데이터가 저장된 로컬 파일시스템

clientPort: 클라이언트가 접속하는 TCP port

설치 후 ZooKeeper 수행 방법은 tarball 로 설치한 경우 다음과 같다.

$ zkServer.sh start

이와 함께 프로그램 내에서 사용하기 위해서는 다른 라이브러리와 마찬가지로 ZooKeeper JAR 를

프로젝트에 포함시킨 후 API 를 이용한다.

(5) Sqoop

Apache Sqoop 는 데이터베이스와 Apache 사이에서 bulk data 를 (즉, 데이터를 통쨰로) 전달하는

도구로서 일종의 교량 역할을 한다. Sqoop 는 명령어 방식으로 사용하며 일부 데이터만 적재할 수도 있고

(즉, incremental load) 또는 Hive 또는 HBase 에서 SQL 대신 사용하여 테이블을 가져올 수도 있다.

sqoop 의 이용하는 데에는 다음 방식 중 선택하여 사용할 수 있다.

sqoop 명령어를 명령어줄에서 직접 실행

sqoop job에 등록하여 실행

$ sqoop –connect jdbc:mysql://database.example.com/users \

- uername openwith –password net123 –all-tables \

-warehouse-dir/common/warehouse

다음은 Oracle 에서 데이터를 가져오는 또 다른 예이다.

Sqoop import --connect jdbc:oracle:thin:@//dbserver:1521/masterdb

Page 53: II. Hadoop¹…데이터1031_6x9_9... · 그런데 이때 Nutch 가 가져오는 방대한 데이터를 처리할 길이 없어 난감해 하던 차에 2004년 Google이 발간한

--username hr --table emp

--where “start_date > ’01-01-2012’”

Sqoop import jdbc:oracle:thin:@//dbserver:1521/masterdb

--username myuser

--table shops --split-by shop_id

--num-mappers 16

(6) Flume

서버에서 서비스를 실행할 때 많은 로그 파일이 생성된다. 과거 이러한 로그 데이터의 크기로 인해 이를

무시하는 일이 많았으나 이제는 그렇지 않다. Hadoop 과 같은 빅데이터 기술을 이용하면 이를 통해

시스템의 건강을 확인할 수도 있고 동시에 성능개선을 위해 유용하기 때문이다.

Flume 은 대용량 log 데이터를 수집, 운반, 통합하는 분산형 서비스 (distributed

data collection service)이다. Fault Tolerant 기능을 갖추고 있으며 다양한 Fail-over 및

recovery 기능을 제공한다. 원칙적으로 중앙집중형 운영을 하면서도 동적 관리방식을 이용할 수 있게

해주며 이와 관련된 API 를 제공해서 손쉽게 이를 확장할 수 있게 해 준다.

Flume 의 모델은 다음과 같은 요소로 구성된다.

Agent: 데이터를 가져온다

Processor (optional): 필요한 중간처리를 한다.

Collector: 데이터를 저장장치에 기록한다

Page 54: II. Hadoop¹…데이터1031_6x9_9... · 그런데 이때 Nutch 가 가져오는 방대한 데이터를 처리할 길이 없어 난감해 하던 차에 2004년 Google이 발간한

Flume source 는 웹서버와 같은 외부 소스에서 발생시킨 이벤트에 의한 데이터 파일(이를 event 라

부른다)을 받아들이는 역할을 한다. sink 는 event 를 channel 에서 제거하고 이를 HDFS 같은 외부

저장소에 기록하거나 Flume 소스에 전달한다.

(7) 기능별 주요 Hadoop 관련 프로젝트

작업 종류 솔루션 (오픈소스) 비고

데이터의 수집 Flume, Scribe, Chukwa 소스 데이터를 가져옴.

데이터의 저장 NoSQL (HBase, Cassandra, MongoDB),

Data Warehouse

데이터 저장을 통한 persistency

확보

실시간 분석 Storm 일종의 real-time Hadoop

워크플로우 Oozie Job workflow engine

빅데이터 분산처리 Hadoop (HDFS, MapReduce) 분산처리 프레임워크

분석 및 통계 Mahout, R 분석 모델링 및 엔진

관리 및 모니터링 ZooKeeper, Hue 클러스터 관리/자원관리

Serialization Avro, Thrift 객체데이터 및 데이터 전송처리

끝으로 다음 그림에 Hadoop 관련 프로젝트가 일반적 작업 순서에 의거하여 나열되어 있다.22

22 원래의 그림은 Prashanth Babu 이 작성한 것으로 알려짐 (http://nosql.mypopescu.com/post/17715359030/hadoop-

ecosystem-map 에서 재인용)

Page 55: II. Hadoop¹…데이터1031_6x9_9... · 그런데 이때 Nutch 가 가져오는 방대한 데이터를 처리할 길이 없어 난감해 하던 차에 2004년 Google이 발간한