객체 스토리지의 이러한 구조는 데이터가 여러 디스크에 복사되기 때문에 일부 하드웨어가 고장나도 데이터가 손실되지 않습니다.
또한 데이터를 다수의 하드웨어에 분산하기 때문에 데이터양이 늘어나도 성능이 떨어지지 않습니다.
하지만 크기가 작은 데이터에 대해서는 비효율적입니다.
예를들어 아주 작은 파일을 자주 읽고 쓰면 데이터양에 비해 통신 오버헤드가 너무 크게됩니다.
데이터 수집
빅데이터에서 자주 다루는 데이터는 시계열 데이터입니다.
이것을 수시로 객체 스토리지에 기록하면 작은 데이터가 계속해서 들어가기 때문에 비효율적입니다.
그래서 작은 데이터는 적당히 모아서 하나의 큰 파일로 만들고 객체 스토리지에 기록하는 것으로 효율을 높일 수 있습니다.
그와 반대로 너무 큰 파일은 문제가 발생합니다.
너무 큰 파일은 네트워크 전송에 시간이 걸려 예상치 못한 오류 발생률이 높아집니다.
그래서 너무 큰 파일은 적당히 나눠서 객체 스토리지에 기록하는 것으로 이러한 문제를 줄일 수 있습니다.
즉, 빅데이터는 단지 수집만 하는 것이 아니라 나중에 처리하기 쉽도록 준비해둘 필요가 있습니다.
벌크형과 스트리밍형
데이터 전송에는 벌크형과 스트리밍형 두종류의 구조가 있습니다.
이 둘은 기술적인 특성과 사용되는 도구가 전혀 다르므로 그 성질을 이해한 다음 구분해서 사용해야 합니다.
벌크형
전통적인 데이터 웨어하우스에서 사용된 것은 주로 벌크형 방식으로 데이터베이스나 파일 서버 또는 웹 서비스 등에서 SQL이나 API 등으로 정리해 데이터를 추출합니다.
빅데이터 경우에도 축적된 대량의 데이터가 이미 있거나 기존의 데이터베이스에서 데이터를 추출하고 싶을 때 벌크형을 사용합니다.
원래 데이터가 처음부터 분산 스토리지에 저장되어 있는 것이 아니라면 ETL서버로 데이터 전송을 합니다.
ETL서버는 구조화 데이터 처리에 적합한 데이터 웨어하우스를 위한 ETL도구와 오픈 소스의 벌크 전송 도구 또는 손수 작성한 스크립트 등을 이용하여 데이터를 전송합니다.
벌크형의 장점은 문제가 발생했을때 여러번 데이터 전송을 재실행할 수 있어서 신뢰성이 우수합니다.
그리고 워크플로 관리 도구와의 궁합도 좋습니다.
그렇기에 과거의 데이터를 빠짐없이 가져오거나 실패한 작업은 재실행해야 한다면 벌크형 전송을 해야합니다.
벌크형 데이터 전송 예시
벌크형에서의 파일 사이즈 적정화
벌크형 ETL 프로세스는 하루 또는 1시간 마다의 간격으로 정기적인 실행을 하므로 적정한 크기의 파일로 모아 전송 할 수 있습니다.
만약 정기적인 실행이 적정한 크기의 파일로 모으지 않는다면 시간 간격 변경 등 전송 방법을 변경하는 것이 좋습니다.
스트리밍형
계속해서 전송되어 오는 작은 데이터를 취급하기 위한 데이터 전송 방식입니다.
대다수 데이터는 통신 장비 및 소프트웨어에 의해 생성되고, 네트워크를 거쳐서 전송됩니다.
이러한 데이터는 벌크형 도구로 모을 수 없기 때문에 스트리밍형 데이터 전송이 필요합니다.
이러한 데이터 전송의 공통점은 다수의 클라이언트에서 계속해서 작은 데이터가 전송 된다는 것입니다.
이러한 데이터 전송 방식을 일반적으로 메시지 배송이라고 합니다.
메시지 배송 시스템은 전송되는 데이터양에 비해 통신 오버헤드가 크기 때문에 이를 처리하는 서버는 높은 성능을 요구합니다.
스트리밍형 메시지 배송 예시
보내온 메시지를 저장하는 몇가지 방법이 있는데 그 중 하나는 작은 데이터 쓰기에 적합한 NoSQL 데이터베이스를 이용하는 것입니다.
이 경우 Hive와 같은 쿼리 엔진으로 NoSQL 데이터베이스에 연결해 데이터를 읽을 수 있습니다.
또 다른 하나는 분산 스토리지에 직접 쓰는 것이 아니라 메시지 큐나 메시지 브로커 등의 중계 시스템에 전송하는 것입니다.
이 경우 기록된 데이터는 일정한 간격으로 꺼내고 모아서 함께 분산 스토리지에 저장합니다.
메시지 브로커
대량의 메시지를 안정적으로 받기 위해서는 빈번한 쓰기에도 견딜 수 있는 높은 성능의 스토리지가 필요하지만, 분산 스토리지가 반드시 높은 성능을 가지고 있다고 할 수 없기 때문에 빅데이터의 메시지 배송 시스템에서는 종종 데이터를 일시적으로 축적하는 중산층이 설치됩니다.
이것을 메시지 브로커라고 합니다.
빅데이터를 위한 메시지 브로커는 오픈 소스의 경우 Apache Kafka, 클라우드 서비스의 경우는 Amazon Kinesis 등이 있습니다.
메시지 브로커에 써넣은 데이터는 복수의 다른 소비자에서 읽어 들일 수 있습니다.
이를 통해 메시지가 복사되어 데이터를 여러 경로로 분기시킬 수 있습니다.
이것을 메시지 라우팅이라 합니다.
즉, 메시지를 여러 경로로 라우팅함으로써 동일한 데이터를 스트리밍 처리 및 배치 처리 모두에서 사용할 수 있습니다.
메시지 배송의 신뢰성 문제와 3가지 설계 방식
성능 문제 외에도 피할 수 없는 것이 신뢰성의 문제인데, 신뢰성은 성능과 트레이드 오프 관계에 있습니다.
모바일 회선과 같은 신뢰성이 낮은 네트워크에서는 반드시 메시지의 중복이나 누락이 발생합니다.
그것을 처리하는 시스템은 다음 3가지 중 하나를 보장하도록 설계됩니다.
at most once : 메시지는 한 번만 전송, 도중에 전송에 실패하면 데이터 손실
exactly once : 메시지는 손실 중복 없이 한번만 전달
at least once : 메시지는 확실히 전달, 중복 가능성 있음
at most once는 무슨 일이 일어나도 메시지를 다시 보내지 않습니다.
그렇게 때문에 오류가 발생하면 데이터 손실이 가능성이 있습니다.
exactly once는 양쪽 통신 내용을 중계하는 코디네이터라는 것이 있습니다.
송신 측과 수신 측 모두 서로의 정보를 코디네이터에게 전달하고, 문제가 발생하면 코디네이터에 따라 문제를 해결합니다.
하지만 분산 시스템에 항상 코디네이터가 있다고 할 수 없기 때문에 장애가 발생할 가능성이 있습니다.
그리고 코디네이터의 처리에 시간이 소요되기 때문에 성능이 저하됩니다.
at least once는 오류가 발생하면 재전송을 하기 때문에 중복이 일어날 수 있습니다.
중복을 제거하는 방법은 있지만 중복 제거에 시간이 소요되고 비용도 들기 때문에 일반적으로 중복 제거는 사용자에게 맡깁니다.
대부분의 메시지 배송 시스템은 at least once를 보장합니다.
오프셋을 이용한 중복 제거
전송해야 할 데이터에 파일명 등의 이름을 부여해 그것을 작은 메시지에 실어서 배송합니다.
각 메시지에는 파일 안의 시작 위치를 덧붙입니다.
만일 메시지가 중복되어도 같은 파일의 같은 장소를 덮어쓸 뿐이므로 문제가 되지 않습니다.
시스템이 at least once 보장한다면 언젠가는 파일이 재구성되어 데이터 전송이 완료됩니다.
이 방법은 벌크형 데이터 전송과 같이 데이터양이 고정된 경우에는 잘 작동하지만, 스트리밍형 메시지 배송에서 쓰는 경우는 거의 없습니다.
고유 ID에 의한 중복 제거
스트리밍형 메시지 배송에서 자주 사용되는 것은 모든 메시지에 UUID 등의 고유 ID를 지정하는 방법입니다.
이 방법은 메시지가 늘어남에 따라 ID가 폭발적으로 늘어나기 때문에 그것을 어떻게 관리하느냐가 문제입니다.
현실적으로는 예를 들어 최근 1시간 등 최근에 받은 ID만을 기억해두고 그보다 늦게 온 메시지는 중복을 허용합니다.
중복 대부분은 일시적인 통신 오류로 인해 발생하기 때문에 그것만 제거하면 99퍼의 신뢰도는 달성할 수 있습니다.
데이터베이스에서의 중복 제거
분산 스토리지로 Cassandra와 Elasticsearch 등의 NoSQL 데이터베이스를 이용한다고 하면, 데이터를 쓸 때 고유 ID를 지정되기 때문에 동일한 ID의 데이터는 덮어씁니다.
그렇기에 중복이 일어나도 아무런 변화가 없기 때문에 중복 제거가 됩니다.
보내온 데이터를 그대로 객체 스토리지에 저장하고 나중에 읽어 들이는 단계에서 SQL로 중복을 제거하는 방법도 있습니다.
이 방법은 대규모 데이터 처리이므로 메모리에서 실행하는 것은 거의 불가능하며, Hive 같은 배치형 쿼리 엔진에서 실행합니다.
종단간의 신뢰성
스트리밍형 메시지 배송은 다수의 요소로 구성되는데 그 중 일부분에서 중복 제거가 되더라도 다른 일부분에서 중복이 발생할 수 있습니다.
그렇기에 중복 제거는 종단 간에 실행하지 않으면 의미가 없습니다.
즉, 신뢰성이 높은 메시지 배송을 실현하려면 중간 경로를 모두 at least once로 통일한 후 클라이언트 상에서 모든 메시지에 고유 ID를 포함하도록 하고 경로의 말단에서 중복 제거를 실행해야 합니다.
시계열 데이터 최적화
이벤트 시간과 프로세스 시간
클라이언트 상에서 메시지가 생성된 시간을 이벤트 시간, 서버가 처리하는 시간을 프로세스 시간이라 합니다.
스마트 폰에서 데이터를 수집하면 메시지가 며칠 늦게 도착하는 일은 드물지 않습니다.
왜냐하면 사용자가 전파가 닿지 않는 곳으로 외출하거나 배터리가 완전히 방전될 수도 있기 때문입니다.
그렇기에 며칠 정도의 지연을 예측해서 데이터 분석을 고려해야 합니다.
주로 데이터 분석의 대상은 이벤트 시간이기 때문에 이 두 시간의 차이가 문제를 일으킵니다.
예를 들어, 과거 특정일 1월 1일에 대한 이벤트를 집계한다고 하면 한달 뒤인 2월 1일까지의 모든 파일을 열고 거기에 1월 1일 데이터를 뽑아내면 비교적 정확한 결과를 얻을 수 있습니다.
하지만 데이터가 이벤트 시간으로 정렬되어 있지 않기 때문에 한달 동안의 모든 데이터를 로드해야 원하는 이벤트 시간이 포함되어 있는지 알 수 있기 때문에 시간과 자원을 많이 낭비하게 됩니다.
시계열 인덱스
이벤트 시간에 의한 집계의 효율화를 위한 방법 중 하나로 이벤트 시간에 대해 인덱스를 만드는 것입니다.
Cassandra와 같은 시계열 인덱스에 대응하는 분산 데이터베이스를 이용하여 처음부터 이벤트 시간으로 인덱스 된 테이블을 만들 수 있습니다.
시계열 인덱스를 사용하면 매우 짧은 범위의 특정 시간에 맞춘 데이터 집계를 빠르게 실행할 수 있습니다.
정해진 시간에 발생한 이벤트를 조사하거나, 실시간 대시보드를 만드는 경우에 유용합니다.
하지만 장기간에 걸쳐서 대량의 데이터를 집계하는 경우에는 분산 데이터베이스가 그다지 효율적이지 않기 때문에 장기적인 데이터 분석은 집계 효율이 높은 열지향 스토리지를 지속적으로 만들어야 합니다.
조건절 푸쉬다운
이벤트 시간에 의한 집계의 효율화를 위한 방법 중 하나로 매일 한번씩 새로 도착한 데이터를 배치 처리로 변환하는 것입니다.
열지향 스토리지에서는 RDB와 동등한 인덱스를 만들 수 없지만, 처음에 데이터를 정렬할 수 있습니다.
이벤트 시간으로 데이터를 정렬한 후에 열지향 스토리지로 변환하도록 합니다.
열지향 스토리지는 칼럼 단위의 통계 정보를 이용하여 이벤트 시간의 최솟값(시작 시각)과 최댓값(종료 시각) 정보를 얻을 수 있습니다.
이 정보를 이용하면 파일의 어떤 부분에 원하는 데이터가 포함되어 있는지 알 수 있습니다.
이 통계를 이용하여 필요 최소한의 데이터만을 읽도록 하는 최적화를 조건절 푸시 다운이라고 합니다.
시계열 테이블
조건절 푸시 다운에서 데이터 검색을 효율적으로 하는 방법이 있습니다.
앞의 글에서 테이블 포지셔닝에 대해 설명을 했고, 그 중 시간을 이용하여 분할된 테이블을 시계열 테이블이라고 합니다.
그러면 새로운 데이터들이 오면 이벤트 시간에 해당하는 파티션이 있다면 데이터를 추가하고, 없다면 파티션을 만들어 추가하면 됩니다.
하지만 새로운 데이터 때문에 새로운 파티션을 만드는 것은 잠재적인 문제가 있습니다.
계속해서 새로운 데이터가 추가된다면 결국 분산 스토리지에는 대량의 작은 파티션들이 만들어지게 되고 점차 쿼리의 성능이 악화됩니다.
그렇기때문에 작은 데이터를 효율적으로 추가할 수 있는 분산 데이터베이스를 사용하거나 오래된 데이터는 버리는 방법이 필요합니다.
데이터 마트를 이벤트 시간으로 정렬
데이터 검색에 더 좋은 방법은 데이터 마트만이 이벤트 시간에 의한 정렬을 고려하도록 하는 것입니다.
즉, 데이터 마트를 만드는 단계에서 이벤트 시간에 의한 정렬을 함께 하도록 하는 것입니다.
그러면 파일이 조각나는 일도 없고, 항상 최적의 데이터 마트를 유지할 수 있습니다.
NoSQL 데이터베이스
NoSQL 데이터베이스는 비구조화 데이터 분산 스토리지로 사용할 수 있습니다.
NoSQL 데이터베이스의 구조는 분산 KVS, 와이드 칼럼 스토어, 다큐먼트 스토어가 있습니다.
분산 KVS
분산 KVS는 모든 데이터를 키값 쌍으로 저장하도록 설계된 데이터 저장소입니다.
모든 데이터에 고유의 키를 지정하고 그것을 부하 분산을 위해 이용합니다.
키가 정해지면 그 값을 클러스터 내의 어느 노드에 배치할 것인지 결정합니다.
이 구조에 의해 노드간에 부하를 균등하게 분산하고 노드를 증감하는 것만으로 클러스터의 성능을 변경할 수 있게 되어 있습니다.
가장 간단한 경우에 하나의 키에 하나의 값을 할 수 있습니다.
시스템에 따라서는키에 여러 값을 할당하거나, 반대로 여러 키 조합에 값을 할당할 수 있습니다.
분산 KVS 아키텍처에는 마스터/슬레이브 형, P2P 형이 있습니다.
마스터/슬레이브 형은 1대의 마스터가 전체를 관리하게 되어있고 마스터가 중지되면 아무도 데이터를 읽고 쓸 수 없습니다.
P2P 형은 모든 노드가 대등한 관계이기 때문에 클라이언트는 어떤 노드에 연결해도 데이터를 읽고 쓸 수 있습니다.
마스터/슬레이브 형과 P2P 형 예시
클라우드 서비스로 Amazon DynamoDB 등이 있습니다.
와이드 칼럼 스토어
와이드 칼럼 스토어는 2개 이상의 임의의 키에 데이터를 저장할 수 있도록 한 것입니다.
내부적으로 행 키와 칼럼 명의 조합에 대해 값을 지정합니다.
테이블에 새로운 행을 추가는 것과 마찬가지로 칼럼도 추가할 수 있습니다.
즉, 하나의 테이블에 가로 세로 2차원에 데이터를 쓸 수 있도록 한 것입니다.
와이드 칼럼 스토어 예시
클라우드 서비스로 Google Cloud Bigtable, 오픈 소스로 Apache HBase, Apache Cassandra 등이 있습니다.
다큐먼트 스토어
와이드 칼럼 스토어가 주로 성능 향상을 목표로 한다면, 다큐먼트 스토어는 데이터 처리의 유연성을 목적으로 합니다.
JSON처럼 복잡하게 뒤얽힌 스키마리스 데이터를 그대로의 형태로 저장하고 쿼리를 실행할 수 있도록 합니다.
물론 간단한 분산 KVS도 JSON 텍스트로 저장할 수 있지만, 그에 대한 복잡한 쿼리를 실행할 수 있다고 할 순 없습니다.
다큐먼트 스토어는 배열과 연상 배열과 같은 중첩된 데이터 구조에 대해 인덱스를 만들거나 다큐먼트 일부만을 치환하는 식의 쿼리를 쉽게 실행할 수 있습니다.
다큐먼트 스토어는 외부에서 들여온 데이터를 저장하는데 특히 적합합니다.
보통 자체 개발한 애플리케이션 등에서는 명시적으로 스키마를 정하는 편이 좋은 점이 많기 때문에 주로 참고 시스템의 데이터 및 로그 저장 등에 적합니다.
오픈 소스로 MongoDB 등이 있습니다.
ACID 특성
ACID 특성은 트랜잭션 처리에 요구되는 4가지 성질을 말합니다.
원시성(atomicity)
일관성(consistency)
독립성(isolation)
내구성(durability)
원자성(Atomicity)은 트랜잭션과 관련된 작업들이 부분적으로 실행되다가 중단되지 않는 것을 보장하는 능력이다. 예를 들어, 자금 이체는 성공할 수도 실패할 수도 있지만 보내는 쪽에서 돈을 빼 오는 작업만 성공하고 받는 쪽에 돈을 넣는 작업을 실패해서는 안된다. 원자성은 이와 같이 중간 단계까지 실행되고 실패하는 일이 없도록 하는 것이다.
일관성(Consistency)은 트랜잭션이 실행을 성공적으로 완료하면 언제나 일관성 있는 데이터베이스 상태로 유지하는 것을 의미한다. 무결성 제약이 모든 계좌는 잔고가 있어야 한다면 이를 위반하는 트랜잭션은 중단된다.
독립성(Isolation)은 트랜잭션을 수행 시 다른 트랜잭션의 연산 작업이 끼어들지 못하도록 보장하는 것을 의미한다. 이것은 트랜잭션 밖에 있는 어떤 연산도 중간 단계의 데이터를 볼 수 없음을 의미한다. 은행 관리자는 이체 작업을 하는 도중에 쿼리를 실행하더라도 특정 계좌간 이체하는 양 쪽을 볼 수 없다. 공식적으로 고립성은 트랜잭션 실행내역은 연속적이어야 함을 의미한다. 성능관련 이유로 인해 이 특성은 가장 유연성 있는 제약 조건이다. 자세한 내용은 관련 문서를 참조해야 한다.
지속성(Durability)은 성공적으로 수행된 트랜잭션은 영원히 반영되어야 함을 의미한다. 시스템 문제, DB 일관성 체크 등을 하더라도 유지되어야 함을 의미한다. 전형적으로 모든 트랜잭션은 로그로 남고 시스템 장애 발생 전 상태로 되돌릴 수 있다. 트랜잭션은 로그에 모든 것이 저장된 후에만 commit 상태로 간주될 수 있다.
일반적인 RDB는 이들을 충족하고 있어 신뢰성 있는 트랜잭션 처리를 실현하고 있습니다.
CAP 정리
ACID 특성을 만족하면서 분산 시스템을 구축하는 것은 어렵기 때문에 그 한계에 대해서 제창된 것이 CAP 정리입니다.
일반적으로 분산 시스템에서는 다음 3가지를 동시에 충족시킬 수 없어 어느 하나가 희생될 수 있습니다.
일관성(consistency)
가용성(availability)
분단내성(partition-tolerance)
CAP 정리는 제한된 조건에서만 성립하며, 분산 시스템에서 트랜잭션 처리를 실행할 수 없다는 의미는 아닙니다.
그러나 실제 NoSQL 데이터베이스 중에는 성능상의 이유로 ACID 특성을 충족하지 않는 것도 있으므로 주의가 필요합니다.
결과 일관성
NoSQL 데이터베이스의 일부는 CAP 정리의 일관성이나 가용성 중 하나를 선택합니다.
일관성을 선택하면 단시간의 장애 발생을 수용한다는 것이고, 가용성을 선택하면 오래된 데이터를 읽을 수 있도록 한다는 것입니다.
그 중 자주 볼 수 있는 것이 결과 일관성의 개념으로 써넣은 데이터를 바로 읽을 수 있다고는 말할 수 없다는 것입니다.
결과 일관성은 시간이 지나면 언젠가 최신 데이터를 읽을 수 있음을 보장하지만 그게 언제가 될지는 알 수 없습니다.
검색 엔진
NoSQL 데이터베이스와는 조금 성격이 다르지만, 저장된 데이터를 쿼리로 찾아낸다는 점에서는 유사한 부분도 많고, 특히 텍스트 데이터 및 스키마리스 데이터를 집계하는데 자주 사용됩니다.
검색 엔진의 특징은 텍스트 데이터를 전문 검색하기 위해 역 색인을 만듭니다.
역 색인을 만들기 때문에 데이터를 기록하는 시스템 부하 및 디스크 소비량은 커지지만, 그 덕분에 키워드 검색이 훨씬 고속화 됩니다.
만약 역 색인이 없다면 모든 텍스트를 전체 스캔해야 원하는 레코드를 찾을 수 있기에 검색 효율이 크게 저하됩니다.
대부분의 NoSQL 데이터베이스가 성능 향상을 위해 색인 작성을 제한하고 있는 것과 대조적으로 적극적으로 색인을 만들어서 데이터를 찾는 것에 특화 되어 있습니다.
결과적으로 검색 엔진은 데이터의 집계에 적합하며, 특히 비정상적인 상태의 감지 및 보안 체크, 고객 서포트처럼 민첩성이 요구되는 용도에서 최근의 데이터를 보기 위해 사용됩니다.
그래서 검색 엔진은 장기적으로 데이터를 축적하기보다는 실시간 집계 시스템의 일부로 이용됩니다.
자연 언어로 작성된 텍스트 데이터, 이미지, 동영상 등의 미디어 데이터 처럼 스키마가 없는 데이터를 비구조화 데이터라고 합니다.
스키마리스 데이터
CSV, JSON, XML 등의 데이터처럼 서식은 정해져있지만, 칼럼 수나 데이터형은 명확하지 않은 데이터를 스키마리스 데이터라고 합니다.
데이터 구조화 파이프라인
SQL로 테이블을 집계하기 위해서는 비구조화 데이터와 스키마리스 데이터를 구조화 데이터로 변환시킬 필요가 있습니다.
데이터 구조화 파이프라인 예시
하둡(Hadoop)
현재는 빅데이터를 대표하는 분산 처리 프레임워크입니다.
분산 시스템을 구성하는 다수의 소프트웨어로 이루어져 있습니다.
하둡에서 사용할 수 있는 열 지향 스토리지에는 몇가지 종류가 있습니다.
그 중 Apache ORC는 구조화 데이터를 위한 스토리지로 스키마를 정한 후 데이터를 저장합니다.
Apache Parquet은 스키마리스에 가까운 데이터 구조로 되어있어서 JSON과 같은 데이터를 그대로 저장할 수 있습니다.
분산 시스템의 구성 요소
하둡의 기본 구성 요소는 분산 파일 시스템인 HDFS, 리소스 관리자인 YARN, 분산 데이터 처리의 기반인 MapReduce 이렇게 3가지입니다.
그 외의 프로젝트는 하둡 본체와는 독립적으로 개발되어 하둡을 이용한 분산 애플리케이션으로 동작합니다.
모든 분산 시스템이 하둡에 의존하는 것이 아니라 하둡의 일부만 사용하거나 혹은 전혀 이용하지 않는 구성도 있습니다.
예를 들어 분산 파일 시스템은 HDFS, 리소스 관리자는 Mesos, 분산 데이터 처리는 Spark를 사용하는 것입니다.
즉, 다양한 소프트웨어들 중에서 자신에게 맞는 것을 선택하고 조합하여 사용하면 됩니다.
하둡 분산 시스템 예시
분산 파일 시스템과 리소스 관리자
하둡에서 처리되는 데이터 대부분은 분산 파일 시스템인 HDFS에 저장됩니다.
다수의 컴퓨터에 파일을 복사하여 중복성을 높인다는 특징이 있습니다.
CPU나 메모리 등의 계산 리소스는 리소스 관리자인 YARN에 의해 관리됩니다.
YARN은 애플리케이션이 사용하는 CPU 코어와 메모리를 컨테이너 단위로 관리합니다.
하둡에서 분산 애플리케이션을 실행하면 YARN이 클러스터 전체의 부하를 보고 비어 있는 호스트부터 컨테이너를 할당합니다.
리소스 관리자는 어느 애플리케이션에 얼마만큼의 리소스를 할당 할 것인지를 관리하여 모든 애플리케이션이 차질없이 실행되도록 제어합니다.
그리고 애플리케이션마다 실행 우선순위를 결정할 수 있습니다.
즉, 덜 중요한 애플리케이션에 낮은 우선순위를 부여해서 아무도 리소스를 사용하지 않을 경우에만 실행하는 등, 높은 우선순위부터 실행함으로써 한정된 리소스를 낭비없이 활용하면서 데이터 처리를 진행할 수 있습니다.
분산 데이터 처리 및 쿼리 엔진
MapReduce는 YARN 상에서 동작하는 애플리케이션 중 하나이며, 분산 시스템으로 데이터 처리를 실행하는데 사용합니다.
비구조화 데이터를 가공하는데 적합하고 한번 실행으로 대량의 데이터를 읽을 수 있습니다.
하지만 작은 프로그램을 실행하면 오버헤드가 너무 크기 때문에 몇 초 안에 끝나는 쿼리 실행에는 적합하지 않습니다.
SQL 등의 쿼리 언어에 의한 데이터 집계가 목적인 쿼리 엔진 중 Apache Hive가 있습니다.
Apache Hive는 MapReduce의 성질을 계승하였기 때문에 시간이 걸리는 배치 처리에는 적합하나 애드 혹 쿼리를 여러번 실행하는데는 적합하지 않습니다.
Hive on Tez
Hive를 가속화하기 위해 개발된 것이 Apache Tez입니다.
Tez는 기존의 MapReduce를 대체할 목적으로 개발된 프로젝트이며, MapReduce에 있던 몇가지 단점을 해소함으로써 고속화를 실현했습니다.
현재의 Hive는 MapReduce뿐만 아니라 Tez에도 동작하도록 되어있습니다.
이것을 Hive on Tez라고 불리고 예전 Hive는 Hive on MR이라 불립니다.
대화형 쿼리 엔진
Hive를 고속화하는 것이 아닌, 처음부터 대화형의 쿼리 실행만을 전문으로 하는 쿼리 엔진 중 Apache Impala와 Presto가 있습니다.
대화형 쿼리 엔진은 순간 최대 속도를 높이기 위해 모든 오버헤드가 제거되어 사용할 수 있는 리소스를 최대한 활용하여 쿼리를 실행합니다.
그 결과 MPP 데이터베이스와 비교해도 꿀리지 않는 응답속도를 가졌습니다.
대량의 비구조화 데이터를 가공하는 무거운 배치 처리에는 높은 처리량을 가진 Hive를 이용하고, 그렇게 해서 만들어진 구조화 데이터를 대화식으로 집계하고자 할 때 지연이 적은 Impala와 Presto를 이용합니다.
하둡에서는 다수의 쿼리 엔진이 개발되어 있으며, 그것들을 총칭해 SQL-on-Hadoop이라 불립니다.
Spark
Apache Spark는 하둡과는 다른 독립된 프로젝트입니다.
컴퓨터에서 취급하는 메모리의 양이 증가함에 따라 대량의 메모리를 활용하여 고속화를 실현한 것이 Spark의 특징입니다.
이 경우 컴퓨터가 비정상 종료되면 중간 데이터들이 사라져 버리지만, 처리를 다시 시작해서 중간 데이터를 다시 만들면 됩니다.
Spark는 하둡을 대체하는 것이 아니라 MapReduce를 대체하는 존재입니다.
즉, 분산 파일 시스템 HDFS, 리소스 관리자 YARN, 분산 데이터 처리 Spark로 쓸 수 있습니다.
Spark 상에서 실행되는 데이터 처리는 스크립트 언어를 사용할 수 있습니다.
표준으로 자바, 스칼라, 파이썬 그리고 R언어가 있습니다.
Spark에서는 SQL로 쿼리를 실행하기 위한 Spark SQL과 스트림 처리를 수행하기 위한 Spark Streaming 기능이 있습니다.
그래서 대규모 배치 처리뿐만 아니라 대화형 쿼리 실행과 실시간 스트림 처리에도 이용되고 있습니다.
비정규화 테이블 만들기
데이터의 구조화가 끝나면 다음은 데이터 마트의 구축을 합니다.
즉, 테이블을 결합 및 집약해서 비정규화 테이블을 만듭니다.
이때 Hive와 같은 배치형 쿼리 엔진을 사용할 것인지 Presto와 같은 대화형 쿼리 엔진을 사용할 것인지 선택할 수 있습니다.
Hive
시간이 걸리는 배치 처리는 원칙적으로 Hive를 사용합니다.
비정규화 테이블을 만드는데 오랜 시간이 걸리는 것은 흔한 일이며, 그렇기에 효율적인 쿼리를 작성해야 합니다.
Hive의 쿼리를 개선하는 예로 서브 쿼리 안에서 레코드 수 줄이기와 데이터 편향 피하기가 있습니다
서브 쿼리 안에서 레코드 수 줄이기
예시로 모든 데이터를 읽어 들인 후 결합된 테이블을 WHERE 문으로 검색한다고 해봅시다.
테이블을 결합 한 후 WHERE문으로 검색하기 보다는 먼저 WHERE문을 적용하고 테이블을 결합하는 것이 서브 쿼리 안에서 팩트 테이블을 작게 하기 때문에 좀 더 효율적입니다.
즉, 초기에 팩트 테이블을 작게 하여 데이터 양을 줄이는 것입니다.
데이터 편향 피하기
예시로 30일의 기간동안 하루마다의 고유 방문자 수를 알아낸다고 합시다.
그렇다면 보통 날짜별로 GROUP BY를 하고 distinct count로 방문자를 중복제거하여 고유 방문자 수를 구할 것입니다.
이때 날짜별로 GROUP BY를 했기 때문에 하나의 노드에서 하루의 방문자들을 distinct로 중복제거를 할 것입니다.
30일 동안 고유 방문자가 모두 균등하게 방문하였다면 노드에 distinct로 처리해야할 데이터 양이 균등하게 분산이 되어 데이터 편향은 없겠지만, 어느 특정 기간에만 고유 방문자가 많이 방문하였다면 일부 노드에 distinct로 처리해야할 데이터 양이 많아져 데이터편향이 생길 것입니다.
그러면 처음에 distinct로 (날짜, 방문자)를 중복제거하고 날짜별로 GROUP BY하고 방문자 수를 세주는 것이 데이터 편향을 줄임으로써 좀 더 효율적입니다.
즉, 최초에 중복을 제거하여 균등하게 분산 처리를 하는 것입니다.
Presto
작은 쿼리를 여러번 실행하는 대화형 데이터 처리, 쿼리 실행의 지연을 감소시키는 것에 적합한 것이 대화형 쿼리 엔진입니다.
Presto는 그 중 하나입니다.
Presto는 다양한 데이터 소스를 테이블로 참고할 수 있는 플러그인 가능한 스토리지입니다.
예를 들어, 하나의 쿼리 안에서 분산 스토리지 상의 팩트 테이블과 MySQL의 마스터 테이블을 조인할 수 있습니다.
메모리 상에서 할 수 있는 단시간 쿼리 실행에 효율적입니다.
열지향 스토리지에서 집계를 매우 빠르게 실행합니다.
데이터 마트 구축
팩트 테이블의 작성에는 추가와 치환 두가지 방법이 있습니다.
추가는 새로 도착한 데이터만을 증분으로 추가하는 것이고, 치환은 과거의 데이터를 포함하여 테이블 전체를 치환하는 것입니다.
추가
효율만을 생각하면 추가가 압도적으로 좋으나 잠재적인 문제가 있습니다.
첫째, 추가에 실패한 것을 알아채지 못하면 팩트 테이블의 일부에 결손이 발생합니다.
둘째, 추가를 잘못해서 여러번 실행하면 팩트 테이블의 일부가 중복됩니다.
셋째, 나중에 팩트 테이블을 다시 만들고 싶은 경우의 관리가 복잡해집니다.
이러한 문제가 일어날 가능성을 줄이기 위해 테이블 파티셔닝이라는 기술을 사용합니다.
테이블 파티셔닝
테이블 파티셔닝은 하나의 테이블을 여러 물리적인 파티션으로 나눔으로써 파티션 단위로 정리하여 테이터를 쓰거나 삭제할 수 있도록 한 것입니다.
일반적으로 1일 1회, 또는 1시간에 1회라는 식으로 자주 새 파티션을 만들고 그것을 팩트 테이블에 붙입니다.
각 파티션은 매번 교체하도록 하고 만약 이미 존재한다면 덮어씁니다.
이렇게 하면 데이터가 중복될 가능성을 배제하면서 필요에 따라 여러번 데이터의 기록을 바로 잡을 수 있습니다.
테이블 파티셔닝 예시
치환
데이터 파티셔닝은 데이터 웨어하우스를 구축하는데 유용합니다.
데이터 마트를 만드는 경우에는 단순히 팩트 테이블을 치환하는 경우가 많을 수도 있습니다.
왜냐하면 상당히 거대한 테이블을 만들지 않는 한 매번 치환하기는 어렵지않기 때문입니다.
예를 들어, 일일 보고서를 위해 지난 30일 동안의 데이터를 매일 꺼내서 치환하는 식입니다.
테이블 파티셔닝과 치환 예시
치환은 처리 시간이 우려되는 방법이지만 많은 장점이 있습니다.
첫째, 중간에 데이터가 중복되거나 빠드릴 가능성이 없습니다.
둘째, 테이블을 처음부터 다시 만들고 싶다면 쿼리를 한번 실행하기만 하면 됩니다.
셋째, 스키마 변경 등에도 유연하게 대응할 수 있습니다.
넷째, 오래된 데이터는 자동으로 지워지기 때문에 데이터 마트가 계속 확대되는 일은 없습니다.
만약 데이터 양이 너무 많아 처리 시간이 너무 오래 걸린다면 데이터 마트 측에도 테이블 파티셔닝을 하거나 기존의 테이블에 추가한 다음 주의 깊게 모니터링을 해야할 것입니다.
집계 테이블
팩트 테이블을 어느 정도 모아서 집계하면 데이터의 양이 크게 줄어드는데 이것을 집계 테이블이라고 합니다.
특히 1일 단위로 집계한 일일 집계는 일일 보고서를 만드는데 자주 사용됩니다.
집계 테이블을 만들기 위해서는 필요한 칼럼을 골라 숫자 데이터를 집계하면 됩니다.
이때, 각 칼럼이 취하는 값의 범위를 카디널리티라고 합니다.
카디널리티를 너무 적으면 원래 있던 정보가 크게 손실되고 너무 많으면 시각화의 효율을 낮춥니다.
그렇기에 균형에 맞춰서 카디널리티를 정해야합니다.
스냅샷 테이블
마스터 데이터처럼 업데이트될 가능성이 있는 테이블에 대한 방안 중 하나로 정기적으로 테이블을 통째로 저장하는 것을 스냅샷 테이블이라고 합니다.
스냅샷의 날짜를 지정하여 과거의 마스터 테이블을 언제든지 볼 수 있고, 팩트 테이블과 스냅샷 테이블을 날짜를 포함해서 결합할 수 있습니다.
이것은 매일 변화하는 마스터 정보를 이용하여 데이터를 분석하고 싶을 때 유용합니다.
스냅샷은 특정 시점의 테이블의 상태를 기록한 것이므로 나중에 다시 만들 수 없습니다.
그렇기에 데이터 레이크나 데이터 웨어하우스와 같은 영구적인 저장소에 보관하여 삭제되지 않도록 합니다.
이력 테이블
마스터 데이터처럼 업데이트될 가능성이 있는 테이블에 대한 방안 중 하나로 변경된 데이터만 저장하는 것을 이력 테이블이라고 합니다.
이력 테이블은 데이터의 양을 줄이는데 도움이 되지만, 어느 순간의 완전한 마스터 테이블을 나중에 복원하는 것이 어려워지므로, 디멘전 테이블로는 사용하기 힘듭니다.