태깅을 넘어: 데이터 플랫폼에서 실시간 비용 할당을 위한 청사진

발행: (2025년 12월 22일 오후 03:44 GMT+9)
21 min read
원문: Dev.to

Source: Dev.to

태그 기반 FinOps의 문제점

Slack 메시지는 새벽 2시에 도착했습니다:

“주말에 누가 우리 전체 월간 Spark 예산을 다 써버렸나요?”

아침이 되면 전화번호처럼 보이는 AWS 청구서를 들여다보며 메타데이터 로그를 파고들고, CFO에게 *“태깅 전략을 개선하겠다”*는 약속을 합니다.

하지만 불편한 진실은 태깅은 2025년 문제에 대한 2015년 솔루션이라는 점입니다.

공유 컴퓨팅, 서버리스 웨어하우스, 복잡한 DAG가 존재하는 세상에서 태그는 리소스를 누가 소유했는지만 알려줄 뿐, 누가 낭비하고 있는지는 알려주지 못합니다.

  • 예시: Snowflake 웨어하우스에 Owner: Data_Platform이라는 태그를 붙일 수 있지만, 이는 새벽 3시에 비효율적인 교차 조인을 실행해 $2,000이 든 팀을 식별하는 데 도움이 되지 않습니다.

비용을 진정으로 통제하려면 FinOps를 라벨링 작업으로 보는 것을 멈추고 인프라 설계 과제로 접근해야 합니다. 아래는 실제로 작동하는 쿼리 수준 비용 귀속 엔진을 위한 아키텍처 청사진입니다.

Why Tags Fail at Scale

1. Tags are infrastructure‑level metadata

Your Spark cluster is tagged data‑eng‑team and costs $500/hr.
The cluster is shared by five teams running hundreds of queries. When the bill arrives, everyone points at everyone else. The tag tells you the cluster cost, not that the marketing analytics team consumed 60 % of those resources.

2. Tags don’t survive query boundaries

A data scientist submits a Trino query that joins three massive tables. Trino spins up workers, reads from S3, shuffles data, finishes in 20 min.
Which tag captured that cost?

  • The Trino coordinator?
  • The S3 bucket?
  • The VPC?

Good luck reconciling that.

3. Tags require discipline that doesn’t scale

You can mandate every Spark job include --conf spark.yarn.tags=team:analytics.
You can write wiki pages and send Slack reminders.
But the moment someone copy‑pastes code from Stack Overflow at 5 PM on Friday, the tagging discipline collapses.

4. Tags describe infrastructure, not usage

Standard cloud billing files (e.g., AWS Cost and Usage Report) give you the cost of the instance, but they don’t know what happened inside the instance.

Bottom line: The future of data‑platform FinOps isn’t about better tagging – it’s about building query‑level cost attribution systems that treat every query as a billable unit of work.

Source:

아키텍처 프레임워크: 클라우드 청구에서 쿼리 메타데이터까지

1. 모든 쿼리는 여권(누가 실행했는지와 이유를 식별하는 메타데이터)이 필요합니다

플랫폼여권 설정 방법
SnowflakeALTER SESSION SET QUERY_TAG = '{"project":"marketing_churn","env":"prod","team":"analytics"}';
Sparkspark.conf.set("spark.sql.query.tags", "project=customer_segmentation,team=data_science")
TrinoSET SESSION query_id = 'marketing-dashboard-prod';

협상 불가로 만들세요. 쿼리에 유효한 여권이 없으면 거부하거나 “미지정” 버킷으로 라우팅하여 수동 검토를 진행합니다. 이 정책은 입학 컨트롤러플랫폼 수준의 쿼리 인터셉터를 통해 적용할 수 있습니다.

2. 메타데이터 보강

세션 태그만으로는 비즈니스 컨텍스트가 부족합니다:

  • 사용자 → 팀 매핑 (HR 시스템 또는 디렉터리 서비스)
  • 프로젝트 태그 (Airflow, dbt 등)
  • 애플리케이션 컨텍스트 (대시보드, ETL 작업, ad‑hoc 분석)

예시 레코드:

“Analytics 팀, 마케팅 프로젝트, Airflow DAG, 프로덕션 환경, $12.50 비용.”

3. ETL 파이프라인 – 비용 데이터를 1급 시민으로 취급

쿼리 로그 수집

  • Snowflake: ACCOUNT_USAGE.QUERY_HISTORY
  • Databricks: system.runtime.queries
  • Spark/YARN: YARN 로그, Spark History Server
  • Trino: system.runtime.queries

데이터 레이크에 구조화된 포맷(예: Parquet)으로 저장합니다. 수집 항목:

  • 누가 쿼리를 실행했는지
  • 실행 시간(시작/종료)
  • 자원 사용량(CPU, 메모리, I/O)
  • 성공/실패 상태

인프라 비용 수집

  • 클라우드 제공자 비용 보고서(AWS CUR, GCP Billing Export, Azure Cost Management)
  • 온‑프레미스 감가상각 하드웨어 비용

4. 정규화 레이어 – 모든 사용량을 공통 메트릭으로 변환

플랫폼기본 단위초당 컴퓨팅 비용으로 변환
SnowflakeCredits1 Credit = $X (웨어하우스 크기에 따라 다름)
DatabricksDBU (Databricks Unit)1 DBU = $Y (지역/인스턴스에 따라 다름)
SparkExecutor‑hours#executors × instance‑cost/hour
TrinoCPU‑seconds / memory‑seconds인스턴스 가격을 사용해 $/second 로 매핑

여기서 마법이 일어납니다: 쿼리 메타데이터와 정규화된 인프라 비용을 결합해 쿼리당 비용 할당을 생성합니다.

5. 핵심 원칙 – 비례 할당

인프라 비용은 시간 기반입니다. Spark 클러스터는 유휴 상태든 최대 사용이든 시간당 $X 비용이 발생합니다. 실제 사용량(CPU‑seconds, memory‑seconds, I/O 등)에 따라 각 쿼리에게 비용을 비례하게 할당합니다.

전체 흐름 정리 – 고수준 데이터 흐름

flowchart TD
    A[Cloud Billing Export] -->|Cost Data| N[Normalization Layer]
    B[Query Logs (Snowflake, Databricks, Spark, Trino)] -->|Usage Data| N
    N -->|Join on time & resource| C[Attribution Engine]
    C -->|Per‑query cost| D[Cost Dashboard / Alerting]
    C -->|Unattributed bucket| E[Manual Review Process]
  1. Export 클라우드 공급자에서 비용 데이터를 내보냅니다.
  2. Collect 각 컴퓨팅 플랫폼에서 쿼리 로그를 수집합니다.
  3. Normalize 두 스트림을 공통 비용 메트릭으로 정규화합니다.
  4. Join 타임스탬프와 리소스 식별자를 기준으로 결합하여 쿼리당 비용을 계산합니다.
  5. Surface 결과를 대시보드, 알림 및 비용 청구 보고서에 표시합니다.
  6. Review “unattributed” 버킷에 있는, 패스포트가 없는 쿼리를 검토합니다.

조직을 위한 다음 단계

  1. 세션 수준 태깅을 의무화 모든 쿼리 발행 플랫폼에 적용합니다.
  2. 구축하거나 채택 경량 인제스트 파이프라인(AWS Glue, dbt, Airflow 등 사용)으로 로그와 비용 데이터를 레이크에 가져옵니다.
  3. 각 플랫폼의 기본 단위를 $ per compute‑second(초당 컴퓨팅 비용)으로 변환하는 전환 테이블을 생성합니다.
  4. 사용량과 비용 스트림을 병합하는 귀속 엔진을 개발합니다(SQL, Spark, 혹은 작은 Python 서비스).
  5. 대시보드 배포(Looker, Tableau, Superset) 및 비정상적인 지출에 대한 알림을 설정합니다.
  6. 반복 – 패스포트 적용을 정교화하고, 메타데이터를 풍부하게 하며, 비용 할당 세분성을 개선합니다.

TL;DR

  • Tags = static, infrastructure‑level – they don’t tell you who used what at when.
    태그 = 정적, 인프라 수준 – 누가 언제 무엇을 사용했는지는 알려주지 않는다.

  • Solution = query‑level passports + metadata enrichment + cost normalization.
    솔루션 = 쿼리‑레벨 패스포트 + 메타데이터 강화 + 비용 정규화.

  • Build a pipeline that ingests both usage and billing data, converts everything to a common cost metric, and allocates costs proportionally to each query.
    사용량청구 데이터를 모두 수집하고, 모든 데이터를 공통 비용 메트릭으로 변환하며, 비용을 각 쿼리마다 비례적으로 할당하는 파이프라인을 구축한다.

By treating every query as a billable unit of work, you finally get the visibility needed to answer the critical question:

“Who spent what?”
“누가 얼마를 썼나요?”

…and you can move from firefighting surprise bills to proactive, data‑driven FinOps.
…그리고 갑작스러운 청구서에 대응하는 소극적인 상황에서 벗어나, 사전 예방적이고 데이터 기반의 FinOps로 전환할 수 있다.

비용 할당 개요

목표: 어떤 쿼리가 플랫폼 시간을 소비하는지와 비용을 어떻게 할당할지 보여줍니다.

공식

Cost_query = (Infrastructure Cost_period) × (Query Runtime / Total Active Time) × (Resource Weight)

예시:
만약 Spark 클러스터가 오후 2‑3시 사이에 $500의 비용이 들고, 팀 A의 쿼리가 48 분(시간의 80 %) 동안 실행되었으며 **실행기 메모리의 90 %**를 사용했다면, 비용은:

$500 × 0.80 × 1.125 = $450

파이프라인

  • 파이프라인은 1일 차에 실시간일 필요는 없습니다.
  • CSV를 이메일로 보내는 일일 배치 작업이면 시작하기에 충분한 경우가 많습니다.

Trino 비용 할당

Trino는 사용자 친화적—SQL만 제출하면 결과를 얻지만—비용 할당은 까다롭다. 단일 쿼리가 수십 개의 워커에서 작업을 생성할 수 있기 때문이다.

옵션 1 – Trino의 리소스 메트릭 사용

Trino의 system.runtime.queries 테이블은 다음을 노출한다:

MetricDescription
cpu_time사용된 CPU 시간 (나노초)
peak_memory_bytes사용된 최대 메모리 (바이트)
cumulative_memory소비된 총 메모리‑초

비용 프록시 계산:

워커 노드 비용이 시간당 $0.50이고 쿼리가 60 CPU‑seconds를 사용한 경우:

Cost = (60 seconds / 3600 seconds per hour) × $0.50 = $0.0083

Note: I/O와 네트워크는 무시하지만 대략적인 추정치를 제공한다.

옵션 2 – 시간 단위 워커 비용

고정 규모 Trino 클러스터(예: 24시간 7일 운영되는 20개의 워커)가 있는 경우:

  1. 클러스터 전체의 시간당 비용을 산정한다.
  2. 각 쿼리의 CPU 시간을 가중치로 하여 동시 실행되는 쿼리들에 비용을 분배한다.

장점: 안정적인 클러스터에 적합.
단점: 자동 스케일링 클러스터에서는 관리가 복잡해진다.

Spark 비용 할당

Spark은 각 작업마다 JSON 이벤트 로그를 내보내며, 여기에는 단계, 작업, 실행자 및 셔플에 대한 세부 정보가 포함됩니다.

과제

  • 대규모 작업의 경우 이벤트 로그가 수 기가바이트 규모가 될 수 있습니다.
  • 모든 로그를 실시간으로 파싱하는 것은 비현실적입니다.

실용적인 접근법

  1. 전략적 샘플링 – 실행 시간이나 리소스 임계값을 초과하는 작업에 대해서만 로그를 파싱합니다.
  2. 애플리케이션 수준에서 사전 집계 – 먼저 애플리케이션별 비용을 계산하고, 필요할 때만 단계/작업으로 세분화합니다.
  3. 결과 캐시 – 작업 비용이 계산되면 저장합니다; 이벤트 로그는 변경 불가능합니다.

도출된 인사이트:

“당일 ETL 작업 비용은 $87.50입니다. 3단계가 **60 %**의 비용을 차지하는데, 이는 셔플 때문입니다—재분할을 줄이는 것을 고려하세요.”

Hive 비용 귀속

Hive 온‑프레미스 또는 EMR은 종종 불완전한 쿼리 로그를 가집니다.

권장 전술

  • YARN 로그 – Hive가 YARN에서 실행되는 경우, ResourceManager API를 조회하여 애플리케이션 자원 사용량을 확인합니다.
  • 런타임 근사 – 상세 메트릭을 사용할 수 없을 때는 query runtime × cluster capacity를 대략적인 추정치로 사용합니다.
  • 주요 비용 발생자에 집중상위 10개의 가장 비용이 많이 드는 쿼리를 식별합니다; 이들이 일반적으로 절감액의 ~80 %를 차지합니다.

일반적인 함정 (지뢰)

문제설명 및 완화 방안
유휴 시간 딜레마쿼리가 끝난 후에도 웨어하우스가 깨어 있습니다. 유휴 비용을 해당 시간의 사용량에 비례하여 배분합니다.
귀속되지 않은 버킷백그라운드 서비스, 스토리지 오버헤드 및 태그가 없는 쿼리가 잡음을 발생시킵니다. 약 90 % 정도의 귀속을 목표로 하세요; 마지막 10 %는 수익이 감소합니다.
청구 지연클라우드 청구가 24‑48 시간 지연될 수 있습니다. 초기 비용을 즉시 생성하고, 최종 청구와 조정하세요.

문화 및 조직적 영향

  • Unit Economics Visibility: 각 대시보드/파이프라인에 대한 “서비스 비용”을 계산합니다.
  • Automated Guardrails: 비싼 쿼리(예: > $150)에 대해 Slack으로 알림을 보내고, 팀 지출이 급증할 때 알립니다.
  • True Chargebacks: 재무팀에 약 95 % 정확도의 부서별 비용 분류를 제공합니다.
  • FinOps Culture: 엔지니어가 쿼리 비용을 확인하면 비용에 관심을 갖고 효율성을 위해 경쟁합니다.

비용 할당 시스템은 아무도 보지 않으면 무용지물이다.

추천 대시보드

  1. Team Cost Overview – 팀별 월별 지출 및 전월 대비(MoM) 비교.
  2. Top Queries by Cost – 비용이 가장 많이 드는 50개 쿼리(사용자, 실행 시간, 비용).
  3. Cost per User – 사용자의 지출 순위(예: 하루에 $500를 소모하는 노트북).
  4. Unit Economics – 행당 비용, 대시보드 새로 고침당 비용, API 호출당 비용.

시작하기 – 우선순위

  1. 주 엔진 선택 – 가장 많은 비용을 소모하는 엔진을 선택하세요 (Spark, Trino, 또는 Hive).
  2. V1을 과도하게 설계하지 않기 – CSV를 이메일로 보내는 일일 배치 작업이면 충분합니다. 배포하고, 배우고, 반복하세요.
  3. 데이터를 셀프 서비스화 – 할당된 비용을 쿼리 가능한 테이블에 저장하고, 팀이 자체 대시보드를 만들 수 있게 하세요.
  4. 세션 태그를 초기에 적용 – 태그를 필수로 하고, 컨텍스트가 없는 쿼리는 거부하거나 제한하세요.
  5. 성과 공유 – 회의에서 비용 인사이트를 공유하고, 절감 효과를 축하하며, 긍정적인 분위기를 유지하세요.

ROI 일러스트레이션

  • 플랫폼 비용: $150 k / 월.
  • 구축 비용: 한 명의 엔지니어, 1/4년 파트타임 ≈ $40 k.

최적화 후 절감액

최적화 내용월 절감액
대시보드 쿼리 (5 분 → 매시간)$8 k
필요 이상으로 10배 많은 데이터 셔플링 ETL 작업$12 k
팀 간 중복 쿼리$5 k
총합$25 k

결과:≈ 2 개월 안에 시스템이 비용을 회수합니다; 이후 매월은 순수 이익입니다.

당신이 필요한 확신

마침내 CFO의 질문—“우리 데이터 플랫폼이 왜 이렇게 비싼가요?”—에 대해 손짓이 아닌 데이터로 답할 수 있습니다.

  • 엔지니어링 팀이 어디에 비용을 쓰고 있는지 보여줍니다.
  • 더 똑똑한 결정을 내릴 수 있도록 권한을 부여합니다.
  • 예산을 초과하기 전에 과도한 워크로드를 포착합니다.
  • 태그만에 의존하는 것을 중단합니다.

데이터 엔지니어를 위한 새로운 지표

Modern Data Stack 시대에 가장 성공적인 데이터 엔지니어는 데이터를 가장 빠르게 이동시키는 사람만이 아닙니다.
그들은 이동하는 모든 바이트의 단위 경제성을 설명할 수 있는 사람들입니다.

왜 비용 할당이 어려운가 (그리고 해결 방법)

비용 할당은 데이터 플랫폼에 대한 해결된 문제가 아니며—그냥 작동하는 pip install 할 수 있는 단일 오픈소스 도구는 없습니다.
하지만 기본 원칙은 간단합니다:

  1. 인프라뿐 아니라 세션에도 태그를 붙이기Tier 1: Metadata Layer
  2. 청구 및 쿼리 데이터를 통합 스키마로 정규화하기Tier 2: Ingestion
  3. 리소스 사용량에 기반해 비례적으로 조인하고 할당하기Tier 3: Attribution Logic
  4. 데이터를 가시화하고 실행 가능하게 만들기Dashboards & Alerts

Spark, Trino, Hive 중 하나를 사용하든 모두 사용하든, 패턴은 동일합니다:

  1. 쿼리 엔진에 계측을 적용합니다.
  2. 데이터를 수집합니다.
  3. 간단한 파이프라인을 구축합니다.
  4. 팀에게 워크로드 비용을 보여주기 시작합니다.

시작하기

  • 완벽하지 않을 것입니다. 첫 번째 버전에는 빈틈이 있을 것이며, 일부 쿼리는 속성을 파악하기 어려울 것입니다. 괜찮습니다.
  • 80 % 커버리지를 목표로 하고 반복하세요.

목표는 완벽한 비용 회계가 아니라, 엔지니어가 자신의 작업 비용을 이해하고 이를 최적화할 수 있는 도구를 갖춘 데이터 플랫폼을 구축하는 것입니다.

Call to Action

  • 태깅을 멈추고 설계하세요.
  • 당신의 CFO가 감사할 것입니다.
Back to Blog

관련 글

더 보기 »