ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [데이터 중심 애플리케이션] 일괄 처리
    Software Development/Database 2021. 12. 26. 01:36

    시스템의 3가지 유형

    • 서비스(온라인 시스템)
      • 클라이언트로부터 요청이나 지시가 올 때까지 기다린다. 요청 하나가 들어오면 서비스는 가능한 빨리 요청을 처리해서 응답을 되돌려 보내려 한다. 응답 시간서비스 성능을 측정할 때 중요한 지표다.
    • 일괄 처리 시스템(오프라인 시스템)
      • 일괄 처리 시스템은 매우 큰 입력 데이터를 받아 데이터를 처리하는 작업을 수행하고 결과 데이터를 생산한다. 수 분에서 수 일이 걸리기 때문에 대개 사용자가 작업이 끝날 때까지 대기하지 않는다. 일괄 처리 작업의 주요 성능 지표로는 처리량이 대표적이다. 처리량은 입력 데이터 중 특정 크기만큼 처리할 때 걸리는 시간으로 나타낸다.
    • 스트림 처리 시스템(준실시간 시스템)
      • 일괄 처리 시스템과 마찬가지로 요청에 대해 응답하지 않으며 입력 데이터를 소비하고 출력 데이터를 생산한다. 입력 이벤트가 발생한 직후 바로 작동한다.

    유닉스 도구로 일괄 처리하기

    단순 로그 분석

    웹사이트에서 가장 인기가 높은 페이지 5개를 뽑는다고 하면 유닉스 셸에서 아래와 같이 할 수 있다.

    cat /var/log/nginx/access.log |
    awk '{print $7}' |
    sort |
    uniq -c |
    sort -r -n |
    head -n 5

    1. 로그를 읽는다.

    2. 줄마다 공백으로 분리해서 요청 URL에 해당하는 7번째 필드만 출력.

    3. 요청 URL을 알파벳 순으로 정렬. 특정 URL이 n번 요청되면 정렬 후에는 이 URL이 연속해서 n번 반복.

    4. uniq 명령은 인접한 두 줄이 같은지 확인해서 중복을 제거. -c는 중복 횟수를 함께 출력하는 옵션. 즉, 중복 없는 URL을 기준으로 각각 몇 번씩 요청이 있었는지 확인.

    5. -n 옵션을 사용해 매 줄 첫 번쨰로 나타나는 숫자, 즉 URL의 요청 수를 기준으로 다시 정렬. -r 옵션을 함께 사용해 내림차순으로 정렬.

    6. 마지막으로 head 명령을 사용해 앞에서부터 5줄만 출력.

     

    수 기가바이트의 로그 파일을 수 초내로 처리할 수 있다. 실제로 많은 데이터 분석이 수 분 내에 awk, sed, grep, sort, uniq, xargs의 조합으로 결과를 얻을 수 있고 놀라울 정도로 잘 수행된다.

    연쇄 명령 대 맞춤형 프로그램

    유닉스 연쇄 명령 대신 같은 작업을 하는 간단한 프로그램을 작성할 수도 있다.

    정렬 대 인메모리 집계

    허용 메모리보다 작업 셋이 크다면 정렬, 작업 셋이 작다면 인메모리 해시 테이블로 잘 작동한다.

     

    GNU Coreutils에 포함된 sort 유틸리티는 메모리보다 큰 데이터셋을 자동으로 디스크로 보내고 자동으로 여러 CPU 코어에서 병렬로 정렬한다.

    유닉스 연쇄 명령이 메모리 부족 없이 손쉽게 큰 데이터셋으로 확장 가능하다는 의미다. 병목이 있다면 입력 파일을 읽는 속도이다.

    유닉스 철학

    연쇄 명령을 사용해 쉽게 로그 파일을 분석할 수 있었던 것은 유닉스의 핵심 설계 아이디어 중 하나였으며, 오늘날에도 유효하다는 점에서 의미가 있다.

    유닉스에서 빌려 올 수 있는 아이디어가 더 없는지 알아보자.

     

    1978년에 기술된 유닉스 철학.

    1. 각 프로그램이 한 가지 일만 하도록 작성하라. 새 작업을 하려면 기존 프로그램을 고쳐 새로운 "기능"을 추가해 프로그램을 복잡하게 만들기보다는 새로운 프로그램을 작성하라.

    2. 모든 프로그램의 출력은 아직 알려지지 않은 다른 프로그램의 입력으로 쓰일 수 있다고 생각하라. 불필요한 정보로 출력이 너저분해서는 안 된다. 입력 형식으로 엄격하게 열을 맞춘다거나 이진 형태를 사용하지 마라. 대화형 입력을 고집하지 마라.

    3. 소프트웨어를 빠르게 써볼 수 있게 설계하고 구축하라. 심지어 운영체제도 마찬가지다. 수 주 안에 끝내는 것이 이상적이다.

    4. 프로그래밍 작업을 줄이려면 미숙한 도움보단 도구를 사용하라. 도구를 빌드하기 위해 한참 둘러가야 하고 게다가 사용 후 바로 버린다고 할지라도 도구를 써라.

     

    자동화, 빠른 프로토타이핑, 증분 반복, 실험 친화, 큰 프로젝트를 청크로 나누어 처리하기와 같은 방법은 오늘날의 애자일 및 데브옵스 운동과 매우 흡사하다.

     

    sort는 한 가지 일을 잘 해내는 프로그램의 훌륭한 예다. sort의 구현은 대부분의 프로그래밍 언어에 포함된 표준 라이브러리보다 확실히 뛰어나다. 표준 라이브러리는 처리하는 데이터를 디스크로 흘려보내지 않고, 다중 스레드를 쓰는 게 분명히 이득인 상황에서도 다중 스레드를 사용하지 않는다.

    그러나 sort 단독으로는 유용하지않고, uniq 같은 다른 유닉스 도구와 조합해야 강력해진다.

     

    bash 같은 유닉스 셸을 사용하면 작은 프로그램들을 가지고 놀랄 만큼 강력한 데이터 처리 작업을 쉽게 구성할 수 있다.

    이런 프로그램 중 다수를 다른 그룹에 속하는 사람들이 만들었지만 유연한 방식으로 조합할 수 있다.

    유닉스에 이런 결합성을 부여하는 것은 무엇일까?

    동일 인터페이스

    유닉스에서의 인터페이스는 파일이다. 파일은 단지 순서대로 정렬된 바이트의 연속이다. 파일은 이처럼 단순해서 같은 인터페이스로 파일시스템의 실제 파일, 프로세스 간 통신 채널(유닉스 소켓, 표준입출력), 장치 드라이버, TCP 연결 소켓 등 다른 여러가지 것을 표현할 수 있다. 당연하게 받아들이기 쉽지만 이질적인 것들이 하나의 통일 인터페이스를 공유한다는 점은 사실 꽤나 주목할 만하다. 그렇지 않다면 쉽게 서로 연결하기 어려울 것이다.

     

    관례상 많은 유닉스 프로그램은 연속된 바이트를 아스키 텍스트로 취급한다. 로그 분석 예제에서 이 점을 활용했다. awk, sort, uniq, head는 입력 파일을 \n(개행문자, 아스키 0x0A)문자로 분리된 레코드로 다룬다. 같은 레코드 분리자를 사용해 표준화했기 때문에 이 모든 프로그램이 상호 운용 가능하다.

     

    각 레코드를 파싱하는 건 더욱 애매하다. 유닉스 도구는 대개 한 줄을 공백이나 탭 문자로 분리해 필드로 만든다. 하지만 CSV나 파이프 문자 등의 다른 부호화 방법도 사용한다. xargs와 같이 상당히 간단한 도구로 어떻게 입력을 파싱할지 결정하는 명혈줄 옵션이 6가지나 있다.

    로직과 연결의 분리

    유닉스 도구의 다른 특징으로 표준 입력과 표준 출력을 사용한다는 점을 들 수 있다. 프로그램을 실행하고 아무것도 설정하지 않는다면 stdin은 키보드로부터 들어오고 stdout은 화면으로 출력한다. 혹은 파일에서 입력을 가져와 다른 파일로 출력을 재전송할 수도 있다. 파이프는 한 프로세스의 stdout을 다른 프로세스의 stdin과 연결한다. 이때 중간 데이터를 디스크에 쓰지 않고 작은 인메모리 버퍼를 사용해 프로세스 간 데이터를 전송한다.

    투명성과 실험

    유닉스 도구가 성공적인 이유 중 하나는 진행 사항을 파악하기가 상당히 쉽기 때문이다.

    • 유닉스 명령에 들어가는 입력 파일은 일반적으로 불변으로 처리. 다양한 명령행 옵션을 사용해가며 원하는 만큼 명령을 수행하더라도 입력 파일에는 손상을 주지 않는다는 뜻이다.
    • 어느 시점이든 파이프라인을 중단하고 출력을 파이프를 통해 less로 보내 원하는 형태의 출력이 나오는지 확인할 수 있다. 이런 검사 기능은 디버깅할 때 매우 유용하다.
    • 특정 파이프라인 단계의 출력을 파일에 쓰고 그 파일을 다름 단계의 입력으로 사용할 수 있다.

    유닉스 도구는 관계형 데이터베이스의 질의 최적화 도구와 비교하면 상당히 불친절하고 단순하지만 매우 유용하며 실험용으로 매우 좋다.

    유닉스 도구의 가장 큰 제약은 단일 장비에서만 실행된다는 점이다. 이 점이 하둡같은 도구가 필요한 이유다.

    맵리듀스와 분산 파일 시스템

    맵리튜스는 유닉스 도구와 비슷한 면이 있지만 수천 대의 장비로 분산해서 실행이 가능하다는 점에서 차이가 있다.

    맵리듀스는 유닉스 도구와 마찬가지로 상당히 불친절하고 무차별 대입 방법이지만 대신 엄청나게 효율적인 도구다. 단일 맵리듀스 작업은 하나 이상의 입력을 받아 하나 이상의 출력을 만들어 낸다는 점에서 단일 유닉스 프로세스와 유사하다.

     

    맵리듀스 작업은 입력을 수정하지 않기 때문에 출력을 생산하는 것 외에 다른 부수 효과는 없다. 출력 파일은 순차적으로 한 번만 쓰여지고 파일에 이미 쓰여진 부분은 고치지 않는다.

     

    맵리듀스 작업은 분산 파일 시스템상의 파일을 입력과 출력으로 사용한다. HDFS 외에도 아마존 S3, 애저 Blob 저장소 같은 객체 저장소도 유사하다.

     

    HDFS는 비공유 원칙을 기반으로 하는데 NAS(Network Attached Storage)와 SAN(Storage Area Network) 아키텍처에서 사용하는 공유 디스크 방식과는 반대다. 공유 디스크 저장소는 중앙 집중 저장 장치를 사용하는 데 맞춤형 하드웨어를 사용하거나 파이버 채널(Fibre Channel)과 같은 특별한 네트워크 인프라를 사용하기도 한다. 반면 비공유 방식은 특별한 하드웨어가 필요없다. 일반적인 데이터센터 네트워크에 연결된 컴퓨터면 충분하다.

     

    HDFS는 각 장비에서 실행되는 데몬 프로세스로 구성된다. 데몬 프로세스는 다른 노드가 해당 장비에 저장된 파일에 접근 가능하게끔 네트워크 서비스를 제공한다. 이때 데이터센터 내 모든 범용 장비에 디스크가 장착돼 있다고 가정한다. 네임노드라고 부르는 중앙 서버는 특정 파일 블록이 어떤 장비에 저장됐는지 추적한다.

    HDFS는 개념젹적으로 매우 큰 하나의 파일 시스템이고 데몬이 실행 중인 모든 장비의 디스크를 사용할 수 있다.

    장비가 주거나 디스크가 실패하는 경우에 대비하기 위해 파일 블록은 여러 장비에 복제된다. 복제는 단순히 여러 장비에 동일한 데이터를 복사하는 방식이 있고 리드 솔로몬 코드 같은 삭제 코딩 방식을 사용해 데이터 전테를 복제하는 것보다 적은 저장소 부담으로 손실된 데이터를 복구하는 방식도 있다. 이 기술은 장비내에 장착된 여러 개의 디스크를 통해 중복을 제공하는 RAID와 유사하다. 차이가 있다면 분산 파일 시스템에서는 파일의 접근과 복제가 특별한 하드웨어 장치 없이 평범한 데이터 센터네트워크 상에서 이뤄진다는 점이다.

     

    HDFS는 확장성이 뛰어나다. 수만 대의 장비를 묶어서 사용할 수 있고 데이터 저장과 접근 비용은 범용 하드웨어와 오픈소스 소프트웨어를 사용하기 때문에 동급 용량의 전용 저장소 장치를 사용하는 비용보다 훨씬 저렴하다.

    맵리듀스 작업 실행하기

    맵리듀스는 대용량 데이터셋을 처리하는 코드를 작성하는 프로그래밍 프레임워크다. 맵리듀스의 데이터 처리 패턴은 앞의 로그 분석 예와 비슷하다.

    1. 입력 파일을 읽는다. 레코드로 쪼갠다. 웹 서버 로그 예제에서 로그의 각 줄이 레코드가 된다. 즉 레코드 분리자로 \n을 사용한다.

    2. 각 입력 레코드마다 매퍼 함수를 호출해 키와 값을 추출한다.

    3. 키를 기준으로 키-값 쌍을 모두 정렬한다.

    4. 정렬된 키-값 쌍 전체를 대상으로 리듀스 함수를 호출한다. 

    맵리듀스 작업 하나는 4가지 단계로 수행한다. 2단계와 4단계 맵, 리듀스는 사용자가 직접 작성한 데이터 처리 코드다. 1단계는 파일을 나누어 레코드를 만드는 데 입력 형식 파서를 쓴다. 3단계는 정렬 단계로 맵리듀스에 내재하는 단계라서 직접 작성할 필요가 없는데 매퍼의 출력은 리듀스로 들어가기 전에 이미 정렬됐기 때문이다.

     

    맵리듀스 작업을 생성하려면 매퍼와 리듀서라는 두 가지 콜백 함수를 구형해야 한다.

    매퍼: 모든 입력 레코드마다 한 번씩만 호출. 매퍼는 레코드로부터 키와 값을 추출.

    리듀서: 같은 키를 가진 레코드를 모으고 해당 값의 집합을 반복해 리듀서 함수를 호출한다.

    맵리듀스의 분산 실행 

    맵리듀스 프레임웨크가 장비 간에 데이터가 이동하는 복잡한 부분을 처리.

     

    맵리듀스 작업의 병렬 실행은 파티셔닝을 기반으로 한다. 작업 입력으로 HDFS상의 디렉터리를 사용하는 것이 일반적이고, 입력 디렉ㅌ터리 내 각 파일 또는 파일 블록을 독립된 맵 태스크에서 처리할 독립 파티션으로 간주한다.

    각 입력 파일은 보통 수백 메가바이트에 달한다.

    맵리듀스 스케줄러가 입력 파일이 있는 장비에서 작업을 수행하려 한다. 네트워크를 통해 입력 파일을 복사하는 부담과 네트워크 부하가 감소하고 지역성이 증가한다.

     

    맵 태스크에서 실행될 애플리케이션 코드는 작업이 할당된 장비에 아직 존재하지 않기 때문에 맵리듀스 프레임워크가 작업을 수행하기에 적절한 장비로 코드를 복사한다. 복사가 끝나면 장비에서 매퍼 태스크가 시작된다. 입력 파일을 읽기 시작하면 입력 파일에서 한 번에 레코드 하나씩 읽어 매퍼 콜백 함수로 전달한다. 매퍼의 출력은 키-값 쌍으로 구성된다.

     

    리듀서 측 연산도 파티셔닝된다. 맵 태스크 수는 입력 파일의 블록 수로 결정되지만 리듀스 태스크 수는 사용자가 설정한다. 특정 키-값 쌍이 어느 리듀스 태스크에서 수행될지 결정하기 위해 키의 해시값을 사용한다.

     

    키-값 쌍은 반드시 정렬돼야 하지만 대개 데이터셋이 매우 크기 때문에 일반적인 정렬 알고리즘으로 한 장비에서 모두 정렬하기는 쉽지 않다. 그렇기 때문에 단계를 나누어 정렬을 수행한다.

     

    먼저 각 맵 태스크는 키의 해시값을 기반으로 출력을 리듀서로 파티셔닝한다. 그리고 각 파티션을 매퍼로 로컬 디스크에 정렬도니 파일로 기록한다.

     

    매퍼가 입력 파일을 읽어서 정렬된 출력 파일을 기록하기를 완료하면 맵리듀스 스케줄러는 그 매퍼에서 출력 파일을 가져올 수 있다고 리듀서에게 알려준다. 리듀서는 각 매퍼와 연결해서 리듀서가 담당하는 파티션에 해당하는 정렬된 키-값 쌍 파일을 다운로드한다. 리듀서를 기준으로 파티셔닝하고 정렬한 뒤 매퍼로부터 데이터 파티션을 복사하는 과정을 셔플이라 한다.

     

    리듀스 태스크는 매퍼로부터 파일을 가져와 정렬된 순서를 유지하면서 병합한다. 그렇기 때문에 다른 매퍼가 동일한 키로 레코드를 생성하면 병합된 이후 리듀서의 입력으로 들어갈 때는 서로 인접하게 된다.

     

    리듀서는 키와 반복자를 인자로 호출하는데 이 반복자로 전달된 키와 동일한 키를 가진 레코드를 모두 훑을 수 있다. 리듀서는 임의의 로직을 사용해서 이 레코드들을 처리하고 여러 출력 레코드를 생성할 수 있다.

    맵리듀스 워크플로

    하둡 맵리듀스는 서로 완전히 독립적이다. URL별 방문자수를 집계하는 맵리듀스 잡과 가장 인기있는 URL을 구하는 잡은 독립적이다. 이를 연결시키기 위해 첫번째 잡의 출력 디렉터리가 다음 작업의 입력 디렉터리가 되도록 한다.

    작업 간 수행 의존성을 관리하기 위해 다양한 스케줄러가 있는데, 우지, 아즈카반, 루이지, 에어플로우 등이 있다.

     

    이런 스케줄러에는 많은 일괄 처리 작업의 집합을 유지보수할 때 유용한 관리 기능이 있다. 추천 시스템을 구축하는 데 사용하는 워크플로는 50개에서 100개가 일반적이다. 

    피그, 하이브 등 다양한 하둡용 고수준 도구는 다중 맵리듀스를 서로 적절하게 자동으로 역어 워크프롤를 설정한다.

    리듀스 사이드 조인과 그룹화

    여러 데이터셋에서 한 레코드가 다른 레코드와 연관이 있는 것은 일반적이다. 관계형 모델에서는 외래키, 문서 모델에서는 문서 참조라 하고 그래프 모델에서는 간선이라 부른다. 

    데이터베이스에서 적은 수의 레코드만 관련된 질의를 실행한다면 데이터베이스는 일반적으로 색인을 사용해 관심 있는 레코드의 위치를 빨리 찾는다. 맵리듀스에는 적어도 일반적으로 이야기하는 색인 개념이 없다.

     

    파일 집합이 입력으로 주어진 맵리듀스 작업이 있다면 맵리듀스 작업은 입력 파일 전체 내용을 읽는데 데이터베이스에서 이 연산을 전체 테이블 스캔이라 부른다. 적은 수의 레코드만 읽고 싶을 때 전체 테이블 스캔은 사용한다면 탐색 비용이 터무니없이 많이 든다. 그러나 분석 질의는 대량의 레코드를 대상으로 집계 연산을 하는 것이 일반적이다. 이런 경우 입력 전체를 스캔하는 것이 상당히 합리적이다. 여러 장비에 걸쳐 병럴처리가 가능한 경우는 특히 그렇다.

     

    일괄 처리 맥락에서 조인은 데이터셋 내 모든 연관 관계를 다룬다는 뜻이다. 예를 들어 특정 사용자의 데이터만을 찾는 것이 아니라 모든 사용자 데이터를 동시에 처리한다. 특정 사용자의 데이터만 찾는다면 색인을 사용하는 편이 훨씬 효율적이다.

    사용자 활동 이벤트 분석 예제

    사용자 ID마다 원격서버에 있는 디비에 질의를 보내는 것은 나쁜 성능이 생길 수 있다. 디비 통신시에 왕복 시간으로 처리향이 제한되고 지역 캐시의 효율성은 데이터 분포에 크게 좌우되며 상당히 많은 질의가 병렬로 실행되면 데이터베이스에 과부하가 걸리기 쉽다.

     

    일괄 처리에서 처리량을 높이기 위해서는 가능한 한 한 장비 내에서 연산을 수행해야 한다.

    데이터베이스의 사본을 가져와 사용자 활동 이벤트 로그가 저장된 분산 파일 시스템에 넣는 방법이다. 그러면 사용자 데이터베이스와 사용자 활동 레코드가 같은 HDFS 상에 존재하고 맵리듀스를 사용해 연관된 레코드끼리 모두 같은 장소로 모아 효율적으로 처리가 가능하다.

    정렬 병합 조인

    매퍼는 레코드로부터 키-값을 추출한다. 

    맵리듀스 프레임웍에서 키로 매퍼의 출력을 파티셔닝해 키-값으로 정렬한다면 같은 사용자의 활동 이벤트와 사용자 레코드는 리듀서의 입력으로 서로 인접해서 들어간다.

     

    리듀서가 항상 사용자 데이터베이스를 먼저 보고 활동 이벤트를 시간 순으로 보게 하는 식으로 맵리듀스에서 작업 레코드를 재배열하기도 한다. 이 기술은 보조 정렬이라 한다.

     

    보조 정렬 후 리듀서가 수행하는 실제 조인 로직은 간단하다. 리듀서 함수는 모든 사용자 ID당 한번만 호출되고 보조 정렬 덕분에 첫 번째 값은 사용자 데이터베이스의 생년월일 레코드로 예상할 수 있다. 리듀서는 지역 변수에 생년월일을 저장하고 그다음으로부터 같은 사용자 ID가 동일한 활동 이벤트를 순회해서 본 URL과 본 사람의 연령의 쌍을 출력한다. 그러면 맵리듀스 작업들이 각 URL마다 본 사람의 연령 분포를 게산하고 연령대별로 클러스터링할 수 있다.

     

    리듀서는 특정 사용자 ID의 모든 레코드를 한 번에 처리하므로 한 번에 사용자 한 명의 레코드만 메모리에 유지하면 되고 네트워크로 아무 요청도 보낼 필요가 없다. 이 알고리즘을 정렬 병합 조입이라고 한다. 매퍼 출력이 키로 정렬된 후에 리듀서가 조인의 양측의 정렬된 레코드 목록을 병학하기 때문이다.

    같은 곳으로 연관된 데이터 가져오기 

    병합 정렬 조인 중 매퍼와 정렬 프로세스는 특정 사용자 ID로 조인 연산을 할 때 필요한 모든 데이터를 한 곳으로 모은다. 그래서 사용자 ID별로 리듀서를 한 번만 호출한다. 필요한 데이터를 사전에 줄 세웠기 대문에 리듀서는 단일 스레드로 동작하는 간단한 코드 조각이 될 수 있으며 레코드를 휘젓고 다닐 떄 처리량을 높게 유지하면서도 메모리 부담을 줄일 수 있다.

     

    매퍼가 리듀서로 메세지 전송하는 방식을 보면 매퍼의 키는 값을 보낼 목적지 주소 역할을 한다. 같은 키를 가진 키-값 쌍은 모두 같은 목적지(리듀서 호출)로 배달된다.

     

    맵리듀스 프로그래밍은 올바른 장비로 데이터를 모으는 연산의 물리적 네트워크 통신 측면과 받은 데이터를 처리하는 애플리케이션 로직을 분리한다. 이는 전형적인 데이터베이스 사용 유형과 대조적이다. 데이터베이스로부터 데이터를 가져오는 요청은 애플리케이션 코드 내에서 주로 발생한다. 맵리듀스는 모든 네트워크 동신을 직접 관리하기 때문에 특정 장비가 죽는 것과 같이 부분적으로 실패가 발생하더라도 애플리케이션 코드 단에서 고민할 필요가 없다. 맵리듀스는 애플리케이션 롲기에 여향이 가지 않게 실패한 대스크는 확실하게 재시도 한다.

    그룹화

    맵리듀스로 그룹화 연산을 구현하는 가장 간단한 방법은 매퍼가 키-값 쌍을 생성할 때 그룹화할 대상을 키로 하는 것이다.

     

    특정 사용자가 취한 일련의 활동을 찾기 위해 사용자 세션별 활동 이벤트를 수집 분석할 때도 일반적으로 그룹화를 사용한다. 이 과정을 세션화라고 하는데, 예를 들어 사용자에게 옛 버전 웹사이트를 보여줬을 떄보다 새 버전 웹사이트를 보여줬을 때 구매를 더 햇는지 확인하거나 혹은 어떤 마케팅 활동이 가치 있는지 분석하는 것을 말한다.

    쏠림 다루기

    소셜 네트워크에서 인플루언서의 데이터는 일반인에 비해 불균형적이다. 이렇게 불균형한 활성 데이터베이스 레코드를 린치핀 객체 또는 핫 키라 한다.

    인플루언서와 관련된 모든 활동을 리듀서 한 개에서 모으면 쏠림 현상이 생기고 이를 핫스팟이라 한다. 즉 한 리듀서가 다른 리듀서보다 엄청나게 많은 레코드를 처리해야 한다.

    완화하는 알고리즘으로 피그의 쏠린 조인 메서드는 어떤 키가 핫 키인지 결정하기 위해 샘플링 작업을 수행한다. 실제 조인을 수행할 때 매퍼는 핫 키를 가진 레코드는 여러 리듀서 중 임의로 선택한 하나로 레코드를 보낸다. 핫 키로 조인할 다른 입력은 핫 키가 전송된 모든 리듀서에 복제한다.

     

    핫 키를 여러 리듀서에 퍼뜨려서 처리하려는 방법이다. 다른 조인 입력을 여러 리듀서로 복제하는 비용이 들지만 병렬화 효과가 훨씬 크다. 

     

    하이브는 쏠린 조인을 최적화할 때 핫 키는 테이블 메타데이터에 명시적으로 지정하고 핫 키와 관련된 레코드를 나머지 키와는 별도 파일에 저장한다. 해당 테이블에서 조인할 때 핫 키를 가지는 레코드는 맵 사이드 조인을 사용해 처리한다.

    맵사이드 조인 

    실제 조인 로직은 리듀서에서 수행하기 때문에 리듀스 사이드 조인이라 한다. 매퍼는 각 입력 레코드에서 키와 값을 추출해 추출한 키-값 쌍을 리듀서 파티션으로 할당하고 키별로 정렬하는, 즉 입력 데이터를 준비하는 역할을 한다.

     

    리듀스 사이드 접근법의 장점은 입력 데이터에 대한 특정 가정이 필요없다. 그러나 정렬 후 리듀서로 복사한 뒤 리듀서 입력을 병합하는 몯ㄴ 과정에 드는 비용이 상당하다는 큰 단점이 있다.

     

    입력 데이터에 대한 특정 가정이 가능하다면 맵사이드 조인으로 불리는 기법을 사용해 조인을 더 빠르게 수행할 수 있다. 각 매퍼가 할 작업은 분산 파일 시스템에서 단순히 입력 파일 블럭 하나를 읽어 다시 해당 분산 파일 시스템에 출력하는 것이 전부다.

    브로드캐스트 해시 조인

    맵 사이드 조인은 작은 데이터셋과 큰 데이터셋을 조인하는 경우에 가장 간단하게 적용해볼 수 있다.

    매퍼가 시작할 때 분산 파일 시스템에서 사용자 데이터베이스를 읽어서 인메모리 해시 테이블에 넣는다. 매퍼는 사용좌 활동 이벤트를 모두 스캔할 수 있고 사용자 ID를 해시 테이블에서 간단하게 조회할 수 있다.

     

    매퍼 태스크를 여러 개 사용할 수도 있다. 각 맵 태스크에 조인할 큰 입력 파일 블록 중 하나를 한당하면 된다. 모든 매퍼는 작은 입력 전체를 메모리에 적재한다.

     

    이를 브로드캐스트 해시 조인이라 한다.  피그, 하이브 등에서 제공하며 임팔라 같은 데이터 웨어하우스 질의 엔젠에서도 사용한다.

    인메모리 해시 테이블로 적재하는 대신 디스크에 읽기 전용 색인으로 작은 조인 입력을 저장하기도 한다. 이 색인 중 자주 사용되는 부분은 운영체제의 페이지 캐시에 남는다. 따라서 이 방법은 메모리안에 전체 데이터가 들어오지 않아도 인메모리 해시 테이블만큼 빠르게 임의 접근 조회가 가능하다.

    파티션 해시 조인

    해시 조인 접근법을 각 파티션에 독립적으로 적용하는 방법이다. 마지막 십진수를 기준으로 파티셔닝해 재배열할 수 있다. 각 매퍼는 각 입력 데이터셋 중 파티션 한 개만 읽어도 충분하다. 객 매퍼의 해시 테이블에 적재해야 할 데이터의 양을 줄일 수 있다는 점이 장점이다.

    맵 사이드 병합 조인

    입력 데이터셋을 같은 방식으로 파티셔닝됐을 뿐 아니라 같은 키를 기준으로 정렬됐다면 변형된 맵사이드 조인을 적용할 수 있다.

    이때 입력 크기가 메모리에 적재 가능한지 고려할 필요가 없다. 매퍼는 리듀서에서 일반적으로 수행하는 것과 동일한 병합 연산을 수행할 수 있기 때문이다.

    맵 사이드 조인을 사용하는 맵리듀스 워크플로

    리듀스 사이드 조인은 조인 키로 파티셔닝하고 정렬해서 출력한다. 반면 맵 사이드 조인은 큰 입력과 동일한 방법으로 파티셔닝하고 정렬한다.

    일괄 처리 워크플로의 출력

    일괄 처리는 트랜잭션도 아니고 분석도 아니지만 데이터셋 대부분을 스캔하는 것이 일반적이라 분석에 더 가깝다.

    검색 색인 구축

    정해진 문서 집합을 대상으로 전문 검색이 필요하다면 일괄 처리가 색인을 구축하는 데 매우 효율적이다. 

    일괄 처리의 출력으로 키-값을 저장

    일괄 처리 작업의 출력은 일종의 데이터베이스가 된다.

    데이터 파일은 기록되면 불변이고, 벌크로 적재해 읽기 전용으로 쓰인다.

    일괄 처리 출력에 관한 철학

    입력을 불변으로 처리하고 외부 데이터베이스에 기록하는 등의 부수효과를 피하기 때문에 일괄 처리 작업은 좋은 성능을 내면서도 유지보수가 훨씬 간단하다.

    유닉스와 하둡은 몇가지 다른 점이 있다.

    유닉스 도구 대부분은 타입이 없는 텍스트 파일을 가정

    하둡에서는 구조화된 파일 형식을 사용하면 저수문 구문 변환 작업 중 일부를 하지 않아도 된다. 에이브로, 파케이가 구조화 파일 형식이다. 스키마 기반 부호화를 제공하고 시간이 지남에 따라 스키마를 발전할 수 있다.

    하둡과 분산 데이터베이스의 비교

    맵리듀스와의 가장 큰 차이점을 보면 MPP 데이터베이스는 장비 클러스터에서 분석 SQL 질의를 병렬로 수행하는 것에 초점을 두지만 맵리듀스와 분산 파일 시스템의 조합은 아무 프로그램이나 실행할 수 있는 운영체제와 비슷한 속성을 제공한다.

    저장소의 다양성

    데이터베이스는 특정 모델(관계형, 문서형)을 따라 데이터를 구조화해야한다. 

    분산 파일시스템의 파일은 어떤 데이터 모델과 인코딩을 사용해서도 기록할 수 있는 연속된 바이트일 뿐이다.

    HDFS는 어떤 형태라도 상관없이 HDFS로 덤프할 수 있는 가능성이 있다.

    세심하게 모델링하는게 바람직하지만 현실에서는 이상적인 데이터 모델을 만들려고 하기보다 데이터를 빨리 사용 가능하게 만드는 것이 더 가치 있다.

    처리 모델의 다양성

    다양한 처리 모델은 모두 단일 공유 클러스터 장비에서 실행되고 분산 파일 시스템상에 존재하는 동일한 파일들에 접근 가능하다. 

    빈번하게 발생하는 결함을 줄이는 설계

    MPP는 한 장비만 죽어도 전체 질의가 종료된다.

    맵리듀스는 태스크의 실패에 견딜 수 있다. 맵리듀스 접근법은 대용량 작업에 더 적합하다. 

    맵리듀스를 넘어

    중간 상태 구체화

    한 작업에서 다른 작업으로 옮기는 수단, 즉 중간 상태다.

    중간 상태를 파일로 기록하는 과정을 구체화라 한다.

    중간 상태의 단점

    • 모든 선행 작업 태스크가 종료될 때까지 기다린다.
    • 매퍼는 종종 중복되기도 한다.
    • 임시 데이터인 중간 상태를 저장하는 것은 여러 장비에 걸쳐 복제됐다는 의미로서 과잉조치다.

    데이터플로 엔진

    위의 문제를 해결하기 위해 분산 일괄 처리 연산을 수행하는 엔진이 새롭게 개발됐다. Spark, Tez, Flink

    전체 워크플로를 독립된 하위 작업으로 나누지 않고 작업 하나로서 다룬다.

    맵리듀스의 비해 가지는 장점

    • 정렬은 필요할 때만. 기본적으로 맵과 리듀스 사이에서 정렬 작업이 항상 발생.
    • 스케줄러가 어느 데이터가 어디에 필요한지에 대한 개요를 가져서 지역성 최적화가 가능하다.
    • IO가 훨씬 적게든다.
    • 연산자들은 입력이 준비되는 즉시 실행가능. 선행 단계 전체가 끝나기를 기다릴 필요가 없다.
    • 새로운 JVM을 연산자마다 띄울 필요가 없이 이미 존재하는 JVM 사용 가능.

    내결함성

    구체화의 이점은 내구성이다. 중간 상태를 구체화하여 내결함성을 확보. 태스크가 실패해도 다른 장비에서 실행 가능.

    스파크는 RDD를 사용해 데이터의 조상을 추척할 수 있다. 플링크는 체크포인트를 남겨 작업 실행 중 실패한 연산자 수행을 재개할 수 있다.

    연산자를 결정적으로 만드는 것이 핵심이다.

    그러나 의사난수, 확률 등 비결정적인 것도 있다. 이를 제거해야 신뢰성 있게 회복할 수 있다.

    결함에서 복구할 때 데이터를 재연산하는 방식이 항상 정답은 아니다. 중간 데이터가 원천 데이터보다 훨씬 작거나 연산이 CPU 중심적이라면 재연산보다 중간 데이터를 파일로 구체화하는 방식이 더 효과적이다.

    구체화에 대한 논의

    데이터플로 엔진은 유닉스 파이프와 비슷하다.

    입력은 불변이고 최종 출력을 완전히 교체하는 방식은 맵리듀스와 비슷하다. 중간 상태를 파일 시스템에 기록하는 수고를 덜어준다는 점은 맵리듀스보다 개선된 장점이다. 

    댓글

Designed by Tistory.