Hadoop HDFS 및 MapReduce 기초개념

2019-07-06

.

Data_EngineeringTIL(20190704)

study program : https://www.fastcampus.co.kr/data_camp_hadoop

[학습목표]

  • Hadoop HDFS 및 MapReduce 이해

[학습기록]

1. Hadoop Clustering 기초개념

  • 마스터 노드 : 최소 2대 보통 3대로 운영

마스터 노드가 상식적으로 한대만 있으면 되는데 왜 두대가 필요하냐 .. 만약의 상황을 대비해서 한대가 더 있는건데 오인할 경우를 대비해서 홀수개인 3대를 쓰는건다. (그러나 주 운영은 하나의 마스터가 한다는 것이다)

  • 데이터 노드 : 최소 한대이상으로 운영

  • Yarn : 클러스터 자원관리

2. HDFS 기초개념

[HDFS 구성요소]

1) 데이터노드 : 데이터 파일을 저장하고 관리하는 노드

2) 네임노드 : 어떤 특정파일이 어느 데이터 노드에 저장되어 있는지 기록(=메타데이터)하여 갖고 있는 노드. 즉, 메타데이터를 저장하고 관리하는 노드

** ‘메타’란 데이터에 대한 정보를 말한다.

3) 클라이언트

[데이터 저장 시 HDFS 작동원리]

step1) 예를 들어서 200MB 파일을 저장하고자 한다. 클라이언트는 네임노드에게 200MB파일 하나를 3곳의 디스크에 분산저장해달라고 요청한다. HDFS는 200MB짜리 파일 하나를 조각내서 ‘블록’이라는 것들로 만든다. 블록 하나의 사이즈는 통상 64MB나 128MB다. 블록사이즈는 최대 128MB이므로 통상 128메가가 넘으면 그때 블록단위로 짜르게 된다.

step2) 그래서 우리가 저장하고자 하는 이 200MB짜리 파일 하나는 128MB짜리 블록 하나, 72MB짜리 블록 하나 총 2개의 블록으로 쪼개질 것이다. 그리고 이 블록들은 각각 통상 3곳으로 분산저장 될 것이다.(이런 분산저장 개념을 Replication 이라고 한다.)

step3) 그래서 이렇게 두개의 블록으로 파일을 쪼개는게 완료되면 클라이언트는 먼저 네임노드에게 첫번째 블록(128MB 짜리 블록)을 어디에다 저장할지 물어본다. 그러면 네임노드가 어떤 데이터 노드에다가 저장할지 지정해서 지정된 데이터 노드 3개의 주소(IP주소)를 클라이언트에게 알려준다.

step4) 주소를 받은 클라이언트는 해당주소의 데이터 노드에 파일(128MB짜리 1블록)을 패킷단위로 전송하게 된다. 아래 만화 그림과 같이 첫번째 데이터 노드에게 데이터를 보내면 첫번째 데이터 노드는 먼저 자기 하드에 데이터를 저장하고, 동시에 데이터를 받고 있는 동안 이미 받은 동일한 데이터를 다음 데이터 노드로 보내게 된다. 두번째 노드도 마찬가지 방식으로 데이터를 저장하고 다음 데이터로 데이터를 보내게 된다. 결론적으로 데이터를 받으면서 또 다른 노드로 데이터를 보내기 때문에 한군대 보내나 두군대 보내나 세군대 보내나 데이터를 보내고 저장하는 시간이 별로 차이가 나지 않게 된다.

패킷단위로 던지기 때문에 페이지 번호가 지정되어 있어서 순서관계 없이 데이터 노드끼리 막 던지고 받아도 상관없어서 빠른 것이다.

step5) 이렇게 첫번째 블록이 저장이 완료되면 두번째 블록도 마찬가지로 클라이언트가 네이터 노드에게 어디에다 저장할지 물어보면 네임노드는 클라이언트에게 첫번째 블록을 저장했던 데이터 노드들을 제외한 다른 데이터 노드들의 주소들을 알려줄 것이다(물론 데이터 노드의 수가 적으면 상황이 달라질 것이다. 어쨌든 핵심은 첫번째 블록을 저장했던 노드들이 아니라 다른 노드에 저장하려는 의도가 있다.). 그러면 step4)와 같은 방식으로 데이터를 저장하게 된다.

** ‘패킷’은 파일이 있으면 이것을 네트워크 상으로 전송하기 위해 쪼개서 보내는 단위이다. 보통 4키로바이트 단위

1

[데이터를 불러올 시 HDFS 작동원리]

아래 만화그림과 같이 데이터 1개가 3개 블록으로 구성되어 있고, 각각의 블록은 각각 3개의 노드에 저장되어 있다고 치자. 먼저 클라이언트가 파일에 대한 정보를 달라고 네임노드에게 요청한다. 그러면 네임노드는 클라이언트에게 아래 그림과 같이 파일에 대한 모든 저장정보를 알려주게 된다. 데이터 이동간에 문제가 발생할 수도 있기 때문에 굳이 각 블록들이 저장되어 있는 데이터 노드 주소 하나만 알려줘도 되지만 클라이언트로 데이터를 보내고 있다가 갑자기 데이터 노드 하나가 죽어버리면 그 데이터 노드가 하던 일을 다른 데이터노드(작업했던 동일한 블록이 저장되어 있는 데이터 노드)에게 시키기 위한 만약의 상황을 대비한 것이다.

1-2

[위의 내용들을 총정리해서 도식화한 그림이다.]

2

3. MapReduce 기초개념

1) 컴퓨터의 연산 기준속도

1-1) 검색

데이터 사이즈의 1승 만큼의 시간소요

1-2) 집계

데이터 사이즈의 2승 만큼의 시간소요

1-3) 분석

데이터 사이즈의 3승 만큼의 시간소요

1-4) 일반적인 분산컴퓨팅(슈퍼컴퓨터)에서 데이터 처리속도를 향상시키기 위한 방향

기존에 한대로 처리하던걸 N대로 처리하게 되면

검색은 예를들어서 1대로 처리하던 시간이 10분이 걸리면 10대로 하게 되면 1분이 걸린다.

집계(정렬)는 예를들어서 1대로 처리하던 시간이 100분이 걸린다고하면 10대(N대)로 하게 되면 10(N)의 제곱분의 1이 되기 때문에 1분이 걸리게 된다.(100/10의 제곱)

다시말해서 데이터 정렬 시 클러스터의 노드가 많으면 많을수록 유리하다.

2) Hadoop의 MapReduce를 사용할 시 N대의 3승분의 1이 된다. 엄청나게 빠르다.

3) MapReduce의 간략한 흐름

입력 -> 맵 -> 셔플 -> 리듀스 -> 출력

** ‘셔플’은 중간에 네트워크로 데이터를 전송하는 단계이다.

4) MapReduce의 세가지 유형

그림 2-3

A라는 데이터를 맵리듀스 연산한다고 치자. 보통 데이터를 여러군대에 저장하기 때문에 A라는 데이터들이 또 블록단위로 저장되어 있어서 이 A데이터의 블록들이 저장된 주소를 알아내서 이 블록들을 또 split이라는 연산을 통해 3개로 쪼갠다음에 맵연산을 수행한다.

이렇게 동시에 세군대서 맵을하고 리듀스를 해야 하는데 결과가 하나가 나와야 하기 때문에 결과도 하나의 노드에서 나와야 한다. 이 동시에 세군대에서 맵을 한 각각의 결과들을 리듀스 연산을 수행할 노드로 보내줘야 한다. 이렇게 맵의 결과를 리듀스 연산의 input으로 네트워크로 보내주는 것이 셔플이다.

그림 2-4와 같이 데이터 흐름이 2개 이상의 노드에 분할 되는 경우도 있다.

그림 2-5와 같은 경우는 ‘검색’할때 보통 이런 양상이다. 검색은 남시키는 연산이 없기 때문이다. 특정노드 하나에서 연산하고 결과 내주면 끝이기 때문이다.

3

5) MapReduce의 통상적인 데이터 흐름

맵연산의 경우에 따라 아래 그림처럼 노드1에서 맵한 결과가 자기 자신의 인풋값으로 다시 들어오는 경우도 있다.

연산이 복잡해질수록 통상 두번째 그림처럼 DAG 형식의 워크플로우가 형성된다. 다시말해서 맵리듀스의 반복이 진행되는 것이다. 맵리듀스하고 저장하고 또 그 저장된 결과를 다시 다른 맵리듀스 인풋값으로 넣고 이런식으로 복잡한 연산을 해결할 수 있다.

우리가 하둡을 사용하면서 맵리듀스 연산을 명령하면 한방에 그냥 알아서 실행되지만 속에서는 아래와 같은 과정이 자동으로 진행되는 것이라고 할 수 있다.

4

6) 맵리듀스의 원리

** 맵리듀스에서 컴퓨터의 ‘코어’의 갯수가 중요하다. 보통 컴퓨팅 단위를 ‘코어’단위로 하기 때문이다.

6-1) 맵리듀스의 3대 원리

6

6-2) 맵리듀스 연산으로 연산시간을 단축하는 원리

하둡에서 ‘sum’ 연산을 한다는 것은 단순한 검색연산이기 때문에 맵에서 소계/총계에서 끝나버린다. 그러나 대부분의 연산에 있어서는 데이터를 정렬하고 연산을 하는 경우가 많다.

그래서 우리는 정렬에 대해서 알 필요가 있다.

[대용량 데이터 정렬시간]

9

10개의 코어가 있는 컴퓨터가 있다고 치자. 1억건의 데이터를 위와 같이 1천만건 단위로 10개로 먼저 split한다. 그리고 이렇게해서 split된 각각의 천만건 데이터를 정렬하는데 소요되는 시간은 100분이다. 그런데 코어가 10개여서 100 * 10분이 아니라 100 * 1분이 된다.

그래고 셔플을해서 한곳으로 모아야 한다. 소계/총계하듯이 부분정렬/전체정렬을 하려면 전처정렬이 되야 하니까 리듀스는 한곳에 모아야하기 때문에 총 1억건을 read/write 연산으로 판단해서 10분이 걸린다.

그래서 이렇게 모아놓은 데이터를 가지고 전체정렬을 해야하는데 이때 쓰는 알고리즘이 머지소트이다. 10개의 파일을 하나로 모으면(병합) 되는 것이다.

[머지소트 연산예시]

10

위와 같이 머지소트를 하게 되면 결론적으로 read/write 연산만 하기 때문에 reduce하면 병합(전체정렬)하여 정렬하게 되므로 1억건의 데이터에 대해 10분이 소요된다. 보통 셔플시간과 리듀스 시간이 동일하다.

이렇게 되면 100분 + 10분 + 10분 = 총 120분

이 정렬의 문제를 부분정렬, 전체정렬 문제로 해결한다. 1억건에 대한 정렬이 10,000분인 것이었는데 1억건을 결론적으로 우리가 정렬하기 때문에 이걸 map 10개로 나누어서 각 천만번을 정렬하였다. 천만번의 정렬시간은 10분이니까 연산시간이 10의 제곱분의 일이 되는 것이다. 그래서 10000/100 = 100분이 되는 것이다. 그런데 우리는 맵연산만 하는 것이 아니기 때문에 이 100분에다가 오버헤드가 보통 20 ~ 30%가 붙는다. 그래서 120분인 것이다.

mapreduce에서 셔플이라는 것도 또한 연산시간 단축에 영향을 미친다.

  • 위에서 언급했던 맵리듀스 원리를 도식화

11

6-3) 맵리듀스를 이용한 1~10의 합계 예시

5

6-4) 맵리듀스를 이용한 1~10의 평균 예시 (초창기 하둡 맵리듀스의 문제점)

우리는 1~10의 평균이 5.5라고 알고 있는데 실제 계산을 해보니까 5.5가 나왔다. 뭔가 이상해서 두번째 시도를 했는데 이때는 5.5가 제대로 나왔다.

슈퍼컴퓨터에서 프로그램을 짤때 두번하게 되어 있다. 아래 그림과 같이 split을 다르게해서 두번 실행하게 되어 있다.

도대체 왜 이런것일까

이 프로그램에서 짠 것은 잘못된것이다. 연산을 두번했을때 동일한 연산이 나오지 않으면 잘못된 것이다. 동일하게 결과가 나와야 한다. 맵리듀스는 집계까지는 문제가 없는데 통계 연산을 할때 이런문제가 발생한다. 위에서는 예시를 들어서 split을 다르게 주었지만 실제 하둡에서는 split연산을 마음대로 줄 수 없다. 하둡에서는 그래서 두번돌려도 동일한 결과를 내긴하는데 문제는 잘못된 결과를 준다는 것이다. 하둡 1.0에서 이런 문제가 심각했다.

하둡이 3.0이 되면서 90%이상 이런문제가 해결은 되었다. 하둡을 그래서 1.0 버전은 안쓰는게 좋다.

7

그래서 이런맹점을 극복하기 위해 요즘 하둡에서는 이런 연산에 있어서는 함수기능을 제공하여 아래와 같이 연산한다.

8