데이터 웨어하우스 비용 최적화: BigQuery 사용량 모니터링 시스템 구축기

잡플래닛의 BigQuery 사용량 모니터링 시스템 구축으로 데이터 민주화와 비용 최적화에 다가간 사례를 소개합니다.
정성현's avatar
Jun 17, 2024
데이터 웨어하우스 비용 최적화: BigQuery 사용량 모니터링 시스템 구축기

1. 들어가며

안녕하세요. 잡플래닛 Data Insight & Strategy팀(이하 DIS팀)의 Analytics Engineer 정성현입니다.
DIS팀의 미션은 데이터가 흐르는 조직을 만드는 것입니다. DIS팀은 데이터 민주화를 목표로 하고 있으며, 이를 위해 데이터 직군뿐만 아니라 다양한 구성원들이 직접 쿼리를 실행하고 스스로 업무에 활용할 수 있도록 지원하고 있습니다. 그러나 비전문가가 비용 효율적인 쿼리를 작성하는 일은 쉽지 않습니다. 따라서 데이터 마트를 생성하고 쿼리 교육을 제공하는 것뿐만 아니라, 사용량을 모니터링하고 쿼리에 대한 피드백을 제공하는 시스템이 필요했습니다. 또한, Analytics Engineer의 관점에서는 내 구성원들이 주로 조회하는 테이블이 무엇인지, 해당 테이블이 비효율적으로 설계된 것은 아닌지 확인하는 것도 중요했습니다.
이를 위해 BigQuery 사용량을 모니터링하고 높은 사용량의 쿼리가 발생할 경우 자동으로 슬랙 알림을 보내는 기능을 개발했습니다. 이번 포스트에서는 이러한 시스템을 어떻게 구축했는지, 클라우드 비용을 절감하기 위해 어떤 방법을 사용했는지에 대해 설명하겠습니다. 데이터 웨어하우스 비용 최적화와 데이터 민주화 과정에 관심이 있는 분들에게 도움이 되기를 바랍니다.

2. 배경 및 문제점

(이해를 돕기 위한 가상의 대시보드입니다.)
(이해를 돕기 위한 가상의 대시보드입니다.)
잡플래닛은 Metabase를 활용해 대시보드를 만들어 구성원들의 데이터 접근성을 높이고 있습니다. Metabase는 사용자 친화적인 인터페이스를 통해 기술적인 배경이 없는 사용자도 쉽게 사용할 수 있으며, SQL 코드를 작성하지 않고도 데이터를 시각화하고 분석할 수 있습니다. 물론, 필요할 경우 직접 쿼리를 작성하여 원하는 데이터를 조회하고 분석할 수 있어 자유도가 높다는 점이 큰 장점입니다. 사용자 스스로 데이터를 조회하고 인사이트를 도출하여 업무에 적용할 수 있습니다. 잡플래닛의 많은 구성원들이 Metabase를 통해 데이터를 조회하며, 이는 데이터 활용의 장벽을 낮추는 데 크게 기여하고 있습니다.
그러나 Metabase를 사용하는 과정에 두 가지 문제(아쉬운 점)가 있었습니다.
BigQuery Console에서는 예상 처리량을 확인할 수 있음
BigQuery Console에서는 예상 처리량을 확인할 수 있음
  1. BigQuery 콘솔에서는 쿼리를 실행하기 전에 예상 처리량을 확인할 수 있지만, Metabase에서는 이러한 기능이 제공되지 않았습니다.
  1. Metabase는 BigQuery와 연동할 때 서비스 계정을 사용하기 때문에, 쿼리 실행 시 서비스 계정으로 실행되어 누가 얼마나 쿼리를 사용하는지 파악하기 어려웠습니다.
Metabase를 통해 데이터 접근성을 높일 수 있었지만, 데이터 사용량이 급격하게 증가하면서 클라우드 비용도 증가하게 되었습니다.
이 문제를 해결하기 위해 BigQuery 사용량을 체계적으로 모니터링하고, 높은 사용량의 비효율적인 쿼리가 발생할 경우 즉시 알림을 보내는 시스템의 필요성이 대두되었습니다. 이를 통해 클라우드 비용을 효과적으로 관리하고, 모든 구성원이 효율적으로 데이터를 활용할 수 있는 환경을 구축하고자 했습니다.

3. 사용량 대시보드

3-1. 구축 과정

대시보드를 구축하기 위해 BigQuery의 INFORMATION_SCHEMA.JOBS 뷰를 활용했습니다. 이 뷰는 BigQuery에서 실행된 작업(job)들의 메타데이터를 조회할 수 있는 정보 스키마 뷰로, 쿼리 생성 시간, 실행 시간, 사용자 이메일, 쿼리문, 처리량 등 다양한 정보를 제공합니다. (참고: information-schema-jobs)
하지만 Metabase에서 쿼리할 경우, INFORMATION_SCHEMA.JOBS의 user_email 컬럼에는 Metabase와 연동된 서비스 계정 이메일이 기록되어 있어, 누가 쿼리를 실행했는지 특정하기 어려웠습니다. 그러나 query 컬럼에서 Metabase User ID를 확인할 수 있기에 해당 User ID를 정규표현식을 사용해 파싱한 후, Metabase의 메타데이터를 담고 있는 데이터베이스와 결합하여 사용자의 이메일과 성명 등의 정보를 가져올 수 있었습니다.
만약 Metabase DB 리전과 쿼리 대상 데이터 세트의 리전이 달라 JOIN이 불가능한 경우, EXTERNAL_QUERY를 사용하여 Metabase DB 테이블의 유저 정보를 조회하고, 그 결과를 데이터 커넥터 또는 Apps Script를 활용해 주기적으로 구글 스프레드시트에 적재한 뒤 이 스프레드시트를 JOIN하는 방식으로 해결할 수 있습니다.

3-2. 결과

notion image
사용량 모니터링 대시보드의 일부
사용량 모니터링 대시보드의 일부
다양한 방식으로 시각화하여 유저별 BigQuery 사용량과 사용 금액을 확인할 수 있도록 했습니다. 필요한 경우 유저가 실행한 모든 쿼리를 확인할 수 있습니다.

4. 사용량 Alert

대시보드를 통해 매일 혹은 실시간으로 BigQuery 사용량을 모니터링할 수 있게 되었으나 여전히 개선이 필요한 부분이 있었습니다.

4-1. 기존의 Slack Alert 메시지

기존에 이미 Cloud Monitoring과 메타베이스 Alert 기능을 사용한 Alert가 있었습니다.
기존의 Alert는 GCP Monitering에서 Audit Log를 활용한 Log-based Mertics를 만들고, Alerting Policy를 설정하여 Notification Channels에 Slack 채널을 연결하는 방식으로 구현되어 있었습니다. 이 방식으로 특정 쿼리가 발생할 때 Slack 채널에서 실시간으로 알림 메시지를 받을 수 있어, 문제를 인지하고 대응할 수 있었습니다.
하지만 이 방법은 두 가지 한계가 있었습니다.
  1. 메타베이스로 쿼리를 실행한 경우 Metabase User ID를 확인할 수는 있었으나, ID로는 누구인지 한 눈에 알 수 없어 해당 ID를 복사한 후 대시보드에 붙여넣기하여 누구인지를 확인해야 했습니다.
    1. Monitering-Alerting을 사용해 만든 Alert
      Monitering-Alerting을 사용해 만든 Alert
  1. Slack 멘션이 적용되지 않아, 사용자가 스스로 인지하고 과다 사용 이유를 공유하는 프로세스가 부재했습니다. 메시지가 오면 대시보드를 통해 과다 사용자를 식별한 후, Slack에서 직접 멘션하여 사용 이유를 묻거나 쿼리를 개별적으로 확인해야 했습니다.
    1. 무슨 이유인지 물어보고 다니던 지난날
      무슨 이유인지 물어보고 다니던 지난날
과다 사용 이유를 지속적으로 묻는 것은 "데이터 민주화"의 취지에 어긋난다는 생각이 들었습니다. 사용자가 대시보드를 조회하거나 직접 쿼리를 실행하는 데 있어 부담을 느끼게 만들 수 있기 때문입니다. 따라서 사용자가 자발적으로 사용량을 인지하고 "이러한 이유로 사용했다"고 공유하는 방식이 더 적절하다고 판단했습니다.
이러한 맥락에서 새로운 모니터링 시스템을 구축하고자 했고, 새로운 시스템은 아래 세 가지를 보장하는 것을 목표로 했습니다.
  1. 알림 메시지가 적절한 대상자에게 전달되어야 한다.
  1. 수신자가 문제 상황을 인지하고 있음을 확인할 수 있는 피드백 루프가 마련되어야 한다.
  1. 사용자가 자발적으로 사용 이유를 공유하고, 문제 해결 후 그 결과를 기록할 수 있는 수단을 제공해야 한다.
이를 통해 과다 사용에 대한 모니터링과 동시에, 사용자의 자율적인 데이터 활용을 독려할 수 있을 것으로 기대되었습니다.

4-1. 구축 과정

BigQuery 사용량 모니터링 및 알림 시스템을 구축하는 과정을 단계별로 설명하겠습니다. 이 시스템은 GCP의 Log Router, Pub/Sub, Cloud Function을 활용하여 로그 데이터를 수집하고, 특정 조건에 맞는 로그 메시지를 필터링하여, Slack으로 실시간 알림을 보내는 구조로 설계했습니다.
notion image
먼저 메시징 시스템의 개념을 이해하는 것이 중요합니다. 메시징 시스템은 시스템 간 또는 애플리케이션 간 데이터를 전달하는 데 사용됩니다. 여기서 "메시지"는 전달되는 데이터의 단위입니다. 메시지 시스템은 비동기적으로 데이터를 주고받을 수 있어, 시스템 간 결합도를 낮추고 확장성을 높이는 데 유용합니다.
비동기적 데이터 전송은 시스템이 서로 직접적으로 연결되지 않고, 메시지 큐나 버퍼를 통해 데이터를 주고받는 방식을 말합니다. 발신자가 데이터를 전송하면, 수신자는 즉시 응답하지 않고도 나중에 데이터를 받을 수 있습니다. 이는 시스템 간에 강한 시간적 결합(즉시 응답이 필요한 상황)을 줄여줍니다.
조금 더 쉽게 설명해 보면, 메시징 시스템은 마치 “우편 서비스”와 같습니다. 발신자는 편지를 작성하여 우체통에 넣고, 수신자는 곧바로 확인할 필요 없이 우편함에서 자신의 편의에 따라 편지를 수령합니다. 발신자와 수신자는 직접 만나지 않고 편지를 주고받을 수 있기 때문에 서로의 일정에 구애받지 않고 소통할 수 있습니다.

1. Pub/Sub Topic 생성

이 단계의 목표는 로그 데이터를 전달할 논리적 채널을 만드는 것입니다. Pub/Sub는 GCP의 메시징 서비스로, 메시지를 게시하고 구독하는 시스템을 제공합니다. 먼저 Pub/Sub Topic을 생성하고, 이후 단계에서 Log Router와 Cloud Function이 이 Topic을 사용하도록 설정합니다.
Pub/Sub을 사용하는데 알아야 할 기본적인 개념은 다음과 같습니다.
  1. Topic
    1. Topic은 Pub/Sub에서 메시지가 게시되는 논리적 채널로, 모든 메시지는 Topic을 통해 전달됩니다. 이는 메시지를 전달할 수 있는 기본 단위로, 로그 데이터나 이벤트를 시스템에 게시할 때 가장 먼저 설정해야 하는 요소입니다.
      1. Topic은 여러 사람이 편지를 넣는 공동 우체통입니다. 발신자들은 편지를 작성하여 이 우체통에 넣습니다.
  1. Subscription
    1. Subscription은 특정 Topic에 게시된 메시지를 구독하기 위해 설정된 리소스로, Topic에서 메시지를 받아 보관하고, 이 메시지들을 Subscriber에게 전달할 준비를 합니다.
      1. Subscription은 특정 우체통에서 편지를 받아보는 개인 우편함입니다. 우체통에 들어온 편지는 구독자의 개인 우편함으로 전달됩니다.
  1. Publisher와 Subscriber:
    1. Publisher는 메시지를 생성하고 Topic에 게시하는 주체입니다. 현재 시스템에서는 Log Router가 필터링된 로그를 Topic에 게시하는 Publisher 역할을 합니다.
      1. Publisher는 편지를 작성하여 우체통에 넣는 사람입니다.
    2. Subscriber는 메시지를 구독하여 처리하는 주체로, 구독한 Subscription을 통해 Topic의 메시지를 받아 이를 처리합니다. 현재 시스템에서는 Cloud Function이 Subscription을 통해 메시지를 받아 처리하고 Slack 알림을 보냅니다.
      1. Subscriber는 개인 우편함에서 편지를 꺼내어 읽고 필요한 작업을 수행하는 사람입니다.
  1. Ack (Acknowledgement): Ack는 Subscriber가 메시지를 성공적으로 처리했음을 Pub/Sub 시스템에 알리는 신호입니다. Subscriber는 메시지를 처리한 후 Pub/Sub에 Ack를 전송하며, 이 신호가 수신되면 Pub/Sub 시스템은 해당 메시지를 큐에서 제거합니다. 만약 Ack가 설정된 시간 내에 수신되지 않으면 Pub/Sub는 동일한 메시지를 다시 전달합니다.
    1. Ack는 수신자가 편지를 잘 받았음을 발신자에게 확인시켜 주는 과정입니다. 이 확인이 없으면 발신자는 편지가 제대로 전달되지 않았다고 판단하고 다시 보낼 수 있습니다.

2. Log Router 설정

이 단계의 목표는 특정 조건에 맞는 로그 메시지를 필터링하여 Pub/Sub Topic으로 전달하는 것입니다. Log Router는 GCP의 Cloud Logging 서비스의 일부로, 다양한 서비스에서 생성된 로그를 수집하고 필터링하여 지정된 대상으로 전송하는 역할을 합니다. 즉, BigQuery 사용량 로그를 수집하고, 조건에 맞는 로그만을 필터링하여 Pub/Sub Topic으로 전달합니다.
즉, Log Router는 우체국의 분류 시스템과 같습니다. 수많은 편지가 들어오면 이를 자동으로 분류하여 각각의 편지가 특정 우체통으로 가도록 합니다.
필터링을 위해서는 Cloud Logging 데이터를 쿼리하고 필터링하는 데 사용하는 Logging 쿼리를 작성합니다. (참고: logging-query-language)
  • resource.type="bigquery_resource": BigQuery 리소스에서 발생한 로그를 필터링합니다.
  • proto_payload.method_name="jobservice.jobcompleted": BigQuery 작업이 완료되었음을 나타내는 로그를 필터링합니다.
  • proto_payload.service_data.job_completed_event.job.job_statistics.total_billed_bytes > 53687091200: 청구된 총 바이트 수가 50GB(50*1024*1024*1024)를 초과하는 로그를 필터링합니다.
resource.type="bigquery_resource" AND proto_payload.method_name="jobservice.jobcompleted" AND proto_payload.service_data.job_completed_event.job.job_statistics.total_billed_bytes > 53687091200
필터링 조건 예시
Log Router를 통해 필터링된 로그가 Pub/Sub Topic으로 전달됩니다. 다음 단계에서는 이 로그 메시지를 처리하고 알림을 보내는 Cloud Function을 설정합니다.

3. Cloud Function 설정

Cloud Function은 GCP의 이벤트 기반 서버리스 컴퓨팅 서비스로, 특정 이벤트가 발생했을 때 지정된 코드를 실행합니다.
Cloud Function은 개인 우편함에서 편지를 꺼내어 읽고 필요한 작업을 수행하는 비서입니다. 비서는 개인 우편함에서 우편물을 가져와서 우편 종류를 확인한 후, 중요한 서류가 포함된 우편물이라면 이를 수취인에게 직접 전달할 수 있고, 광고 전단이라면 다른 처리 방법을 선택할 수도 있습니다.
우선 Configuration(구성)에서 Runtime - Autoscaling(자동 확장)의 최소 인스턴스 수를 1로 설정했습니다. 이렇게 하면 항상 하나의 인스턴스가 실행 상태로 유지되어 함수가 호출될 때 콜드 스타트로 인한 지연을 피할 수 있어 응답 시간이 빨라집니다.
함수(코드)는 Pub/Sub 메시지를 처리하여 Slack 채널에 쿼리 사용자를 멘션한 Alert 메시지를 보내도록 구성했습니다.
  1. Pub/Sub 메시지 파싱: Pub/Sub 메시지에서 필요한 정보를 추출합니다. 여기에는 이메일, 사용량, 쿼리, Metabase User ID 등이 포함됩니다.
  1. Metabase User ID 매핑: Metabase User ID를 이메일로 변환합니다. 이를 위해 Cloud SQL에 저장된 Metabase 데이터베이스에서 사용자 정보를 조회합니다.
  1. Slack 알림 전송: Slack API를 사용하여 특정 사용량 이상의 쿼리 발생 시, 슬랙 채널에 해당 사용자를 멘션하여 과다 사용량 알림을 보냅니다.
    1. 코드를 작성하기 전에, Slack API에서 app을 만들어 줍니다. OAuth & Permissions의 Scope에 아래 세 가지 권한을 추가했습니다. 전체 권한에 대한 자세한 정보는 Permission scopes에서 확인할 수 있습니다.
      1. chat:write : Send messages as @BigQuery Alert
      2. users:read : View people in a workspace
      3. users:read.email : View email addresses of people in a workspace
    2. 초기에는 Slack 웹훅을 사용하여 알림을 전송하려 했으나, 웹훅으로는 특정 사용자를 멘션하는 기능을 만들 수 없었습니다. 따라서 Slack API를 사용하여 이메일을 통해 사용자 ID를 조회하고, 멘션을 포함한 알림을 전송하는 방식으로 구성했습니다. (참고: webhooks)

4-2. 결과

일정 처리량 이상의 쿼리 발생 시 날아오는 Slack Alert 메시지 (1)
일정 처리량 이상의 쿼리 발생 시 날아오는 Slack Alert 메시지 (1)
일정 처리량 이상의 쿼리 발생 시 날아오는 Slack Alert 메시지 (2)
일정 처리량 이상의 쿼리 발생 시 날아오는 Slack Alert 메시지 (2)
누적 사용량 임계치 이상 도달 시 날아오는 Slack Alert 메시지
누적 사용량 임계치 이상 도달 시 날아오는 Slack Alert 메시지
특정 처리량 이상의 쿼리를 실행한 경우, Slack Bot이 해당 유저를 멘션하여 BigQuery 사용량과 쿼리를 확인할 수 있도록 했습니다. 이를 통해 사용자가 높은 처리량의 쿼리를 실행했을 때 자동으로 알림을 받아 자발적으로 사용량을 인지하고 적극적으로 개선할 수 있는 환경을 만들었습니다. (더 과한 처리량의 쿼리를 실행한 경우에는 DIS팀 그룹을 함께 멘션하여 빠른 대응이 가능하도록 구성했습니다.)

5. 결론 및 효과

데이터 웨어하우스 사용량 모니터링 시스템을 통해 비용을 최적화할 수 있었고 데이터 민주화에 한 발 더 다가갈 수 있었습니다.
  • 비용 감축: 데이터 웨어하우스, 데이터 마트 제작과 더불어 실시간 모니터링과 알림 시스템을 도입한 후, 비효율적인 쿼리를 신속하게 감지하고 대응할 수 있게 되어 BigQuery 사용 비용을 상당량 줄일 수 있었습니다. 또한 Analytics Engineer를 비롯한 데이터 직군이 일일이 사용량을 모니터링하고 추적하는 데 드는 시간을 절약할 수 있었습니다.
  • 투명성 강화: 사용자들이 자신의 데이터 사용량을 투명하게 볼 수 있게 되었으며, 높은 처리량의 쿼리를 실행한 경우 사용자들이 스스로 인지하고 그 원인을 공유하는 프로세스를 통해 자발적인 책임감을 높였습니다.
  • 쿼리 피드백: 쿼리에 익숙하지 않은 사용자들이 실행한 쿼리에 대해 피드백을 제공할 수 있는 시스템이 만들어짐으로써 사용자들이 더 최적화된 쿼리를 작성할 수 있게 되었습니다.

6. 앞으로

  1. 데이터 리터러시 교육
    1. 전사 구성원들이 자신의 업무에 데이터를 효과적으로 사용할 수 있도록 돕기 위해 새로운 요구 사항에 대응하여 시스템을 발전시키는 것은 물론이고 SQL 교육, 데이터 웨어하우스 및 데이터 마트 활용 교육, BI툴 사용법 교육 등 전사 교육 프로그램을 강화하여 구성원들의 데이터 활용 능력을 높이고자 합니다.
  1. FinOps 확대
    1. 잡플래닛의 데이터 조직은 AI 연구와 대규모 언어 모델(LLM) 개발을 위해 BigQuery에 적재된 데이터를 활용하고 있습니다. 앞으로는 데이터 웨어하우스 비용 모니터링뿐만 아니라 전체적인 클라우드 비용 관리(FinOps)로 확대할 계획입니다. 이를 통해 모든 클라우드 리소스의 비용을 체계적으로 관리하고 최적화하여, AI 및 연구에 필요한 리소스를 효율적으로 활용할 수 있도록 지원할 예정입니다.

7. 마치며

데이터 민주화를 실현하기 위해서는 데이터 파이프라인 구축만큼이나 클라우드 사용량 최적화가 필수적입니다. 비용 관리에 소홀하면 데이터 플랫폼의 지속 가능성이 위협받아 데이터 민주화라는 본연의 목표를 달성하기 어렵습니다. 데이터 웨어하우스 비용 최적화와 데이터 민주화 과정에 관심이 있는 분들에게 이번 포스팅이 유익한 정보가 되었기를 바랍니다. 잡플래닛 데이터 조직은 앞으로도 데이터 민주화를 위한 다양한 시도를 계속해 나갈 것입니다.
끝으로 저희와 함께 데이터가 흐르는 조직을 만들어갈 Analytics Engineer를 모시고 있습니다. 데이터가 흐르는 조직을 만들고 문화를 바꾸는 새로운 도전을 함께하실 분들의 많은 지원 부탁드립니다.
 
Share article
Subscribe to 잡플래닛 테크블로그
RSSPowered by inblog