Recommanded Free YOUTUBE Lecture: <% selectedImage[1] %>

Contents

Hadoop에 대해서

아파치 하둡(Hadoop)은 대량의 데이터를 용이하게 처리하기 위해서 분산 컴퓨터 네트워크 기술을 사용하는 오픈 소스 소프트웨어 유틸리티들의 모음이다. 수천개의 노드에서 실행 할 수 있으며, 테라바이트 혹은 페타바이트 단위의 데이터를 저장하고 처리 할 수 있다.

아파치 하둡의 핵심은 HDFS로 알려진 분산 파일 저장소와 분산 프로그래밍 모델인 MapReduce로 구성된다. 하둡은 파일을 블록으로 분할해서 클러스터의 노드에 분산하고, 코드를 노드로 전송해서 병렬로 데이터를 처리한다.

하둡은 다수의 노드로 구성되므로 장애가 발생해도 시스템 중단 없이 운영되도록 구성이 되며, 치명적인 오류로의 확산을 막는다.

 Hadoop 클러스터 구성

Hadoop 아키텍처 개요

2018년 3월 현재 Hadoop 최신 안정 버전은 2.9.0이다. 3.0.0 버전은 알파버전이므로, 현장에서는 주로 1.x와 2.x를 사용하고 있다. 1.x 버전도 여전히 사용하고 있으므로 1.x와 2.x를 비교 설명한다.

 Hadoop 1.x와 2.0의 차이

하둡1.x는 HDFS와 분산 작업 처리를 위한 MapReduce(MRv1)으로만 구성이되며, 하둡기반 솔류션들은 모두 MRv1으로만 분산 명령을 수행 할 수 있다. 하지만 2.x에서는 YARN(Yet Another Resource)이라는 Cluster Resource Manager가 추가되면서 MapReduce 뿐만아니라 다른 솔루션들도 하둡 분산 인프라로 통합할 수 있게 됐다. 하둡 2.x에서는 MapReduce 도 YARN이 실행할 수 있는 데이터 프로세싱 애플리케이션의 하나일 뿐이다.

 Hadoop2 YARN Application

Hadoop 데이터 스토리지

네임노드는 HDFS 파일 시스템에 저장된 파일의 디렉토리를 유지하고, 클러스터에 보관된 데이터의 위치를 추적하기 위한 정보들을 저장하고 있다. 클라이언트 애플리케이션에서 파일을 찾거나 추가/삭제/이동 작업을 할 때마다 네임노드에 작업을 요청한다. 네임노드는 파일을 기본 64MB의 크기로(기본 64MB이며 128MB 이상도 가능하다.) 분할해서 데이터 노드에 분산 저장한다. 예를 들어 블럭의 크기를 128M로 했다면, 248MB크기의 파일은 아래와 같이 두개의 블럭으로 나뉘고

 청크단위로 저장되는 파일

아래와 같이 분산 저장된다. 저장할 때는 2개의 복제본을 만들어서, 노드의 실패에 대응한다.

 분산저장

이러한 모든 정보들을 네임노드가 관리한다. 네임노드가 실패하면, 클라이언트의 요청을 처리 할 수 없을 것이다. 하둡 1.x는 하나의 액티브 네임노드를 가질 수 있다. 모든 정보들은 노드의 메모리에 저장되는데, 네임노드의 데이터가 분산되지 않기 때문에 처리할 수 있는 데이터노드의 갯수가 4,000개로 제한된다. 아래는 하둡 1.x의 아키텍처다.

 단일지점 오류
  1. 하나의 네임 노드만 가질 수 있어서 확장이 어렵다.
  2. 단일 장애점(Single point of failure)이다. 네임노드의 실패는 서비스 장애로 이어진다.
  3. 보조 네임 노드에 백업받아놓은 메타데이터로 네임노드를 재시작 할 수 있지만 그 과정이 쉽지 않다.
하둡 2.x은 YARN을 이용해서 작업을 관리한다. YARN ResourceManager 는 네임노드에설치가 되고, 데이터 노드에는 노드 메니저(Node Manager)이 설치된다. Node Manager는 노드의 상태를 YARN ResourceManager에 보고를 하는데, YARN은 이 정보를 이용해서 전체 클러스터의 노드의 자원상태를 모니터링하게된다. 이 정보는 애플리케이션 실행을 위한 스케쥴러를 작동하는데 사용한다. YARN 아키텍처는 아래와 같다.

 YARN Architecture

AM(Application Master)은 작업(Job)을 실행하고 관리한다. 작업은 어떤 프로그래밍 언어든지 사용 할 수 있으며, 다른 애플리케이션과 격리된 컨테이너에서 수행이 된다. 이 아키텍처는 분산 실행된 AM이 애플리케이션을 관리하기 때문에 Job Tracker 데몬을 사용하는 하둡 1.x 보다 확장성이 좋다.

MapReduce

 MapReduce 란 무엇인가

맵리듀스는 그글에서 대용량 데이터를 분산 처리 하기 위해서 제작한 병렬 처리 소프트웨어 프레임워크다. 이 프레임워크는 페타바이트 이상의 대용량 데이터를 저사양의 컴퓨터로 구성된 환경에서 병렬처리 하기 위해서 개발 했다. 이 프레임워크는 함수형 프로그래밍에서 일반적으로 사용하는 Map과 Reduce 두 개의 함수로 구성된다. 맵리듀스는 HDFS시스템과 연동되도록 제작했다. AWS에서는 HDFS 뿐만 아니라 S3도 사용 할수 있다.

맵리듀스를 사용하기 전에는 전용 스토리지에 저장된 대량의 데이터를 강력한 몇 개의 컴퓨터의 스토리지(하드디스크)로 복사한후 처리하는 방식을 사용했다. 이는 네트워크에 심각한 병목을 초래할 수 있었다. 시스템을 구축하는데 많은 비용이 드는 것도 문제다.

맵리듀스는 데이터를 여러 노드에 병렬로 분산해서 처리를 할 수 있다. 비교적 저렴한 컴퓨터로 작업을 처리 할 수 있으며, 네트워크 역시 훨씬 쉽게 분산 할 수 있다. 또한 클러스터에 있는 노드들을 주기적으로 모니터링해서, 응답이 없을 경우 해당 노드를 클러스터에서 제외하고 데이터를 복원해서, 작업을 계속 처리할 수 있도록 관리한다. 개발자는 Java 뿐만 아니라 C#, Python, C++ 등 다양한 언어를 선택할 수 있다. 그외 Hive, Pig와 같이 맵리듀스를 이용해서 업무를 처리하는 많은 응용 소프트웨어들이 있다.

맵리듀스는 데이터를 옮기는 대신, (가급적)데이터가 저장된 로컬에서 데이터를 처리하므로 데이터 복사에서 발생하는 네트워크문제를 완화할 수 있다. 맵리듀스 작업 방식은 현실세계에서 그 예를 찾아볼 수 있다. 아래 그림을 보자.

 맵리듀스 작업이 데이터 처리에 유리한 이유

한명이 4주를 일해야 완료할 수 있는 작업이 있다고 가정해 보자. 이 일을 1주에 끝내고 싶다면, 4명의 작업자를 고용해서 (적절하게 나눈)작업을 분배하면 된다. 그럼 대략 1주일 정도면 4개의 작업결과가 나올 것이고 이 작업을 관리자가 취합해서 완성하면 된다. Hadoop의 맵리듀스도 동일한 병렬처리 개념을 이용한다.

맵리듀스 작업 단계

맵리듀스는 Key/Value 쌍으로 작동한다. 맵리듀스 프레임워크는 입력 값을 키/값 쌍으로 읽고 그 처리 결과를 키/값 쌍으로 출력한다.

단어들을 포함하고 있는 문서가 있다고 가정해보자. 우리는 단어가 몇 개가 들어있는지를 계산해야 한다. 먼저 이 파일을 HDFS에 저장해야 한다.

 HDFS 에 저장

HDFS에 저장된 파일을 분할(split)한다. 작업을 나누기 위해서 분할하는 단계인데, 예를 들어 하둡의 TextInputFormat는 텍스트 파일의 데이터를 라인단위로 분할 한다. 이렇게 분할된 데이터는 개별 매퍼 인스턴스로 전달된다.

 분할 단계

맵 단계에서는 한번의 한 개의 데이터 요소를 읽어서 역시 키/값 쌍으로 구성된 중간 출력 데이터(intermediate data)를 만든다.

 맵 단계

다음으로 셔플(shuffle)단계로 넘어간다. 셔플은 맵 태스크와 리듀스 태스크의 중간 단계의 전달 과정이다. 셔플과정에서 매퍼의 출력데이터가 파티셔닝 되고 정렬되서, 리듀서의 입력으로 전달된다. 데이터가 정렬이 됐으므로 동일한 키를 포함하는 정렬된 데이터를 얻을 수 있을테고, 쉽게 카운트 연산을 수행 할 수 있을 것이다.

 셔플링 단계

마지막 리듀스 단계에서 모든 값을 집계한다. 리듀서는 입력값을 읽어서 값을 결합해서 단일한 출력 값을 반환한다.

 리듀스

결국 단어(과일이름)이 키이고 카운트가 값인 완전한 결과물이 출력된다.

 최종 결과

맵리듀스 Join

Join은 외래키(foreign key)로 두 개 이상의 데이터베이스 테이블을 결합하기 위해서 사용한다. 예를 들어 고객의 구매 내역을 관리하는 데이터베이스를 만들 경우, 유저 정보를 담고 있는 테이블과 구매정보를 담고 있는 테이블을 서로 분리해서 관리한다. 기업은 두 개의 테이블을 결합(고객 ID로 결합할 것이다.)해서 분석 보고서를 만든다.

 Join

SQL Join과 마찬가지로 맵리듀스도 다른 데이터 세트에 대한 Join 작업을 수행할 수 있다. 맵리듀스는 두 가지 유형의 Join 작업을 수행할 수 있다.
  • 맵 사이드 조인 : 이름에서 알 수 있듯이 맵단계에서 Join 연산을 수행한다. 따라서 맵퍼에서 Join 연산을 수행하며, 입력은 키에 따라서 분할되고 정렬되어야 한다. 맵 사이드 join은 일반적으로 리듀스 사이드 join 보다 빠르다. 하지만 키에 다른 분할과 정렬이 이루어져야 하기 때문에 사용 시나리오에 제약이 따른다. 또한 데이터 세트를 동일한 파티션으로 나눠야하며, 특정 키가 동일한 파티션에 있어야 하는 제약도 따른다.
  • 리듀스 사이드 조인 : 리듀스 단계에서 join 작업을 수행한다. 리듀서는 정렬과 셔플링 단계를 끝낸 "동일한 키"가 전송되기 때문에 맵 사이드 join에 비해서 제약이 적고 구현도 쉽다. 하지만 모든 데이터세트들이 맵리듀스 셔플 프로세스를 거쳐야 하기 때문에 좀 더 비효율적이다.
 Reduce 사이드 Join

맵리듀스 combiner

맵리듀스 애플리케이션에서는 맵퍼에서 리듀서로 전달되는 데이터의 양을 줄이는 것이 매우 중요한 성능 최적화 요소다. 이를 위해서 하둡은 combiner이라는 인터페이스를 제공한다. Combiner는 Mini-Reducer이라고 부르기도 하는데, 쉽게 말해서 local reducer이다. 즉 각 맵퍼가 자신이 처리한 데이터에 대해서 reducer 작업을 수행한 후 그 결과만 reducer로 넘기는 방법으로 맵리듀스를 최적화 한다. 단어 카운팅 애플리케이션을 개발한다고 하면, 각 맵퍼는 합산(sum)연산을 할 것이다. 맵퍼는 자신이 처리할 key에 대한 합산을 미리해서 결과만 넘긴다.

Combiner는 sum, min, max 처럼 local 작업 결과와 global 작업 결과가 동일한 연산에는 사용 할 수 있지만 join 같은 연산을 처리 할 수는 없다. Mini-Reducer 연산을 메모리에서 수행하는 식으로 최적화 하는 방법을 쓸 수도 있다.

맵리듀스 partitioner

Partitioner는 맵퍼의 중간 결과물을 분할해서 저장한다. 개발자는 해시함수와 같은 유저가 정의한 조건을 이용해서 파티션을 만들 수 있다. 파티션의 갯수는 리듀서 작업의 갯수와 동일해야 한다.

참고