Skip to main content

왜 모니터링이 중요한가?

데이터 파이프라인은 “실행되고 있다”는 것만으로는 충분하지 않습니다. 제시간에 완료되었는지, 데이터 품질은 괜찮은지, 비용은 예산 내인지 를 지속적으로 확인해야 합니다. 모니터링이 없으면 장애를 사후에야 발견하게 되고, 이는 SLA 위반과 비즈니스 손실로 이어질 수 있습니다.
💡 모니터링의 3대 축: (1) 장애 감지— 실패를 빠르게 발견하고 대응합니다. (2) 성능 추적— 실행 시간 변화를 관찰하여 잠재적 문제를 예방합니다. (3) 비용 관리— 리소스 사용량과 비용을 추적하여 최적화합니다.

Job Run 상태 및 생명주기

Job Run은 다음과 같은 생명주기를 거칩니다.
상태전이 조건다음 상태
(시작)트리거 발생QUEUED
QUEUED대기열에서 선택PENDING
PENDING클러스터 준비 완료RUNNING
RUNNING실행 완료/실패TERMINATING
TERMINATING정상 종료TERMINATED
TERMINATING오류 발생FAILED
TERMINATING타임아웃TIMED_OUT
RUNNING사용자 취소CANCELLING → CANCELLED
FAILED재시도 (max_retries > 0)PENDING
TIMED_OUTretry_on_timeout = truePENDING

상태별 설명

상태설명모니터링 포인트
QUEUED대기열에서 실행 순서를 기다립니다max_concurrent_runs 초과 시 발생
PENDING클러스터 시작을 기다립니다시작 시간이 길면 인스턴스 부족 의심
RUNNING태스크가 실행 중입니다실행 시간이 평소보다 길면 경고
TERMINATED정상적으로 완료되었습니다result_state = SUCCESS 확인
FAILED오류로 인해 실패했습니다에러 메시지 확인, 알림 발송
TIMED_OUT설정된 시간 내에 완료되지 못했습니다타임아웃 값 조정 검토
CANCELLED사용자 또는 시스템에 의해 취소되었습니다취소 원인 파악

Result State (최종 결과)

result_state설명
SUCCESS모든 태스크가 성공적으로 완료되었습니다
FAILED하나 이상의 태스크가 실패했습니다
TIMEDOUT타임아웃으로 종료되었습니다
CANCELED실행이 취소되었습니다
MAXIMUM_CONCURRENT_RUNS_REACHED동시 실행 제한으로 스킵되었습니다
EXCLUDED조건부 실행에서 제외되었습니다

실행 이력 확인

Workflows UI

확인 항목위치용도
실행 이력 목록Workflows → Job → Runs 탭최근 실행 상태 일괄 확인
태스크별 상태개별 Run → DAG 뷰어느 태스크에서 실패했는지 파악
실행 시간 추이Job → Runs 탭의 Duration 그래프성능 변화 트렌드 분석
로그 확인개별 Task → Output / Logs에러 메시지, 스택 트레이스 확인
Spark UI개별 Task → Spark UI 링크스테이지별 성능, 셔플 분석

API로 실행 이력 조회

from databricks.sdk import WorkspaceClient

w = WorkspaceClient()

# 최근 실행 이력 조회
runs = w.jobs.list_runs(
    job_id=12345,
    limit=10,
    expand_tasks=True
)

for run in runs:
    print(f"Run {run.run_id}: {run.state.result_state} "
          f"({run.execution_duration / 1000:.0f}초)")

    # 실패한 태스크 확인
    if run.state.result_state == "FAILED":
        for task in run.tasks:
            if task.state.result_state == "FAILED":
                print(f"  실패 태스크: {task.task_key}")
                print(f"  에러: {task.state.state_message}")

알림 설정 상세

알림 이벤트

이벤트설명권장 대상
On StartJob 실행 시작 시 알림을 보냅니다장시간 실행 Job
On Success성공적으로 완료 시 알림을 보냅니다SLA 관리 필요 Job
On Failure실패 시 알림을 보냅니다모든 프로덕션 Job (필수)
On Duration Warning설정 시간 초과 시 경고를 보냅니다SLA 마감이 있는 Job
On Retry태스크 재시도 시 알림을 보냅니다불안정한 Job 모니터링
On Streaming Backlog스트리밍 백로그 초과 시 알림을 보냅니다스트리밍 Job

Webhook 연동

Slack, Microsoft Teams, PagerDuty 등 외부 서비스와 Webhook으로 연동할 수 있습니다. Slack Webhook 설정 절차:
  1. Databricks Workspace → SettingsNotifications destinationsAdd destination
  2. Destination type: Slack 선택
  3. Slack Webhook URL 입력
  4. 테스트 메시지 발송 확인
  5. Job 설정에서 해당 Webhook ID 참조
# 알림 목적지 설정 후 Job에 연동
webhook_notifications:
  on_start:
    - id: "${var.slack_info_webhook}"
  on_success:
    - id: "${var.slack_info_webhook}"
  on_failure:
    - id: "${var.slack_alert_webhook}"
    - id: "${var.pagerduty_webhook}"
  on_duration_warning_threshold_exceeded:
    - id: "${var.slack_alert_webhook}"

email_notifications:
  on_failure:
    - "data-oncall@company.com"
    - "team-lead@company.com"
  on_duration_warning_threshold_exceeded:
    - "data-oncall@company.com"

시스템 테이블 활용

Databricks는 Job 실행 이력, 비용, 클러스터 메트릭을 시스템 테이블 에 자동으로 기록합니다. SQL로 분석하여 커스텀 대시보드를 만들 수 있습니다.
💡 시스템 테이블(System Tables) 은 Databricks가 자동으로 수집하는 운영 메타데이터입니다. system 카탈로그 아래에 위치하며, Unity Catalog를 통해 접근합니다.

주요 시스템 테이블

테이블설명
system.lakeflow.job_run_timelineJob 실행 타임라인 (시작, 종료, 상태)
system.lakeflow.job_task_run_timeline태스크 레벨 실행 타임라인
system.billing.usage리소스 사용량 및 비용
system.compute.clusters클러스터 정보

실행 이력 분석 쿼리

-- 최근 7일간 Job 실행 현황 요약
SELECT
    job_id,
    job_name,
    COUNT(*) AS total_runs,
    SUM(CASE WHEN result_state = 'SUCCESS' THEN 1 ELSE 0 END) AS success_count,
    SUM(CASE WHEN result_state = 'FAILED' THEN 1 ELSE 0 END) AS failure_count,
    ROUND(
        SUM(CASE WHEN result_state = 'SUCCESS' THEN 1 ELSE 0 END) * 100.0 / COUNT(*), 1
    ) AS success_rate_pct,
    AVG(TIMESTAMPDIFF(MINUTE, period_start_time, period_end_time)) AS avg_duration_min,
    MAX(TIMESTAMPDIFF(MINUTE, period_start_time, period_end_time)) AS max_duration_min
FROM system.lakeflow.job_run_timeline
WHERE period_start_time >= CURRENT_DATE() - INTERVAL 7 DAYS
GROUP BY job_id, job_name
ORDER BY failure_count DESC;

실패 패턴 분석 쿼리

-- 자주 실패하는 태스크 Top 10
SELECT
    t.job_id,
    j.job_name,
    t.task_key,
    COUNT(*) AS failure_count,
    COLLECT_SET(t.result_state) AS failure_types,
    MAX(t.period_start_time) AS last_failure_time
FROM system.lakeflow.job_task_run_timeline t
JOIN system.lakeflow.job_run_timeline j
    ON t.run_id = j.run_id
WHERE t.result_state IN ('FAILED', 'TIMEDOUT')
    AND t.period_start_time >= CURRENT_DATE() - INTERVAL 30 DAYS
GROUP BY t.job_id, j.job_name, t.task_key
ORDER BY failure_count DESC
LIMIT 10;

비용 추적 및 분석

Job별 비용 확인

-- 최근 30일 Job별 DBU 사용량 (비용 상위 20)
SELECT
    usage_metadata.job_id,
    j.job_name,
    SUM(usage_quantity) AS total_dbus,
    COUNT(DISTINCT usage_date) AS active_days,
    ROUND(SUM(usage_quantity) / COUNT(DISTINCT usage_date), 1) AS avg_daily_dbus,
    SUM(usage_quantity * list_price) AS estimated_cost_usd
FROM system.billing.usage u
LEFT JOIN system.lakeflow.job_run_timeline j
    ON u.usage_metadata.job_id = j.job_id
WHERE u.usage_metadata.job_id IS NOT NULL
    AND u.usage_date >= CURRENT_DATE() - INTERVAL 30 DAYS
GROUP BY usage_metadata.job_id, j.job_name
ORDER BY total_dbus DESC
LIMIT 20;

비용 추이 분석

-- 주간 비용 추이 (Job 컴퓨트)
SELECT
    DATE_TRUNC('WEEK', usage_date) AS week,
    sku_name,
    SUM(usage_quantity) AS total_dbus,
    SUM(usage_quantity * list_price) AS estimated_cost_usd
FROM system.billing.usage
WHERE usage_metadata.job_id IS NOT NULL
    AND usage_date >= CURRENT_DATE() - INTERVAL 90 DAYS
GROUP BY DATE_TRUNC('WEEK', usage_date), sku_name
ORDER BY week DESC, total_dbus DESC;

비용 최적화 기회 발견

-- Spot 인스턴스 미사용 Job 탐지 (비용 절감 기회)
SELECT DISTINCT
    usage_metadata.job_id,
    sku_name,
    SUM(usage_quantity) AS total_dbus
FROM system.billing.usage
WHERE usage_metadata.job_id IS NOT NULL
    AND sku_name LIKE '%ALL_PURPOSE%'   -- Job Cluster가 아닌 All-Purpose 사용
    AND usage_date >= CURRENT_DATE() - INTERVAL 30 DAYS
GROUP BY usage_metadata.job_id, sku_name
HAVING SUM(usage_quantity) > 100
ORDER BY total_dbus DESC;

로그 확인 방법

Driver Log

각 태스크의 Driver Log에서 에러 메시지, 스택 트레이스를 확인할 수 있습니다.
로그 유형확인 방법내용
Standard OutputTask → Output 탭print() 출력, 노트북 셀 결과
Standard ErrorTask → Logs → stderr에러 메시지, 경고
Log4jTask → Logs → log4j-activeSpark 내부 로그
Cluster Event LogCluster → Event Log클러스터 시작/종료, 노드 추가/제거

Spark UI 활용

증상Spark UI 탭확인 항목
Job 단계에서 느림Jobs 탭스테이지별 시간을 확인합니다
셔플 문제Stages 탭Shuffle Read/Write를 확인합니다
데이터 편향Tasks 탭태스크별 시간 편차를 확인합니다
메모리 문제Executors 탭GC 시간, 메모리 사용량을 확인합니다

실습: 모니터링 대시보드 쿼리

아래 쿼리들을 Databricks SQL 대시보드에 배치하면 종합적인 모니터링 환경을 구축할 수 있습니다.

대시보드 패널 1: 실행 현황 요약

-- 오늘의 Job 실행 현황 (대시보드 카드용)
SELECT
    COUNT(*) AS total_runs,
    SUM(CASE WHEN result_state = 'SUCCESS' THEN 1 ELSE 0 END) AS succeeded,
    SUM(CASE WHEN result_state = 'FAILED' THEN 1 ELSE 0 END) AS failed,
    SUM(CASE WHEN result_state IS NULL THEN 1 ELSE 0 END) AS running
FROM system.lakeflow.job_run_timeline
WHERE period_start_time >= CURRENT_DATE();

대시보드 패널 2: 실행 시간 이상 감지

-- 평균 대비 2배 이상 오래 걸린 실행 (최근 24시간)
WITH job_stats AS (
    SELECT
        job_id,
        job_name,
        AVG(TIMESTAMPDIFF(MINUTE, period_start_time, period_end_time)) AS avg_duration,
        STDDEV(TIMESTAMPDIFF(MINUTE, period_start_time, period_end_time)) AS stddev_duration
    FROM system.lakeflow.job_run_timeline
    WHERE period_start_time >= CURRENT_DATE() - INTERVAL 30 DAYS
        AND result_state = 'SUCCESS'
    GROUP BY job_id, job_name
)
SELECT
    r.job_id,
    r.job_name,
    r.run_id,
    TIMESTAMPDIFF(MINUTE, r.period_start_time, r.period_end_time) AS actual_duration_min,
    ROUND(s.avg_duration, 1) AS avg_duration_min,
    ROUND(
        TIMESTAMPDIFF(MINUTE, r.period_start_time, r.period_end_time) / s.avg_duration, 1
    ) AS duration_ratio
FROM system.lakeflow.job_run_timeline r
JOIN job_stats s ON r.job_id = s.job_id
WHERE r.period_start_time >= CURRENT_DATE() - INTERVAL 1 DAY
    AND TIMESTAMPDIFF(MINUTE, r.period_start_time, r.period_end_time) > s.avg_duration * 2
ORDER BY duration_ratio DESC;

대시보드 패널 3: 일별 성공률 추이

-- 최근 30일 일별 성공률 (라인 차트용)
SELECT
    DATE(period_start_time) AS run_date,
    COUNT(*) AS total_runs,
    ROUND(
        SUM(CASE WHEN result_state = 'SUCCESS' THEN 1 ELSE 0 END) * 100.0 / COUNT(*), 1
    ) AS success_rate_pct
FROM system.lakeflow.job_run_timeline
WHERE period_start_time >= CURRENT_DATE() - INTERVAL 30 DAYS
    AND result_state IS NOT NULL
GROUP BY DATE(period_start_time)
ORDER BY run_date;

트러블슈팅 체크리스트

Job이 실패했을 때

순서확인 사항조치
1에러 메시지 확인Task → Output/Logs에서 에러 확인
2최근 코드 변경 확인최근 배포된 변경이 원인인지 확인
3데이터 변경 확인소스 데이터의 스키마 변경, 볼륨 급증 확인
4리소스 부족 확인OOM, Disk Space 부족 여부 확인
5외부 의존성 확인API, 데이터베이스 연결 장애 확인
6재시도 로그 확인재시도 횟수 소진 여부 확인

Job이 느려졌을 때

순서확인 사항조치
1데이터 볼륨 증가소스 데이터 크기 변화 확인
2Spark UI: Shuffle과도한 셔플이 발생하는지 확인
3Spark UI: Skew데이터 편향(Skew)이 있는지 확인
4클러스터 이벤트 로그노드 손실, 리사이즈 이벤트 확인
5Spot 인스턴스 회수Spot 회수로 인한 재시작 확인
6동시 실행 경합같은 리소스를 사용하는 다른 Job 확인

Job이 시작되지 않을 때

순서확인 사항조치
1스케줄 상태Pause 상태가 아닌지 확인
2max_concurrent_runs이전 실행이 아직 진행 중인지 확인
3클러스터 할당량계정의 클러스터 할당량 초과 여부 확인
4인스턴스 가용성선택한 인스턴스 타입의 가용성 확인
5권한 확인Job 소유자의 권한이 유효한지 확인

모범 사례 요약

영역모범 사례
알림모든 프로덕션 Job에 실패 알림을 설정합니다. Slack + 이메일 이중화를 권장합니다
Duration Warning평소 실행 시간의 1.5~2배를 임계치로 설정합니다
재시도일시적 오류에 대비하여 1~2회 재시도를 설정합니다
태그Job에 팀명, 프로젝트명, 환경 태그를 달아 비용과 실행을 추적합니다
대시보드시스템 테이블 기반 모니터링 대시보드를 구축합니다
로그 보존중요한 로그는 별도 테이블에 저장하여 장기 분석에 활용합니다
정기 점검주간/월간 단위로 비용, 성공률, 실행 시간 추이를 리뷰합니다

참고 링크