Metric Layer 설계: 정의 충돌, semantic model, ownership
"매출"의 정의는 몇 개인가
데이터 팀 규모가 커지면 반드시 맞닥뜨리는 문제가 있다. 마케팅 팀의 대시보드에 표시된 "이번 달 매출"과 재무팀 리포트의 "이번 달 매출"이 다르다. 조사해 보면 마케팅은 gross revenue를 쓰고 재무는 net revenue를 쓰고, 고객 성공팀은 수수료 제외 수익을 쓰고 있다. 숫자가 세 개 있고 아무도 어느 것이 공식인지 모른다.
이것이 정의 충돌(metric definition conflict)이다. 84%의 데이터 팀이 정기적으로 경험한다고 보고된다. 규모가 작을 때는 "그냥 물어보면 된다"고 넘어가지만, AI 에이전트가 데이터를 직접 소비하기 시작한 지금은 잘못된 정의가 자동 의사결정에까지 전파된다는 점에서 비용이 완전히 달라졌다.
Metric Layer는 이 문제에 대한 구조적 답변이다.
1. Metric Layer가 해결하려는 문제
1.1 정의 중복의 전형적인 경로
mart_marketing_revenue
gross_amount 합산
mart_finance_revenue
net_amount 합산
커스텀 LookML
fee 제외 계산
분석가마다 다른 SQL
기준일 해석 다름
어느 숫자가 공식인지 아무도 모름 · 조인 조건도 각자 다름 · 변경 시 4곳 모두 수정 필요
각 팀이 각자의 BI 도구나 dbt 모델에 "매출"을 독립적으로 정의하면, 동일한 비즈니스 개념이 여러 곳에 분산된다. 시간이 지나면 각각 조금씩 달라지고, 어느 것이 공식 정의인지 아무도 모르게 된다.
1.2 Metric Layer가 주는 것
- 단일 정의 위치: 비즈니스 지표를 한 곳에서만 정의한다.
- 일관된 SQL 생성: 어떤 BI 도구, 어떤 쿼리 엔진을 쓰더라도 동일한 SQL이 생성된다.
- 버전 관리: 지표 정의가 코드로 관리되어 변경 이력이 남는다.
- 소유권 명확화: 각 지표에 owner가 명시된다.
2. Semantic Layer와 Metric Layer의 관계
두 용어가 혼용되는 경우가 많지만 개념적으로 구분할 수 있다.
Semantic Layer: 테이블 간 관계, 조인 경로, 집계 규칙, 접근 권한을 선언하는 계층이다. "orders 테이블과 customers 테이블은 customer_id로 조인된다"가 여기 속한다.
Metric Layer: Semantic Layer 위에 서서 비즈니스 지표를 정의하는 계층이다. "revenue는 orders.amount를 status='paid'인 행에 대해 합산한 값이다"가 여기 속한다.
Metric Layer는 Semantic Layer의 어휘를 빌려 지표를 표현한다. 둘이 합쳐진 개념을 통틀어 "Semantic Layer"라고 부르는 경우도 있으므로, 도구마다 용어가 조금씩 다를 수 있다.
3. dbt Semantic Layer와 MetricFlow
dbt Labs는 2022년부터 MetricFlow를 인수·통합하여 dbt 안에서 지표를 정의하는 공식 방식을 제공한다.
3.1 핵심 개념
MetricFlow는 지표 요청을 데이터플로우 기반 쿼리 플랜으로 컴파일하고 엔진별 SQL로 변환한다.
# semantic_models/orders.yml (dbt semantic model 예시)
semantic_models:
- name: orders
description: "주문 사실 테이블"
model: ref('fct_orders')
entities:
- name: order_id
type: primary
- name: customer_id
type: foreign
expr: customer_id
dimensions:
- name: order_date
type: time
type_params:
time_granularity: day
- name: status
type: categorical
measures:
- name: order_amount
agg: sum
expr: amount
- name: order_count
agg: count_distinct
expr: order_id# metrics/revenue.yml (지표 정의 예시)
metrics:
- name: revenue
description: "결제 완료된 주문의 총 매출"
label: "Revenue"
type: simple
type_params:
measure: order_amount
filter: |
{{ Dimension('orders__status') }} = 'paid'
meta:
owner: "[email protected]"
slack_channel: "#data-finance"
- name: arpu
description: "활성 사용자 1인당 평균 매출"
label: "ARPU"
type: ratio
type_params:
numerator: revenue
denominator: active_users3.2 MetricFlow가 지원하는 지표 유형
| 유형 | 설명 | 예시 |
|---|---|---|
simple | 단일 measure에 집계·필터 | revenue, order_count |
ratio | numerator / denominator | ARPU, conversion_rate |
cumulative | window 내 누적 집계 | rolling_30d_revenue |
derived | 다른 지표들의 수식 조합 | gross_margin = (revenue - cost) / revenue |
3.3 쿼리 방식
MetricFlow를 통해 정의된 지표는 dbt Cloud의 Semantic Layer API, JDBC, Python SDK로 조회할 수 있다.
# CLI 조회 예시
dbt sl query --metrics revenue --group-by order_date__month --limit 12# Python SDK 예시
from dbt_semantic_interfaces.query_interface import MetricFlowQueryRequest
results = mf_client.query(
metrics=["revenue", "arpu"],
group_by=["order_date__month", "customer__tier"],
where="order_date__month >= '2026-01-01'"
)4. 지표 정의의 핵심 요소
좋은 지표 정의는 계산 방법만이 아니라 맥락을 담는다.
agg: sum / count / avg / max / min
filter: 집계 조건
time_dimension: 기준 날짜 컬럼
grain: day / week / month
description: 계산 방식 설명
owner: 책임 팀/담당자
slack_channel: 질문/변경 채널
status: active / deprecated
allowed_teams: 접근 허용 팀
row_level_filter: RLS 조건
certified: 공식 지표 여부
4.1 시간 차원의 중요성
가장 흔한 정의 충돌 중 하나는 기준 날짜가 다른 경우다.
- 주문 생성 시각(
created_at) 기준 매출 - 결제 완료 시각(
paid_at) 기준 매출 - 배송 완료 시각(
shipped_at) 기준 매출
같은 "이번 달 매출"이라도 어느 날짜 컬럼을 기준으로 하느냐에 따라 숫자가 달라진다. 지표 정의에서 time_dimension을 명시하는 이유가 여기 있다.
4.2 필터와 해석의 함정
filter: status = 'paid'는 명확해 보이지만, status가 시간이 지나면서 completed나 fulfilled로 바뀌었다면 어떻게 되는가? 필터는 enum 값의 변화에 취약하다. 지표 정의에 filter의 의도("결제가 확정된 주문")를 description에 명시해두면 미래의 유지보수자가 맥락을 이해할 수 있다.
5. Ownership 구조 설계
Metric Layer의 효과는 기술적 정의만으로는 반쪽이다. 누가 그 지표를 소유하는가를 명확히 해야 완성된다.
5.1 Ownership 레이어
| 레이어 | 소유 주체 | 책임 |
|---|---|---|
| 데이터 소유권 | 원천 시스템 팀 (백엔드, 서비스팀) | 소스 테이블 스키마, 컬럼 의미 |
| 모델 소유권 | 데이터 엔지니어링 / Analytics Engineering | dbt 모델, 지표 YAML |
| 비즈니스 정의 소유권 | 도메인 팀 (재무, 마케팅, 프로덕트) | 어느 계산이 공식인지 |
| 소비 소유권 | BI 개발자, 데이터 분석가 | 대시보드, 리포트 |
데이터 엔지니어가 기술적 구현을 담당하더라도 "revenue는 net이냐 gross냐"는 재무팀이 결정해야 한다. 이 구분이 없으면 엔지니어가 추측으로 구현하고, 나중에 재무팀이 다른 답을 요구한다.
5.2 정의 충돌 해결 프로세스
같은 이름의 지표가 다른 값을 반환하거나, 다른 이름으로 같은 개념이 여러 개 존재
어느 팀이 이 지표를 어디서 쓰는지 파악 · 현재 정의를 각 팀에서 수집
공식 정의 결정 → 대안 정의가 필요한 경우 별도 이름으로 공존 허용
metrics/*.yml에 공식 정의 작성 · 대안 정의는 별도 지표명으로 작성
기존 커스텀 계산을 Metric Layer 지표로 교체 · 불일치 리포트 감시
5.3 지표 네이밍 규칙
정의 충돌의 상당 부분은 이름이 모호해서 발생한다. 팀마다 동의할 수 있는 네이밍 규칙을 만들면 충돌이 줄어든다.
# 권장 패턴
{동사/형용사}_{명사}_{시간범위?}_{필터조건?}
예시:
revenue_gross # 총매출 (세금·수수료 포함)
revenue_net # 순매출 (수수료 제외)
revenue_net_paid # 결제 완료 순매출
revenue_net_paid_30d # 최근 30일 결제 완료 순매출
orders_count_new # 신규 주문 수 (재구매 제외)
churn_rate_seat # 시트 기준 이탈률
churn_rate_account # 계정 기준 이탈률6. Semantic Layer 도구 선택
| 도구 | 특징 | 적합한 상황 |
|---|---|---|
| dbt Semantic Layer + MetricFlow | dbt 프로젝트에 내장, YAML 정의, OSS 가능 | dbt 중심 스택, 새로 구축 |
| Looker (LookML) | Google 생태계, 강력한 조인·액세스 제어 | BigQuery + Google 클라우드 |
| Cube.js | 헤드리스 Semantic Layer, 다양한 엔진 지원 | 멀티 BI 도구 통합 |
| AtScale | 엔터프라이즈, MDX/DAX 호환 | Excel·Power BI 중심 조직 |
| Metriql | 오픈소스, dbt 메타데이터 활용 | 소규모 팀, 자체 호스팅 |
대부분의 신규 프로젝트에서 dbt를 이미 쓰고 있다면 MetricFlow가 가장 진입 비용이 낮다. 기존 Looker 투자가 있는 조직은 LookML을 유지하면서 점진적으로 MetricFlow로 이전하는 하이브리드 경로가 현실적이다.
7. 실전 운영: Metric Layer를 건강하게 유지하기
지표 정의는 한 번 작성하면 끝이 아니다.
지표 변경 프로세스: 지표 정의를 변경하면 해당 지표를 사용하는 모든 대시보드와 리포트에 영향이 간다. Pull Request 기반 리뷰, downstream 소비처 목록 공지, 변경 로그 작성이 필요하다.
deprecated 처리: 더 이상 공식적이지 않은 지표는 즉시 삭제하지 말고 status: deprecated로 표시하고 대체 지표 이름을 안내한다. 삭제는 소비처 전환 확인 후에 한다.
지표 카탈로그: 정의된 지표를 검색 가능한 UI로 제공하면 새 분석가가 기존 지표를 재발견하지 못해 또 다른 커스텀 계산을 만드는 상황을 방지할 수 있다. dbt Cloud의 Explorer, Atlan, DataHub 같은 카탈로그 도구와 연동이 가능하다.
마무리
Metric Layer는 기술 도구이기 전에 조직의 합의를 코드로 만드는 과정이다. YAML 파일이 아무리 잘 작성되어 있어도 비즈니스 소유자가 정의에 동의하지 않았다면 또 다른 대시보드가 만들어진다. 반대로 조직적 합의만 있고 코드화가 없다면 그 합의는 시간이 지나면서 사라진다.
다음 편에서는 이 지표들의 기반이 되는 dbt 모델의 심화 패턴, 즉 레이어별 구현 전략, incremental 모델, snapshot을 다룬다.
References
- dbt Labs, "About MetricFlow": https://docs.getdbt.com/docs/build/about-metricflow
- dbt Labs, "dbt Semantic Layer": https://docs.getdbt.com/docs/use-dbt-semantic-layer/dbt-sl
- dbt Labs, "Build your metrics": https://docs.getdbt.com/docs/build/build-metrics-intro
- Atlan, "Metrics Layer: A Single Source of Truth for All KPI Definitions": https://atlan.com/metrics-layer/
- Coalesce, "Semantic Layers in 2025: A Catalog Owner and Data Leader Playbook": https://coalesce.io/data-insights/semantic-layers-2025-catalog-owner-data-leader-playbook/
- AtScale, "What Actually Changed in 2025 and Why It Redefined the Semantic Layer": https://www.atscale.com/blog/why-ai-redefined-the-semantic-layer/
- Querio, "Metrics Layer vs Semantic Layer: What's the Difference?": https://querio.ai/articles/metrics-layer-vs-semantic-layer-difference
- Alwyn DSouza, "Metrics as Code: Building a Semantic Layer With dbt and MetricFlow": https://medium.com/towards-data-engineering/metrics-as-code-building-a-semantic-layer-with-dbt-and-metricflow-93d7e29e6ab3