빅쿼리 파티셔닝과 클러스터링에 대한 이해

빅쿼리는 대용량 데이터 처리를 위해 데이터를 일별로 분리해서 분할 저장하는 파티셔닝 기능을 제공한다. 파티셔닝은 테이블에 파티션 데코레이터를 지정해서 UTC 타임존 기준 원하는 날짜 혹은 데이터 생성 날짜로 데이터를 분할 저장하는 기법이다. 데이터가 날짜 범위로 분할되어 저장하기 때문에 쿼리 요청시 분할 날짜를 이용하여 처리 대상 데이터의 범위를 줄일 수 있는 장점을 가진다.

하지만 파티셔닝은 일기준으로만 데이터가 분할되기 때문에 클러스터링 기능을 통해 특정 필드 기준으로 데이터를 분할 저장하게 할 수도 있다. 클러스터링은 데이터의 특정 필드값(최대4개)을 기준으로 데이터를 정렬한 후 최적화된 크기로 각 파티션안에서 또다시 저장소를 분리하여 저장한다. 날짜를 기준으로 분할되지 않고 특정 필드값을 기준으로 정렬되기 때문에 좀더 유연하게 쿼리의 처리 대상이 되는 데이터의 범위를 줄일 수 있게 된다.

하지만 파티셔닝과 클러스터링이 적용되지 않더라도 크게 걱정하지는 말자. 빅쿼리는 같은 쿼리문의 결과에 대해서는 24시간 가량 캐시가 되고 캐시가 된 쿼리 결과를 다시 요청할때는 비용이 추가로 발생하지 않는다. 또한 테라바이트 수준의 데이터에 대해서도 쿼리 속도가 1~2초 가량 밖에 걸리지 않기 때문에 성능 문제도 없다.

파티셔닝

파티셔닝은 하나의 테이블을 파티션이라는 단위로 분할하여 저장한다. 데이터 변환기는 테이블을 일별로 나눠서 저장하게 되어 쿼리에서 읽는 범위를 줄여서 쿼리의 성능을 높일 수 있다. BigQuery는 테이블을 수집 시간 기준일이나 지정한 시간 기준일로 나눌 수 있다. 데이터를 처리시 BigQuery 테이블 대상을 지정할때 다음과 같이 테이블명 뒤에 수집 시간 날짜를 포함한 것을 볼 수 있다.

fast-archive-274910:dw_datadriver.googlefitness_tbl_bd_datasets$20020519

위와 같이 파티션 데코레이터 지정을 하면 특정 날짜를 기준으로 데이터를 분할해서 저장할 수 있다. 만약 파티션 데코레이션 지정을 하지 않고 다음과 같이 저장할 테이블 대상을 지정한다면 데이터가 생성되는 시점의 시간을 기준으로 데이터가 분할되므로 여러날의 데이터를 처리해도 무조건 처리 시점의 날짜 기준 파티션에 데이터가 모두 추가된다.

fast-archive-274910:dw_datadriver.googlefitness_tbl_bd_datasets

파티션을 나눈 테이블을 적용한 데이터 변환기에 의해 생성된 테이블의 정보는 다음과 같다.

데이터 변환기 소스코드 살펴보기-파티셔닝테이블.png

이때 분할 기준은 일(Day)로 지정되어 있고 분할 입력란이 수집 날짜 기준으로 파티셔닝 되어 있다는 표시인 _PARTITIONTIME 으로 지정되 있는 것을 볼 수 있다. 테이블명에 수집날짜을 20200522로 지정했으므로 _PARTITIONTIME 역시 2020년 5월 22일로 저장되어 있을 것이다. 빅쿼리에서 다음 쿼리를 실행해보자

SELECT DATE(_PARTITIONTIME) as date, * FROM `fast-archive-274910.dw_datadriver.googlefitness_tbl_bd_datasets`;

면 각 열의 수집 시간이 모두 2002년 5월 19일로 되어 있는 것을 확인할 수 있다.

데이터 변환기 소스코드 살펴보기-파티션시간쿼리결과.png

이후 이렇게 수집된 날짜의 정보인 _PARTITIONTIME 을 기준으로 쿼리를 요청하면 쿼리에서 읽는 범위를 제한할 수 있기 때문에 계속 데이터가 추가되더라도 데이터베이스의 전체적인 성능이 저하되지 않게 된다. 파티셔닝 기능을 쓰지 않거나 검색 쿼리에 _PARTITIONTIME을 지정하지 않으면 전체 테이블에 대해 조회가 일어나므로 서비스 사용 비용이 늘어날 것이므로 주의가 필요하다.

예를 들어 다음과 같이 전체 테이블을 대상으로 쿼리를 요청한 후 화면 하단의 실행정보 탭을 살펴보자. 다음과 같이 쿼리가 1.3MB의 데이터를 대상으로 입력과 출력 모두 5,546개의 행의 정보를 처리한 것을 볼 수 있다.

빅쿼리 파티셔닝의 원리-파티셔닝쿼리1.png

하지만 다음과 같이 _PARTITIONTIME으로 조건을 걸면 869.2KB를 대상으로 3652개 행의 정보만을 처리하는 것을 확인할 수 있다.

빅쿼리 파티셔닝의 원리-파티셔닝쿼리2.png

따라서 데이터 분석을 위해 테이블 정보에 접근할때 최대한 파티셔닝 처리를 되게끔 주의하면서 사용해야 한다. 이 책의 예제에서는 UTC기준의 데이터를 한국 기준 타임존으로 모두 변환해서 출력하기 때문에 파티셔닝이 적용되는 쿼리를 사용하고 있지는 않다. 하지만 특정 기간 동안의 결과가 보여주는 리포트를 추가로 만든다면 파티셔닝을 적용하여 성능을 올릴 수 있을 것이다.

클러스터링

파티션을 나눈 테이블을 만들고 클러스터링을 설정한 테이블의 정보는 다음과 같다. 맨 아래를 살펴보면 클러스터링 기준에 user_id 필드값이 포함된 것을 볼 수 있다. 만약 여러면의 데이터가 들어온다면 앞서 설명한 파티셔닝을 이용해서는 원하는 유저별로 데이터 처리 대상을 줄일 수 없다. 이때 클러스터링 필드를 사용해서 유저 아이디별로 데이터 처리 대상을 분할할 수 있다.

클러스터링테이블3234.png

다음 쿼리문을 통해 파티셔닝이 적용되는 쿼리를 살펴보자.

SELECT * FROM `fast-archive-274910.dw_datadriver.rescuetime_tbl_bd_data` WHERE DATE(_PARTITIONTIME) = "2020-04-16"

다음과 같이 전체 행 866개중 396행을 대상으로 30.4KB 만의 데이터를 대상으로 쿼리 처리가 발생한 것을 볼 수 있다.

빅쿼리 파티셔닝과 클러스터링-클러스터링처리테스트1111.png

그럼 이제 클러스터링 필드로 설정된 user_id를 조건으로 쿼리를 실행해보자. 현재 이 테이블에는 미리 여러명의 user_id를 가진 데이터를 입력해 둔 상태이다

SELECT * FROM `fast-archive-274910.dw_datadriver.rescuetime_tbl_bd_data` WHERE user_id = "leeteam"

역시 866행중 433행을을 대상으로 47.9KB 데이터에 대한 쿼리 처리가 발생한 것을 볼 수 있다.

빅쿼리 파티셔닝과 클러스터링-클러스터링테스트2222.png

이렇게 파티션 날짜 기준뿐만 아니라 클러스터링을 이용하면 특정 필드값을 대상으로도 비용을 아낄 수 있는 쿼리를 요청할 수 있게 된다.

쿼리 효율성 테스트하기

구글 클라우드 플랫폼 웹사이트에서 쿼리를 요청하면 쿼리가 처리하는 데이터의 크기를 알 수 있다. 이를 그건로 쿼리의 효율성과 비용을 예상해볼 수 있다. 다만 빅쿼리는 캐시 기능이 있어서 같은 문장의 쿼리를 중복 요청하면 쿼리를 실행하지 않고 기존의 캐시되어 있는 결과를 보여주기 때문에 효율성 체크를 위해서는 캐싱 옵션을 해제하고 테스트해야 한다.

01. 쿼리 편집기에서 쿼리 설정 메뉴를 클릭한다.

빅쿼리 파티셔닝과 클러스터링-쿼리 옵션 수정.png

02. 리소스 관리 영역에서 “캐시 처리된 결과 사용” 을 체크해제 한후 “저장” 버튼을 클릭한다.

빅쿼리 파티셔닝과 클러스터링-캐시해제.png

이제 캐싱된 쿼리 결과를 사용하지 않는다. 해당 옵션은 웹페이지의 쿼리 편집기에서 캐시를 해주기 때문에 다른 곳에는 영향을 주지 않는다.

03. 테스트할 쿼리를 입려한다. 쿼리 입력시 오른쪽에 “실행 시 이쿼리가 XKB를 처리합니다” 라는 문구가 등장한다. 이 문자은 쿼리 실행전에 데이터 처리의 양을 예측해주는 기능이다. 실제 과금되는 데이터 처리량은 쿼리 후 결과를 보고 분석하는 것이 정확하다.

빅쿼리 파티셔닝과 클러스터링-예상비용.png

04. 쿼리를 요청하면 쿼리 완료 문자열 오른쪽에 처리시간과 처리된 데이터 용량이 출력된다. 그리고 실행 세부정보 탭에는 몇행의 데이터가 처리 대상에 포함되었는지 확인할 수 있다. 이 용량과 행의 수를 테이블의 전체 데이터양과 행의 수와 비교해서 얼마나 효율적으로 처리되었는지 확인할 수 있다.

빅쿼리 파티셔닝과 클러스터링-쿼리효율성확인하기.png

구글클라우드플랫폼 요금 계산하기


GCP 과금에 관한 자세한 내용은 구글 클라우드 플랫폼에 사이트에 정리되어 있고 GCP 과금 계산기(https://cloud.google.com/products/calculator/)를 이용해 자세하게 계산할 수 있다. 이 문서는 데이터 분석 파이프라인에 사용되는 각 GCP 서비스가 어떤 방식으로 과금 하는지에 대해 대략적으로 이해하는데 도움을 주고자 제작한 문서이다. 해당 글은 모두 도쿄 리전 기준으로 설명한다.

클라우드 펍섭

https://cloud.google.com/pubsub/pricing

월 데이터 전송 10GiB까지 무료이다. 이후에는 데이터 전송량에 따라 1TiB당 60$~40$가 과금된다. 오퍼레이션이 발생하는 데이터 전송을 모두 과금하므로 특정 토픽에 1Tib의 데이터가 퍼블리시(메시지 전송)되었고 구독자가 두개 등록되어 있을 경우 총 데이터 전송량은 3Tib(Message byes + (Message byes x Subscription count))가 발생하게 된다.

클라우드 스토리

https://cloud.google.com/storage/pricing?hl=ko

보관 비용

Regional Storage 기준 월 1GB 보관 비용이 0.023$가 든다.

오퍼레이션 비용

여기에 버킷의 객체의 생성, 삭제, 복사등의 작업에 대한 과금이 발생한다. A등급과 B등급에 따라 10,000개 작업당 0.05$ ~ 0.004$의 비용이 발생한다.

네트워크 트래픽 비용

같은 리전에 존재하는 다른 GCP 서비스를 통해 버킷에 접근 하는 경우와 같은 리전의 버킷간에 데이터 이동과 복사할때는 네트워크 사용량이 청구되지 않난다.

클라우드 데이터플로우

https://cloud.google.com/dataflow/pricing

배치

배치 처리는 잡을 요청 받은뒤에 생성된 워커(VM 인스턴스)가 사용한 vCPU, Memory, Storage 자원 사용량에 따라 과금하는 방식이다. 다음은 워커가 사용된 자원양에 따른 과금액이다. 잡이 요청되면 기본적으로 1 vCPU, 3.75GB memory, 250GB Persistent Disk의 자원을 사용하는 배치 워커가 생성된다.

  • 1 vCPU 시간당 $0.0728
  • 1 GB Memory 시간당 $0.0046241
  • 1 GB Storage 시간당 $0.0000702

다음 화면과 같이 GCP의 웹 UI를 통해 특정잡에서 사용된 모든 워커의 자원 사용량을 확인할 수 있고 시간 기준으로 vCPU 사용량을 출력해주기 때문에 특정 잡을 실행하는데 드는 비용을 쉽게 계산할 수 있다. 화면에 나오는 잡의 모든 워커가 사용한 vCPU 과금양은 0.036(vCPU hr) * $0.0728 = 0.0026208$ 이다.

구글클라우드플랫폼 요금 계산하기-cloudataflow-batch-pricing.png

스트리밍

스트리밍 처리는 24시간 워커가 실행되기 때문에 다음 과금 기준에 24를 곱해주면 워커당 하루의 과금 비용을 알아낼 수 있다. 스트리밍 방식으로 잡 요청할때 워커의 최소~최대 갯수에 따라 워커의 갯수가 자동 조절되며 배치와 다르게 기본적으로 워커가 4 vCPU를 사용하는 것에 유의한다.

  • 1 vCPU 시간당 $0.0897 ( 배치에 비해 vCPU 비용이 10%가량 비싸다)
  • 1 GB Memory 시간당 $0.0046241
  • 1 GB Storage 시간당 $0.0000702

스트리밍 역시 GCP 웹 UI에서 사용된 자원의 양을 살펴볼 수 있다. 539.874 vCPU hr는 모든 워커가 사용한 vCPU 자원량을 의미한다.

구글클라우드플랫폼 요금 계산하기-clouddatflow-streaming.png

빅쿼리

https://cloud.google.com/bigquery/pricing

빅쿼리는 크게 저장 비용과 쿼리 비용을 나눠서 과금된다.

저장 비용

월 10GB 저장량까지는 무료이다. 90일 동안 수정한 테이블에 대한 데이터의 월 비용은 1GB당 0.023$이고 90일동안 수정되지 않은 테이블에 저장된 데이터는 월 비용이 1GB당 0.016$이다.

쿼리 비용

쿼리 비용은 쿼리에 의해 스캔되는 데이터 사이즈(https://cloud.google.com/bigquery/pricing#data)에 따라 결정된다.

월 1TB 까지는 무료이다. 이후에는 1TB당 8.55$가 과금된다.

에어플로우를 통한 스케쥴링 처리

에어플로우 설치

아파치 에어플로우는 데이터 처리 파이프라인을 조율하기 위해 만들어진 오픈 소스 소프트웨어이다. 구글 클라우드 플랫폼은 이를 클라우드 컴포저라는 이름으로 쉽게 사용할 수 있도록 서비스 형태로 제공하고 있다. 하지만 클라우드 컴포저는 쿠버네티스로최소 3개의 워커노드를 사용을 요구하며 그외에 추가적인 부가 사용료를 따져보면 월에 700달러 이상의 요금이 부과된다. 따라서 우리는 컴퓨트 엔진에서 서버 인스턴스를 생성한 후 에어플로우를 설치하는 것으로 한다.

VM 인스턴트 준비하기

에어플로우를 설치할 서버는 구글 컴퓨트엔진을 사용하도록 한다.1. COMPUTE > Compute Engine > VM instances 메뉴를 선택한다.

Datadriver airflow setup1.png

2. CREATE INSTANCES 메뉴를 선택한다.

Datadriver airflow setup2.png

3. 생성할 VM 인스턴트 옵션의 각 항목을 다음과 같이 설정한 후 Create 버튼을 클릭하여 VM 인스턴스를 생성한다.

  • Name: datadriver-airflow
  • Region: asia-northeast1(Tokyo)
  • Zone: asia-northeast1-c
  • Machine type : small(1 shared vCPU)
  • Boot disk: Debian GNU/Linux 9
  • Identifiy and API access
    • Service account: Compute Engine default service account
    • Access scopes : Allow full access to all Cloud APIs
Datadriver-airflow-setup3.png

에어플로우 설치하기

구글 클라우드 플랫폼은 따로 SSH 접속 프로그램 없이도 리눅스 쉘을 실행할 수 있다. 다음과 같인 VM 인스턴스의 SSH 버튼을 눌러서 에어플로우를 설치한 VM 인스턴스에 접속한다.

Datadriver-vm-instance-ssh.png

그리고 쉘에서 다음 명령어를 입력하여 에어플로우를 설치한다. 현재 패키지로 설치되는 에어플로우 버전은 1.10.0 이다. -E를 빠뜨리지 않도록 주의한다. 이 옵션은 사용자가 기존 환경 변수를 보존하기를 원하는 보안 정책을 설정하는 것을 의미한다.

sudo apt-get install -y python3-pip python3-dev build-essential libssl-dev libffi-dev defult-libmysqlclient-dev

export AIRFLOW_GPL_UNIDECODE=y

# Install Airflow with the extra package gcp_api containing the hooks and operators for the GCP services.
sudo -E pip3 install apache-airflow[gcp_api]

AIRFLOW_HOME 위치를 쉘로 접속한 계정의 상위 폴더로 설정한후 에어플로우 데이터베이스를 생성하고 웹서버를 시작한다. -E 옵션을 줘야 AIRFLOW_HOME 위치를 읽을 수 있으므로 빼먹지 않도록 주의한다.

export $AIRFLOW_HOME=~/airflow
sudo -E airflow initdb
sudo -E nohup airflow webserver -p 80 >/dev/null 2>&1 &

에어플로우를 통한 스케쥴링 처리-vm-external-ip.png

에어플로우 웹서버가 시작되었으면 VM 인스턴스의 External IP를 통해 서버에 접속할 수 있다.

브라우저에서 다음과 같은 화면이 나오면 성공적으로 웹서버가 시작된 것이다.

에어플로우를 통한 스케쥴링 처리-web-page.png

에어플로우를 이용해 스케쥴링 처리를 위해서는 스케쥴러 데몬도 실행해야 한다. 이 책에서 데이터 처리를 위해 사용할 서비스는 클라우드 데이터플로우로 자바를 이용해서 개발하므로 쉘에서 다음 명령어를 입력하여 jre 부터 설치를 한다.

sudo apt-get install default-jre

다음 명령어를 통해 스케줄러를 시작한다. 이제 스케쥴러 룰을 정의한 DAG 파일을 처리할 준비가 모두 끝났다.

sudo -E nohup airflow scheduler >/dev/null 2>&1 &

마지막으로 ps ax 명령어로 웹과 스케쥴러 데몬이 모두 정상적으로 떠 있는지 확인한다.

에어플로우를 통한 스케쥴링 처리-psax.png

Hello DAG 작성하기

에어플로우 작업 간의 관계와 흐름을 DAG(Directed Acylic Graph, 방향성 비순환 그래프)로 표현한다. DAG는 파이썬 스크립트를 이용하여 만들어야 한다. 각 작업은 오퍼레이터 클래스를 이용하여 인스턴스화 된다. BashOperator 객체를 이용하여 쉘 명령어를 실행하는 간단한 DAG를 만들어 보자. 먼저 hello_dag.py라는 파이썬 파일을 만들고 다음 소스를 입력한다.

import airflow
from airflow import DAG
from airflow import models
from airflow.operators.bash_operator import BashOperator
from datetime import datetime
from datetime import date, timedelta

# DAG를 언제부터 시작할지 지정한다. 에어플로우에 등록한 이틀 전부터 실행하도록 설정하였다.
default_dag_args = {
        'start_date': airflow.utils.dates.days_ago(2)
}

# 크론탭 방식의 시간 설정 방법으로 DAG의 반복 단위를 설정할 수 있다. 0 0 * * * 은 매일 0시에 실행하라는 의미이다.
dag = models.DAG(
        'hello-dag-v1',
        schedule_interval='0 0 * * *',
        default_args=default_dag_args
)

# BashOperator를 이용하여 echo 커맨드를 실행
run_this = BashOperator(
        task_id='run_bash_operator',
        bash_command='echo hello dag!',
        dag=dag
)

DAG를 등록하려면 VM 인스턴스에 소스파일을 업로드해야 한다. 쉘로 들어간후 다음 명령어로 airflow 폴더 하위에 dags 폴더를 먼저 생성한다. 그리고 스케쥴러와 웹서버를 재실행한다.

cd ~/
sudo mkdir airflow/dags
sudo kill -9 `ps -ef | grep 'scheduler' | grep -v grep | awk '{print $2}'`
sudo -E nohup airflow scheduler >/dev/null 2>&1 &

sudo kill -9 `ps -ef | grep 'webserver' | grep -v grep | awk '{print $2}'`
sudo -E nohup airflow webserver -p 80 >/dev/null 2>&1 &

그리고 cd 명령어로 dags 폴더로 이동후 웹 기반 쉘의 Upload file 메뉴를 통해 hello_dag.py파일을 업로드 한다.Upload files 메뉴는 계정의 홈 폴더로 파일을 업로드하는 기능이다.

내 몸 빅데이터 분석-에어플로우를 통한 스케쥴링 처리-uploadfiles.png

다음 명령어로 홈폴더에 위치한 DAG 파일을 dags 폴더로 이동시킨다.

sudo mv ~/hello-dag.py ~/airflow/dags/

잠시 기다리면 스케쥴러가 DAG를 인식하고 다음 화면과 같이 우리가 작성한 DAG의 이름이 출력된다. OFF라고 적혀있는 토글 버튼을 눌러서 DAG를 활성화 한다.

에어플로우를 통한 스케쥴링 처리-hello-dag-toggle.png

몇분이 지나면 DAG가 우리가 지정한 start_date 부터 시작하고 결과를 보여준다. start_date를 DAG를 활성화한 시점에 이틀전부터 지정했으므로 처리가 완료된 DAG Runs의 갯수가 2개가 뜨는 것을 볼 수 있다.

에어플로우를 통한 스케쥴링 처리-dag-runs-result.png