Skip to main content
HLS 스트림 상태와 영상 이상 감지를 보여주는 모니터링 대시보드

HLS 스트림 모니터링 대시보드

active
monitoring hls ffmpeg flask streaming

개요

HLS 스트림을 주기적으로 점검하고 영상 이상을 감지하는 Python 기반 모니터링 서비스입니다. 방송이나 VOD 스트림은 HTTP 요청이 성공하더라도 실제 화면이 검거나 멈춰 있을 수 있습니다. 단순 헬스체크만으로는 이런 장애를 잡기 어려워서, ffmpeg 분석 결과를 기준으로 스트림 상태를 판단하도록 만들었습니다.

기능내용
주기 점검설정된 HLS 소스를 30초마다 분석
영상 이상 감지Black Screen, Frozen Frame 감지
장애 판정warning, suspect, signal_loss, check_failed 단계로 상태 판단
이력 저장SQLite에 점검 결과와 상태 변경 이력 저장
알림JSON 웹훅, Slack, Microsoft Teams 지원
대시보드최신 상태와 프리뷰 프레임 확인

기술 스택

영역기술
백엔드Python, Flask
영상 분석ffmpeg, blackdetect, freezedetect
데이터베이스SQLite
인증Keycloak OIDC SSO
알림Webhook, Slack, Microsoft Teams

모니터링 방식

각 스트림은 독립 스레드에서 주기적으로 점검합니다. ffmpeg로 짧은 구간을 분석하고, 출력 로그에서 검은 화면과 화면 정지 구간을 파싱해 ProbeResult로 정규화합니다.

분석과 프리뷰 생성은 한 번의 ffmpeg 실행 안에서 처리합니다. 입력 영상을 split=2로 나눠 한쪽은 blackdetect/freezedetect 분석에 쓰고, 다른 한쪽은 대시보드에 보여줄 썸네일로 저장합니다.

flowchart TD
  Config[config/streams.json]
  Service[MonitorService]
  Thread[Per-stream Thread]
  FFMPEG[ffmpeg probe]
  Parser[black/freeze result parser]
  DB[(SQLite)]
  Preview[Preview frame]
  Notifier[Webhook notifier]
  Dashboard[Flask Dashboard]

  Config --> Service
  Service --> Thread
  Thread --> FFMPEG
  FFMPEG --> Parser
  Parser --> DB
  Thread --> Preview
  Parser --> Notifier
  DB --> Dashboard
  Preview --> Dashboard

주요 구현 포인트

Black Screen과 Frozen Frame 감지

ffmpegblackdetect, freezedetect 필터를 사용해 사람이 화면을 직접 보지 않아도 이상 징후를 수치로 판단합니다.

ffmpeg -i <hls_url> \
  -vf "blackdetect=d=3:pic_th=0.98:pix_th=0.1,freezedetect=n=-50dB:d=5" \
  -f null -
감지 항목기준
Black Screen지정 시간 이상 검은 화면 지속
Frozen Frame지정 시간 이상 프레임 변화 없음
WarningBlack 또는 Freeze 중 하나만 감지
SuspectBlack과 Freeze가 함께 감지됐지만 연속 실패 기준 미달
Signal LossBlack/Freeze 조합이 연속 실패 기준 충족
Check Failedffmpeg 실행 실패, timeout, DNS/TLS/HTTP 오류

연속 실패 기반 장애 판정

일시적인 네트워크 흔들림이나 짧은 인코딩 지연을 바로 장애로 보지 않도록 연속 실패 기준을 둡니다. Black과 Freeze가 함께 감지되면 먼저 suspect로 보고, 같은 패턴이 설정 횟수 이상 반복될 때 signal_loss로 올립니다. check_failed도 2회 이상 연속 발생해야 장애로 봅니다.

실패 원인은 그대로 로그를 보여주기보다 운영자가 바로 읽을 수 있는 문장으로 정리합니다. HTTP 4xx/5xx, DNS 실패, timeout, TLS 인증서 문제를 구분해 reason에 남기고, 필요한 경우 stderr 일부를 같이 저장합니다.

Recovery 알림

장애 발생 알림만 보내면 운영자가 복구 여부를 다시 확인해야 합니다. 상태가 healthy로 돌아오면 recovery 이벤트를 별도로 발송해 장애 시작과 종료를 한 흐름으로 추적할 수 있게 했습니다.

점검 이력은 SQLite에 저장하되, 정상/경고 이력은 30일이 지나면 정리합니다. 장애 분석에 필요한 최근 이력은 남기고, 장기 운영 중 DB가 불필요하게 커지지 않도록 했습니다.

설정 파일 기반 소스 관리

모니터링 대상과 판정 기준은 config/streams.json에서 관리합니다. 운영 중 소스별 기준값을 조정할 수 있도록 분석 시간, black/freeze 임계값, 연속 실패 기준을 설정으로 분리했습니다.

{
  "check_interval_sec": 30,
  "probe_duration_sec": 10,
  "black_duration_sec": 3,
  "black_pic_ratio": 0.98,
  "black_pixel_threshold": 0.1,
  "freeze_duration_sec": 5,
  "freeze_noise_db": -50,
  "consecutive_failures_for_down": 2
}

프로젝트 구조

src/cms_monitor/
├── __main__.py
├── config.py
├── monitor.py
├── notifier.py
├── storage.py
├── timeutil.py
├── auth.py
├── web.py
└── static/
    └── dashboard.js

실행

export CMS_SESSION_SECRET='your-secret'
export CMS_KEYCLOAK_CLIENT_SECRET='keycloak-secret'
uv run python -m cms_monitor --host 0.0.0.0 --port 8080

활용 사례

  • 방송 스트림 품질 모니터링
  • VOD 서비스 가용성 확인
  • CDN 장애 빠른 감지
  • 인코더 장애와 소스 장애의 초기 탐지

향후 개선점

  • 다중 CDN 비교 점검
  • QoE 지표 추가
  • 스트림별 알림 정책 분리
  • 대시보드 차트와 장애 타임라인 개선