티스토리 뷰
광고 이벤트 레이크하우스 구축기 — 헬스체크 (쿼리부터 Slack 경보까지)
코딩하는 제리코 2026. 6. 24. 13:591. 문제 - "건강한지 어떻게 알지?"
평가 기준에 이런 항목이 있었다.
"운영자가 매일 5분 안에 파이프라인 헬스체크를 할 수 있는가"
- Iceberg 메타테이블 기반 헬스 체크 쿼리 5~10개 + BI 대시보드 운영 메트릭 탭(신선도, 일자별 행수, 파일 수, 평균 크기)
근데 지금까지 만든 파이프라인엔 흩어진 체크용 SQL 몇 개만 있었지,
'운영자가 실제로 돌려서 건강한지 판단하는' 부분은 없었다.
그래서 제대로 만들어 보고 싶었다.
2. 그래서 헬스체크 쿼리가 뭔가?
데이터 자체가 아니라 Iceberg 메타테이블을 보는 쿼리다.
Iceberg는 테이블마다 숨은 메타 테이블을 준다:
- `$snapshots` - 언제 무엇이 커밋됐나(=신선도, 이력)
- `$files` - 데이터 파일 몇 개, 평균 크기(=small file 여부)
- `$manifests` - 매니페스트 누적.
이걸로 파이프라인이 건강한가 를 1분 내 판별한다:
최근 적재됐나? · 파일이 잘게 안 쪼개졌나? · 스냅샷 안 쌓였나? · 행수 이상 없나? · 중복 0인가? · 집계 안 깨졌나?
3. 산출물
3-1. 산출물 ① - `pipline_health.py` (한 명령 자동 리포트)
운영자가 한 명령으로 돌려 자동 판정 리포트를 받는 구조이다.
아래 표와 같이 총 8개의 체크가 있다.
각각 OK/WARN/FAIL로 판정한다.
| # | 체크 | 근거 | 판정 |
| 1 | 신선도 | bronze=$snapshots 최신 커밋, silver/gold=max(updated_at) | 임계(분) 초과 |
| 2 | small file | $files 파일수, 평균 크기 | 평균<32MB & 파일>5 → compaction |
| 3 | 스냅샷 누적 | $snapshots count | 임계 초과 (expire) |
| 4 | 처리량 | silver 처리 행수 | 0이면 |
| 5 | 중복 | count(*)-count(distinct event_id) | >0 |
| 6 | 퍼널 정합 | requests >= impressions >= clicks >= conversion | 위반 |
| 7 | 비율 범위 | fill_rate/ctr/cvr 이 0과 1사이어야함 | 이탈 |
| 8 | cost 정합 | gold cost==silver click cost 합 | 불일치 |
다르 근거들은 보면 바로 이해될 것들인데 이해가 힘들 수 있는것만 따로 설명해보자면:
#5 count(*)-count(distinct event_id)
→ 전체행 에서 서로 다른 event_id 개수(중복 배고 센것)
→ event_id는 이벤트마다 유일한거니까 중복이 없다면 두개를 뺐을때 0이 나온다.
#8 gold cost == silver click cost 합
cost(광고비) 정의 == SUM(cost) WHERE event_type='click' (클릭만비용 발생, CPC 모델)
Gold의 총 cost와 Silver의 click 이벤트들의 cost 합이 같아야 하는거다.
핵심= `FAIL` 이면 `exit 1` → 나중에 Airflow/Slack 게이트로 자동 확장할 발판이다. (뒤에도 적을거임)
실제 출력(라이브로 돌린 결과):
==============================================================================
파이프라인 헬스체크 리포트
==============================================================================
⚠️ WARN | 신선도 bronze.ad_clicks | 1038분 전 (임계 30분)
✅ OK | 신선도 gold.campaign_daily | 2분 전 (임계 30분)
✅ OK | 파일 silver.processed | 3개·평균 30.78MB
✅ OK | 중복 event_id (silver) | 0건 (0이어야 정상)
✅ OK | cost 정합성 | gold=9309.45 vs silver_click=9309.45 (차이 0.00)
==============================================================================
종합: 29개 체크 | ❌ 0 FAIL · ⚠️ 5 WARN · ✅ 24 OK
==============================================================================
이런걸 보고 운영자는 판단할 수있는거다.
참고로 위에 있는 WARN은 내가 지금 라이브 스트리밍을 안 켜놔서 최근적재가 없어서 나오는거다.
그리고 한 가지 문제. 이 긴 `spark-submit` 명령을 운영자가 매번 손으로 칠 순 없다.
운영자가 개발자일 수 있지만, 진짜 광고 지표를 보면서 판단이 필요한건 퍼블리셔 프로젝트의 PM일 수도 있기 때문이다.
그래서 같은 헬스 지표를 1) 눈으로 보는 대시보드와 2)자동으로 도는 잡 + 알림으로 구현했다.
3-2. 산출물 ② - 대시보드 운영 메트릭 탭
Superset → Trino → Iceberg 구조이다. (write=Spark / read=Trino 분리)
Trino를 고른 이유는 Iceberg 메타테이블($files/$snapshots)을 SQL로 그대로 읽기 때문이다.
그래서 비지니스 KPI뿐 아니라 운영 메트릭 탭까지 같은 엔진으로 된다.
운영 탭엔 차트 5개를 깔았다.
| 차트 | 정상 | 이상 신호 |
| 신선도 | 최신 시각이 최근 | 옛날 시각 → 적재 멈춤 |
| 일자별 행 수 | 고르게 | 0/급증 → 이상 트래픽 |
| 중복 event_id | 0 | 0 아님 → dedup 깨짐 |
| 파일 상태 | 평균 크기 적당 | 작고 많음 → compaction 필요 |
| 스냅샷 수 | 임계 이하 | 증가 → expire 필요 |
그리고 Superset 대시보드는 보통 UI에서 마우스로 만들어서 남이 재현하기 힘들다.
그리고 내가 Superset 을 한번도 안써봐서 이번엔 AI를 사용하여, API로 데이터셋, 차트, 대시보드를 만들고 export해서 import 번들(zip)을 떴다.
그리고 그걸 import 해서 운영 탭을 통째로 재현했다.
아래가 실제 Superset 대시보드 운영 탭 상태다


3-3. 산출물 ③ - 자동화: Airflow 잡 + Slack 실패 경보
긴 명령을 손으로 안치게 이 헬스체크들을 Airflow 잡으로 감쌌다.
health_check DAG (매시간)
└─ pipeline_health.py 실행
├─ 0 FAIL → 태스크 초록 → 조용 (무알림)
└─ FAIL(exit 1)/크래시 → 태스크 빨강 → Slack 경보 🚨
- 매시간돈다. 헬스체크는 읽기 전용이라 가벼워서 자주 돌려 문제를 빨리 잡는다.
- 앞서 만든 `exit 1`이 여기서 사용된다 → 태스크가 자동으로 빨개지고 `on_failure_callback`이 Slack 경보를 쏜다.
- 이 콜백은 새로 만든건 아니고, medallion, maintenance 잡에도 똑같이 썼다
- WARN은 알림 안가고, 치명 적인 FAIL/크래시만 - 노이즈 방지

4. 산출물 ④ - 데일리 KPI 리포트 Slack 봇
위까진 '문제 생기면' 발생하는 알림이었다.
근데 운영자 또는 프로젝트 인원들은 문제가 없어도 매일 어제 광고가 어땠나를 궁금해할 수 있다.
그래서 매일 아침 정상 KPI 요약을 Slack에 푸시하는 봇을 더해봤다.
광고 도메인 특성상 어제vs오늘 비교는 의미가 약할것 같다.
사실 광고는 요일 계절성(주중/주말)이 세서, 전주 동요일(D-7), 전월 동요일(D-28)대비가 진짜 증감을 보여준다고 생각했다.
📊 데일리 KPI 리포트 — 2026-06-23 ← D-1(어제), 완료된 날 집계
지표 오늘 전주대비 전월대비
──────────────────────────────────
노출 259.7k ▼-5.1% ▼-6.2%
클릭 5.7k ▼-9.1% ▼-14.2%
광고비 $3,437 ▼-9.9% ▼-0.9%
...
+ 최근 7일 표 + 4지표 추세 차트(광고비·노출·클릭·전환) 이미지
아래와 같이 핵심 지표를 보여주며,
최근 30일동안의 핵심 지표들을 그래프로도 그려서 매일 아침 9시에 잡이 돈뒤, 슬랙에 올라오도록 하였다.

5. 최종 운영자 워크플로우
평소 → 아무것도 안 함 (잡이 매시간 조용히 체크)
매일 아침 → 데일리 리포트가 Slack에 KPI 요약을 던져줌 (← 푸시)
치명 문제 → Slack 경보 핑 → 로그 링크로 원인 (← 푸시)
궁금/WARN → 대시보드 운영 탭 열어 5개 차트 확인 (← 풀)
같은 헬스 지표를 스크립트(자동판정), 대시보드(시각), Slack(알림) 세 곳에서 보고,
운영자는 평소 무 알림 → 문제 시 푸시 → 궁금하면 풀로 5분안에 헬스체크가 끝난다
'Projects > 광고 플랫폼 Lakehouse 실전 설계 with Iceberg' 카테고리의 다른 글
| 광고 이벤트 레이크하우스 구축기 — 파이프라인 단위 테스트 + CI 붙이기 (0) | 2026.06.24 |
|---|---|
| [트러블슈팅] Silver를 일배치 → 15분 near-real-time으로 당기기 (0) | 2026.06.23 |
| [트러블 슈팅] Iceberg Maintenance -- 현재 구현 & 개선 고민 (0) | 2026.06.23 |
| 광고 이벤트 레이크하우스 구축기 (6-1) — Silver 레이어: 설계와 전체 틀 (0) | 2026.06.20 |
| [개념] Glue Catalog는 왜 필요한가 - 내 Bronze 레이어가 카탈로그와 소통하는 전 과정 (0) | 2026.06.16 |
- Total
- Today
- Yesterday
- 데이터 파이프라인
- 테스트로직
- iceberg
- Unity Catalog
- s3
- Daynamic Task
- 데이터파이프라인
- Data Dngineering
- Data engineering
- Glue
- lake house
- AWS
- DataSet
- task
- RDD
- airflow
- AWS Glue Catalog
- Consumer DAG
- Data Engineerring
- de
- spark
- Prodcuder DAG
- Spark structured streaming
- Data Pipeline
- lakehouse
- Databricks
- 메타코드부트캠프
- docker
- kafka
- DAG
| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | |||
| 5 | 6 | 7 | 8 | 9 | 10 | 11 |
| 12 | 13 | 14 | 15 | 16 | 17 | 18 |
| 19 | 20 | 21 | 22 | 23 | 24 | 25 |
| 26 | 27 | 28 | 29 | 30 | 31 |