LLM WikiAccess-protected knowledge portal
← 스터디 홈
2편 · 약 18분

데이터 계약(Data Contract): schema, SLA, owner, breaking change

암묵적 계약이 파이프라인을 깨뜨린다

소스 팀이 테이블에서 컬럼 하나를 이름 바꿨다. 그들 입장에서는 사소한 내부 리팩터링이었다. 하지만 그 컬럼을 직접 참조하던 세 개의 dbt 모델이 조용히 NULL을 채우기 시작했고, 두 개의 BI 대시보드가 어제부터 잘못된 수치를 보여주고 있다. 아무도 통보받지 못했다.

이것이 암묵적 계약의 문제다. 소스가 "이 데이터를 이 형태로 이 시간까지 제공하겠다"는 약속을 한 적이 없으니, 어기는 것도 인지하지 못한다. 데이터 계약(Data Contract)은 이 관계를 명시적으로 바꾼다. 데이터 생산자와 소비자 사이의 기대치를 코드로 문서화하고, 위반 시 파이프라인을 멈추는 메커니즘을 만든다.


데이터 계약이란 무엇인가

데이터 계약은 데이터 생산자와 소비자 사이의 명시적 합의다. 다음 네 가지를 정의한다.

  1. Schema: 어떤 필드가, 어떤 타입으로, 어떤 제약과 함께 제공되는가
  2. SLA: 언제까지, 얼마나 자주, 얼마나 완전하게 데이터가 도착하는가
  3. Owner: 누가 이 데이터를 소유하고, 문제가 생기면 누구에게 연락하는가
  4. Change policy: 스키마나 SLA가 바뀔 때 어떤 절차를 따르는가

계약은 YAML 파일로 소스 저장소 또는 데이터 플랫폼 저장소에 커밋된다. "살아 있는 문서"처럼 사용되는 Confluence 페이지나 스프레드시트와 달리, 버전 관리되고, 자동 검증되고, CI/CD와 연동된다.


계약의 구성 요소

Schema 필드명 · 타입
Not Null / Unique
허용 값 범위
의미 정의
SLA 신선도(Freshness)
가용성(Availability)
완전성(Completeness)
레이턴시
Owner 생산자 팀
기술 담당자
비즈니스 담당자
에스컬레이션 경로
Change Policy 버전 규칙
Deprecation 기간
Breaking 알림 절차
호환성 정책
계약은 YAML 파일로 버전 관리되고 CI/CD에서 자동 검증된다.
데이터 계약의 네 가지 핵심 구성요소

1. Schema

스키마는 계약의 핵심이다. 필드명, 데이터 타입, nullable 여부, 허용 값 범위, 필드의 의미(semantic definition)를 포함한다.

# 예시: ODCS v3 형식의 스키마 정의 (일부)
schema:
  - name: user_id
    dataType: string
    required: true
    description: "전역 유니크 사용자 식별자"
    examples: ["usr_abc123"]
  - name: event_type
    dataType: string
    required: true
    enum: ["click", "view", "purchase", "refund"]
    description: "이벤트 종류. purchase와 refund는 amount 필드가 반드시 존재해야 함."
  - name: amount
    dataType: decimal(18,2)
    required: false
    description: "거래 금액. event_type이 purchase 또는 refund일 때만 not null."
  - name: created_at
    dataType: timestamp
    required: true
    description: "이벤트 발생 시각 (UTC)"

스키마 정의에서 중요한 것은 의미(semantic definition)다. user_id가 UUID인지, 내부 정수 ID인지, 외부 시스템의 식별자인지를 타입만으로는 알 수 없다. 필드가 무엇을 의미하는지 명시하지 않으면 소비자마다 다르게 해석한다.

2. SLA

SLA는 데이터가 언제까지, 얼마나 완전하게 도착해야 하는지 정의한다.

SLA 항목예시측정 방법
신선도(Freshness)매시간 10분 이내 갱신마지막 파티션의 created_at vs 현재 시각
가용성(Availability)99.5% (월 기준)파이프라인 성공률
완전성(Completeness)기대 행 수의 95% 이상row count 모니터링
레이턴시CDC 이벤트 소스 커밋 후 5분 이내 도착이벤트 타임스탬프 기준

SLA가 빠진 계약은 반쪽짜리다. "데이터를 제공한다"는 약속만 있고 "언제까지"가 없으면 소비자는 자신만의 기대를 갖게 되고, 그 기대가 어긋날 때마다 분쟁이 생긴다.

3. Owner

소유권은 두 역할로 나눈다.

  • 기술 소유자(Technical owner): 파이프라인을 운영하고, 장애를 수리하고, 스키마 변경을 검토하는 엔지니어
  • 비즈니스 소유자(Business owner): 이 데이터가 무엇을 의미하는지 알고, 비즈니스 정의 변경 시 최종 결정권을 갖는 담당자

두 역할이 분리되어야 하는 이유는 엔지니어링 변경과 비즈니스 의미 변경이 서로 다른 승인 경로를 필요로 하기 때문이다. 컬럼 이름 변경은 기술 소유자가 검토할 수 있지만, revenue의 정의를 "세전"에서 "세후"로 바꾸는 것은 비즈니스 소유자의 승인이 필요하다.

4. Change Policy

변경 정책은 계약에서 가장 자주 빠지는 부분이지만 운영에서 가장 중요하다.


Breaking Change: 무엇이 계약 위반인가

모든 스키마 변경이 위험한 것은 아니다. 변경을 호환 가능(backward-compatible)파괴적(breaking)으로 나눠야 한다.

호환 가능 변경 (소비자 코드 수정 불필요)

  • nullable 컬럼 추가
  • 기존 string 컬럼의 최대 길이 증가
  • 새로운 enum 값 추가 (소비자가 unknown 처리하는 경우)
  • 컬럼에 기본값 추가

Breaking Change (소비자 코드 수정 필요)

  • 컬럼 삭제
  • 컬럼 이름 변경
  • 데이터 타입 변경 (string → integer 등)
  • nullable 컬럼을 not null로 변경
  • enum 값 제거 또는 변경
  • SLA 기준 완화 (신선도 기준을 1시간에서 6시간으로)
  • 테이블 분할 또는 병합
Day 0: 공지 - Deprecation 알림
- 소비자 목록 식별
- 마이그레이션 가이드 제공
- 새 버전 계약 초안
Day 0–60: 병렬 제공 - 구 버전·신 버전 동시 운영
- dual-write 또는 alias
- 소비자 이전 현황 추적
- 주간 진행 알림
Day 60–90: 경고 - 미이전 소비자에 경고
- 접근 로그 공유
- 이전 지원 마감 공지
Day 90+: 제거 - 구 버전 종료
- 미이전 소비자 영향 처리
- 계약 버전 archive
Breaking Change 관리 워크플로

Breaking change는 반드시 이전 버전과 병렬로 일정 기간 운영한 후 제거해야 한다. 즉각 제거는 소비자에게 예측 불가능한 장애를 만든다.


계약의 버전 관리

데이터 계약은 소프트웨어 API와 같이 Semantic Versioning을 사용한다.

v{major}.{minor}.{patch}

major: breaking change (소비자 코드 수정 필요)
minor: 하위 호환 추가 (새 컬럼, 새 enum 값)
patch: 비기능 변경 (설명 수정, 담당자 변경)

버전 번호가 올라가는 것은 기술적 사실일 뿐이다. 중요한 것은 major 버전이 올라갈 때 소비자가 충분한 이전 시간을 갖도록 하는 프로세스가 실제로 동작하는지다.


YAML 계약 구조 (ODCS v3 기반)

Open Data Contract Standard (ODCS) v3은 데이터 계약의 표준 YAML 형식을 정의한다.

apiVersion: v3.1.0
kind: DataContract
id: urn:datacontract:payments:order-events:v2
name: order-events
version: 2.1.0
status: active

info:
  owner: payments-team
  contact:
    name: 결제 플랫폼 팀
    email: [email protected]
    url: https://wiki.company.com/data/order-events

servers:
  production:
    type: kafka
    topic: order-events
    format: avro

schema:
  - name: order_id
    dataType: string
    required: true
  - name: user_id
    dataType: string
    required: true
  - name: status
    dataType: string
    enum: ["created", "paid", "cancelled", "refunded"]
  - name: amount
    dataType: decimal(18,2)
    required: false

quality:
  - type: completeness
    description: "order_id and user_id must not be null"
    query: "SELECT count(*) FROM order_events WHERE order_id IS NULL OR user_id IS NULL"
    mustBe: 0
  - type: freshness
    description: "최신 이벤트가 1시간 이내여야 함"
    mustBeLessThan: 60
    unit: minutes

servicelevels:
  availability:
    description: "월 99.5% 이상"
    percentage: 99.5%
  freshness:
    description: "소스 커밋 후 5분 이내 Kafka 도착"
    threshold: 5
    unit: minutes

이 파일이 Git에 커밋되면 다음이 가능해진다.

  • PR 리뷰로 계약 변경을 제어
  • CI에서 실제 데이터와 계약의 일치 여부 자동 검증
  • Schema Registry와 연동해 Kafka/Avro 호환성 강제
  • 카탈로그 도구(DataHub, OpenMetadata 등)에서 계약 연결

계약 위반 시 파이프라인을 어떻게 멈출 것인가

계약이 있어도 위반을 감지하지 못하면 의미가 없다. 두 가지 접근을 결합한다.

1. Ingestion 시점 검증: 데이터가 플랫폼에 들어오는 순간 계약과 비교한다. 스키마가 맞지 않으면 dead-letter queue(DLQ)로 보내고 파이프라인을 중단하거나 알림을 보낸다.

2. 변환 후 검증(Post-transform assertion): dbt test, Great Expectations 같은 도구로 변환 완료 후 데이터 품질을 검증한다. 이 단계에서 실패하면 serving 레이어로의 배포를 막는다.

위반 유형Ingestion 감지Transform 후 감지
컬럼 삭제✓ (즉시 감지)✓ (NULL 이상 감지)
타입 변경✓ (파싱 오류)△ (캐스팅 성공 시 통과)
신선도 SLA 위반✓ (도착 시각 확인)△ (이미 늦게 처리)
의미 변경✗ (감지 불가)✗ (감지 불가, 사람이 판단)

의미 변경(semantic drift)은 자동으로 감지하기 가장 어렵다. amount의 정의가 세전에서 세후로 바뀌어도 스키마는 그대로다. 이것은 계약의 business owner 변경 승인 절차로만 통제할 수 있다.


계약 없는 세계와의 비교

상황계약 없음계약 있음
소스 컬럼 삭제파이프라인이 조용히 NULL 채움, 며칠 후 BI 이상 발견Ingestion 즉시 실패, 알림 발송
신선도 SLA 위반대시보드가 오래된 데이터 표시, 사용자 티켓 발생모니터링 알림, 사전 공지
소비자가 컬럼 의존 여부 불확실생산자가 변경 전 모든 코드 직접 탐색lineage 기반 영향도 분석 즉시 가능
담당자 불명확장애 발생 시 핑퐁계약에 owner 명시, 에스컬레이션 경로 존재

실전 체크리스트

데이터 계약을 처음 만들 때

  • [ ] 생산자 팀과 소비자 팀 모두 계약 내용에 동의했는가?
  • [ ] 모든 필드의 의미(semantic)가 명시되어 있는가?
  • [ ] SLA가 측정 가능한 숫자로 정의되어 있는가?
  • [ ] 기술 소유자와 비즈니스 소유자가 분리되어 있는가?
  • [ ] Breaking change 정의와 deprecation 기간이 합의되어 있는가?
  • [ ] 계약 검증이 CI/CD에 통합되어 있는가?
  • [ ] 위반 시 알림 경로와 대응 프로세스가 정해져 있는가?

Breaking change를 처리할 때

  • [ ] 변경이 breaking인지 backward-compatible인지 분류했는가?
  • [ ] 모든 소비자를 lineage로 식별했는가?
  • [ ] 충분한 deprecation 기간(최소 30일)을 설정했는가?
  • [ ] 구 버전과 신 버전 병렬 운영 계획이 있는가?
  • [ ] 마이그레이션 가이드를 소비자에게 전달했는가?
  • [ ] 이전 완료 여부를 추적하는 수단이 있는가?

기억할 문장

데이터 계약은 소스와 플랫폼 사이의 신뢰 메커니즘이다. 계약이 없으면 소스 팀은 변경의 downstream 영향을 알 수 없고, 플랫폼 팀은 "언제 무엇이 바뀔지 모르는 상태"로 운영된다. 좋은 계약은 양쪽이 더 빠르게 움직일 수 있게 한다. 생산자는 계약 범위 안에서 자유롭게 내부를 바꿀 수 있고, 소비자는 계약이 지켜지는 한 안심하고 의존할 수 있다.

다음 장에서는 계약과 연결된 데이터 품질(Data Quality): completeness, freshness, uniqueness, validity, reconciliation을 다룬다.

References

  • bitol-io, Open Data Contract Standard (ODCS) — https://github.com/bitol-io/open-data-contract-standard
  • Acceldata, How Data Contracts Enforce Pipeline Stability & Quality — https://www.acceldata.io/blog/how-data-contracts-guarantee-pipeline-reliability-data-quality-slas
  • Monte Carlo, Data Contracts Explained — https://montecarlo.ai/blog-data-contracts-explained
  • Branch Boston, Data Contracts vs Data SLAs — https://branchboston.com/data-contracts-vs-data-slas-ensuring-data-quality-at-scale/
  • Medium, Data Contracts: 9 Versioning Rules That End Schema Wars — https://medium.com/@bhagyarana80/data-contracts-9-versioning-rules-that-end-schema-wars-ac58badddc2c
  • DEV Community, Data Contract Framework Implementation Guide — https://dev.to/thesius_code_7a136ae718b7/data-contract-framework-data-contract-framework-implementation-guide-hhj