본문 바로가기

Observability

알림 설계: 노이즈를 줄이고 의미 있는 알림만 받는 방법

반응형

모니터링 도구를 도입하면 대부분 알림부터 설정합니다. CPU 80% 초과, 디스크 90% 초과, 5xx 에러 발생 — 하나씩 추가하다 보면 하루에 수십 건의 알림이 울립니다. 팀원들은 알림을 무시하기 시작하고, 정작 실제 장애 알림도 놓치게 됩니다. 이 글에서는 알림 피로(Alert Fatigue)를 줄이고, 사람이 대응해야 하는 상황에만 알림이 울리도록 설계하는 원칙을 정리합니다.

핵심 요약

  • 알림은 "사람이 즉시 대응해야 하는 상황"에만 설정합니다. 정보성 알림은 대시보드로 대체합니다.
  • 원인(Cause)이 아닌 증상(Symptom)에 알림을 걸어야 커버리지가 높아집니다.
  • 심각도(Severity)를 명확히 분류하고, 각 심각도에 맞는 알림 채널과 대응 시간을 정의합니다.
  • for 절(지속 시간)을 설정하여 일시적 스파이크에 의한 오탐(False Positive)을 줄입니다.
  • 알림은 한 번 설정하고 끝이 아닙니다. 정기적으로 리뷰하여 노이즈를 제거하고 임계값을 조정합니다.

1. 알림 피로란 무엇인가

알림 피로 발생 과정
알림 피로 발생 과정

On-call 엔지니어의 슬랙 채널에 하루 50건의 알림이 쌓입니다. 그 중 실제로 대응이 필요한 것은 2~3건입니다. 나머지는 자동 복구되거나, 정보성이거나, 이미 알고 있는 상태입니다.

이 상황이 반복되면:

단계 현상 결과
1단계 알림이 많아짐 모든 알림을 하나씩 확인하느라 시간 소모
2단계 대부분 대응 불필요 확인 "또 이거구나" → 알림 확인을 미루기 시작
3단계 알림 무시 습관화 슬랙 채널 음소거, 이메일 필터 설정
4단계 실제 장애 알림 놓침 MTTR(평균 복구 시간) 증가, SLA 위반

Google의 SRE 팀은 이를 "알림은 사람이 즉시 행동을 취해야 하는 상황에만 발생해야 한다"라는 원칙으로 정리합니다. 행동이 필요 없는 알림은 알림이 아니라 로그 또는 대시보드입니다.

알림 피로의 주요 원인

원인 예시 해결 방향
낮은 임계값 CPU > 50%에 알림 설정 서비스 영향 기준으로 임계값 재설정
for 절 없음 순간 스파이크에도 알림 발생 5분 이상 지속 조건 추가
원인 기반 알림 "디스크 80%" → 실제 서비스 영향 없음 증상 기반으로 전환
중복 알림 같은 이슈에 여러 알림 동시 발생 그룹핑과 억제(Inhibition) 적용
자동 복구 알림 Auto Scaling으로 해결되는 상황에도 알림 자동 복구 후에도 지속될 때만 알림

2. 증상 기반 vs 원인 기반 알림

증상 기반 vs 원인 기반 알림 비교
증상 기반 vs 원인 기반 알림 비교

Google SRE Book에서 강조하는 핵심 원칙 중 하나는 "증상(Symptom)에 알림을 걸고, 원인(Cause)은 진단 정보로 활용하라"입니다.

원인 기반 알림의 문제

원인 기반 알림은 시스템 내부 상태에 직접 걸리는 알림입니다.

# 원인 기반 알림 (비권장)
- alert: HighCPUUsage
  expr: node_cpu_seconds_total{mode="idle"} < 0.2
  for: 5m
  labels:
    severity: warning
  annotations:
    summary: "CPU 사용률이 80%를 초과했습니다"

이 알림의 문제:

  • CPU가 80%여도 서비스 응답 시간이 정상이면 대응할 필요가 없습니다.
  • 반대로 CPU가 40%인데 GC(Garbage Collection)로 응답이 느려질 수 있습니다.
  • CPU 알림은 "뭔가 느릴 수 있다"는 원인 후보일 뿐, 사용자 영향을 직접 보여주지 않습니다.

증상 기반 알림의 장점

증상 기반 알림은 사용자가 체감하는 문제에 걸리는 알림입니다.

# 증상 기반 알림 (권장)
- alert: HighErrorRate
  expr: |
    sum(rate(http_requests_total{status=~"5.."}[5m]))
    /
    sum(rate(http_requests_total[5m])) > 0.05
  for: 5m
  labels:
    severity: critical
  annotations:
    summary: "5xx 에러율이 5%를 초과했습니다 (5분 지속)"
    dashboard: "https://grafana.example.com/d/service-overview"

증상 기반 알림의 장점:

측면 원인 기반 증상 기반
커버리지 특정 원인 1개만 감지 여러 원인이 같은 증상을 유발하면 모두 감지
오탐률 높음 (영향 없는 상태에도 발생) 낮음 (사용자 영향이 있을 때만 발생)
대응 필요성 불확실 ("이게 실제로 문제인가?") 명확 ("서비스가 영향을 받고 있다")
유지보수 인프라 변경마다 알림 수정 필요 서비스 동작 기준이므로 안정적

실무 설계 원칙

  • 알림: 증상에 걸립니다 (에러율, 응답 시간, 가용성)
  • 대시보드: 원인을 확인합니다 (CPU, 메모리, 디스크, 큐 깊이)
  • Runbook: 증상 → 원인 후보 → 확인 방법 → 조치를 문서화합니다

증상 알림이 발생하면, 대시보드에서 원인을 추적하는 흐름입니다. 원인 자체에 알림을 걸면 "문제가 아닌 것"에 시간을 낭비하게 됩니다.

Tip
원인 기반 알림이 유용한 예외도 있습니다. 디스크 용량이 90%를 넘어 곧 서비스가 중단될 예측 가능한 상황, 인증서 만료 임박 등 "지금은 괜찮지만 곧 증상이 나타날 것이 확실한" 경우에는 원인 기반 알림이 적합합니다.

3. 심각도 분류와 알림 채널 설계

심각도별 알림 라우팅
심각도별 알림 라우팅

모든 알림을 같은 채널로 보내면 중요한 알림이 묻힙니다. 심각도를 명확히 분류하고, 각 심각도에 맞는 채널과 기대 대응 시간을 정의해야 합니다.

심각도 레벨 정의

심각도 정의 기대 대응 시간 알림 채널
Critical (P1) 서비스 전체 또는 핵심 기능 중단 5분 이내 확인 PagerDuty/전화 + Slack
High (P2) 일부 사용자 영향, 성능 심각 저하 15분 이내 확인 PagerDuty + Slack
Warning (P3) 잠재적 문제, 방치 시 악화 가능 업무 시간 내 확인 Slack 채널
Info (P4) 참고 정보, 대응 불필요 대응 불필요 대시보드만

심각도 판단 기준

심각도를 결정할 때 고려할 질문:

  1. 사용자 영향 범위: 전체 사용자인가, 일부인가, 내부 시스템만인가?
  2. 비즈니스 영향: 매출에 직접 영향을 주는가? (결제, 주문 vs 내부 리포트)
  3. 자동 복구 가능성: Auto Scaling, 재시도 등으로 자동 해결되는가?
  4. 시간 민감도: 지금 당장 조치하지 않으면 악화되는가?

실무 시나리오: 이커머스 서비스 심각도 설계

알림 조건 심각도 근거
결제 API 에러율 > 5% (5분 지속) Critical 매출 직접 영향, 사용자 이탈
상품 검색 응답 p99 > 3초 (10분 지속) High 사용자 경험 저하, 이탈률 증가
주문 처리 큐 깊이 > 1000 (15분 지속) Warning 지연 발생 중이나 즉시 중단은 아님
배치 리포트 생성 실패 Warning 내부 시스템, 다음 업무일에 재처리 가능
디스크 사용량 > 85% Warning 당장 서비스 영향 없으나 방치 시 문제
CPU 사용률 > 70% Info Auto Scaling 동작 중, 대시보드 확인만

Alertmanager 라우팅 설정 예시

# alertmanager.yml
route:
  receiver: 'slack-info'
  group_by: ['alertname', 'service']
  group_wait: 30s
  group_interval: 5m
  repeat_interval: 4h
  routes:
    - match:
        severity: critical
      receiver: 'pagerduty-critical'
      repeat_interval: 5m
    - match:
        severity: high
      receiver: 'pagerduty-high'
      repeat_interval: 15m
    - match:
        severity: warning
      receiver: 'slack-warning'
      repeat_interval: 4h

receivers:
  - name: 'pagerduty-critical'
    pagerduty_configs:
      - service_key: '<P1_SERVICE_KEY>'
        severity: critical
  - name: 'pagerduty-high'
    pagerduty_configs:
      - service_key: '<P2_SERVICE_KEY>'
        severity: high
  - name: 'slack-warning'
    slack_configs:
      - channel: '#alerts-warning'
        title: '{{ .GroupLabels.alertname }}'
        text: '{{ .CommonAnnotations.summary }}'
  - name: 'slack-info'
    slack_configs:
      - channel: '#alerts-info'
        title: '{{ .GroupLabels.alertname }}'
        text: '{{ .CommonAnnotations.summary }}'

4. 알림 규칙 설계 원칙

원칙 1: for 절로 일시적 스파이크 필터링

# 나쁜 예: for 절 없음 — 1초라도 넘으면 알림
- alert: HighLatency
  expr: histogram_quantile(0.99, rate(http_request_duration_seconds_bucket[5m])) > 1

# 좋은 예: 5분 이상 지속될 때만 알림
- alert: HighLatency
  expr: histogram_quantile(0.99, rate(http_request_duration_seconds_bucket[5m])) > 1
  for: 5m

for 절은 조건이 연속으로 충족되는 시간을 의미합니다. 배포 직후 잠깐 응답이 느려지는 것은 정상입니다. 5분 이상 지속되면 실제 문제일 가능성이 높습니다.

권장 for 값:

심각도 for 근거
Critical 2~5분 빠른 감지 필요하지만 최소 확인 시간 확보
High 5~10분 일시적 스파이크 필터링
Warning 10~30분 추세 확인, 자동 복구 대기

원칙 2: 비율(Rate) 기반 알림 사용

# 나쁜 예: 절대값 기반 — 트래픽 적은 시간에 오탐 발생
- alert: TooManyErrors
  expr: sum(increase(http_requests_total{status=~"5.."}[5m])) > 10

# 좋은 예: 비율 기반 — 트래픽 양에 관계없이 일관된 기준
- alert: HighErrorRate
  expr: |
    sum(rate(http_requests_total{status=~"5.."}[5m]))
    /
    sum(rate(http_requests_total[5m])) > 0.01
  for: 5m

절대값(에러 10건)은 트래픽이 적은 새벽에는 심각하지만, 피크 시간(초당 1만 건)에는 무의미할 수 있습니다. 비율로 설정하면 트래픽 양에 관계없이 일관된 기준을 적용할 수 있습니다.

원칙 3: 모든 알림에 Runbook 링크 포함

- alert: DatabaseConnectionPoolExhausted
  expr: |
    hikaricp_connections_active / hikaricp_connections_max > 0.9
  for: 5m
  labels:
    severity: high
    team: backend
  annotations:
    summary: "DB 커넥션 풀이 90% 이상 사용 중입니다"
    runbook: "https://wiki.example.com/runbooks/db-connection-pool"
    dashboard: "https://grafana.example.com/d/db-connections"

알림이 울렸을 때 "이게 뭐지? 뭘 해야 하지?"라는 질문에 바로 답을 줘야 합니다. Runbook에는 다음을 포함합니다:

  • 이 알림이 의미하는 것
  • 확인해야 할 대시보드/로그
  • 단계별 대응 절차
  • 에스컬레이션 기준

원칙 4: 알림에 행동이 연결되어야 함

알림을 설정하기 전에 물어야 할 질문:

"이 알림이 울렸을 때, 누군가가 구체적으로 무엇을 해야 하는가?"

답이 없으면 알림이 아니라 대시보드에 표시해야 합니다.

질문 "예"이면 "아니오"이면
즉시 행동이 필요한가? 알림(Critical/High) 대시보드 또는 Warning
사람이 개입해야 해결되는가? 알림 자동화 또는 대시보드
이 정보 없이 장애를 놓칠 수 있는가? 알림 제거

5. 그룹핑, 억제, 음소거

알림 노이즈 제거 메커니즘
알림 노이즈 제거 메커니즘

Alertmanager는 알림 노이즈를 줄이기 위한 세 가지 메커니즘을 제공합니다.

그룹핑 (Grouping)

같은 종류의 알림을 하나로 묶어서 전달합니다.

서비스 A의 인스턴스가 10개이고 모두 같은 에러를 내면, 10건의 개별 알림 대신 1건의 그룹 알림을 받습니다.

route:
  group_by: ['alertname', 'service', 'namespace']
  group_wait: 30s       # 첫 알림 후 30초 대기 (같은 그룹 알림 수집)
  group_interval: 5m    # 그룹에 새 알림 추가 시 5분 간격으로 알림
  repeat_interval: 4h   # 해결 안 되면 4시간마다 반복
  • group_wait: 첫 알림 발생 후 추가 알림을 모으는 대기 시간
  • group_interval: 기존 그룹에 새 알림이 추가되었을 때 재알림 간격
  • repeat_interval: 변경 없이 지속될 때 반복 알림 간격

억제 (Inhibition)

상위 알림이 발생하면 하위 알림을 자동으로 숨깁니다.

inhibit_rules:
  # 클러스터 장애 시 개별 Pod 알림 억제
  - source_match:
      alertname: ClusterDown
    target_match:
      severity: warning
    equal: ['cluster']

  # 노드 장애 시 해당 노드의 Pod 알림 억제
  - source_match:
      alertname: NodeDown
    target_match_re:
      alertname: 'Pod.*'
    equal: ['node']

노드가 죽으면 그 위의 모든 Pod이 비정상 상태가 됩니다. 각 Pod에 대한 알림을 개별적으로 받으면 노이즈만 증가합니다. 노드 장애 알림만 받으면 충분합니다.

음소거 (Silence)

특정 시간 동안 알림을 일시 중단합니다. 계획된 유지보수 시 사용합니다.

# Alertmanager API로 Silence 생성
# 유지보수 기간: 2026-06-07 02:00 ~ 04:00 UTC
amtool silence add alertname=~".*" namespace="production" \
  --comment="Planned maintenance window" \
  --author="ops-team" \
  --duration="2h"

음소거는 임시 조치입니다. 영구적으로 알림을 끄려면 알림 규칙 자체를 재설계해야 합니다.

6. 에스컬레이션 정책 설계

에스컬레이션 정책은 "알림에 응답하지 않으면 누구에게 전달하는가"를 정의합니다.

기본 에스컬레이션 구조

단계 대상 시간 조건 알림 방식
Level 1 Primary On-call 즉시 Push 알림 + 전화
Level 2 Secondary On-call 5분 무응답 시 Push 알림 + 전화
Level 3 팀 리드/매니저 15분 무응답 시 Push 알림 + Slack DM
Level 4 전체 팀 30분 무응답 시 Slack 채널 @here

실무 시나리오: 주문 서비스 에스컬레이션

새벽 2시에 "결제 API 에러율 5% 초과 (Critical)" 알림이 발생합니다.

  1. 0분: Primary On-call(김 엔지니어)에게 PagerDuty 전화
  2. 5분: 응답 없음 → Secondary On-call(박 엔지니어)에게 전화
  3. 15분: 여전히 미응답 → 팀 리드에게 Slack DM + 전화
  4. 30분: 에스컬레이션 Level 4 → #incident 채널에 @here 호출

에스컬레이션 설계 시 고려사항

  • 시간대 인식: 글로벌 팀이면 해당 시간대의 On-call에게 먼저 라우팅
  • 서비스 소유권: 결제 알림은 결제팀에게, 인프라 알림은 플랫폼팀에게
  • 번아웃 방지: On-call 로테이션 주기를 1~2주로 설정, 연속 배정 금지
  • 응답 시간 현실성: "5분 이내 확인"이 새벽에도 가능한지 검토

7. 실무 알림 설계 예시

예시 1: 웹 서비스 기본 알림 세트

groups:
  - name: web-service-alerts
    rules:
      # 증상: 에러율 급증 (사용자 영향)
      - alert: HighErrorRate
        expr: |
          sum(rate(http_requests_total{status=~"5.."}[5m])) by (service)
          /
          sum(rate(http_requests_total[5m])) by (service) > 0.05
        for: 5m
        labels:
          severity: critical
        annotations:
          summary: "{{ $labels.service }} 에러율이 5%를 초과했습니다"
          runbook: "https://wiki.example.com/runbooks/high-error-rate"

      # 증상: 응답 시간 저하 (사용자 경험)
      - alert: HighLatencyP99
        expr: |
          histogram_quantile(0.99,
            sum(rate(http_request_duration_seconds_bucket[5m])) by (le, service)
          ) > 2
        for: 10m
        labels:
          severity: high
        annotations:
          summary: "{{ $labels.service }} p99 응답시간이 2초를 초과했습니다 (10분 지속)"
          runbook: "https://wiki.example.com/runbooks/high-latency"

      # 예측: 디스크 풀 예상 (원인 기반이지만 예측 가능)
      - alert: DiskWillFillIn24h
        expr: |
          predict_linear(node_filesystem_avail_bytes{mountpoint="/"}[6h], 24*3600) < 0
        for: 30m
        labels:
          severity: warning
        annotations:
          summary: "{{ $labels.instance }} 디스크가 24시간 내 가득 찰 것으로 예측됩니다"
          runbook: "https://wiki.example.com/runbooks/disk-full"

      # 가용성: 서비스 프로브 실패
      - alert: ServiceDown
        expr: up{job="web-service"} == 0
        for: 2m
        labels:
          severity: critical
        annotations:
          summary: "{{ $labels.instance }}가 응답하지 않습니다"
          runbook: "https://wiki.example.com/runbooks/service-down"

예시 2: SLO 기반 알림 (Burn Rate)

단순 임계값 대신 SLO(Service Level Objective) 기반으로 알림을 설계하면 "얼마나 빠르게 에러 예산을 소진하고 있는가"를 기준으로 판단합니다.

SLO가 "월간 가용성 99.9%"라면, 월 에러 예산은 약 43분입니다.

# Burn Rate 알림: 현재 속도로 에러 예산을 얼마나 빨리 소진하는가
groups:
  - name: slo-burn-rate
    rules:
      # 14.4x burn rate (1시간 내 에러 예산 소진 속도)
      - alert: SLOBurnRateCritical
        expr: |
          (
            sum(rate(http_requests_total{status=~"5.."}[5m]))
            /
            sum(rate(http_requests_total[5m]))
          ) > (14.4 * 0.001)
        for: 2m
        labels:
          severity: critical
        annotations:
          summary: "에러 예산이 1시간 내 소진될 속도로 에러 발생 중"

      # 6x burn rate (6시간 내 에러 예산 소진 속도)
      - alert: SLOBurnRateHigh
        expr: |
          (
            sum(rate(http_requests_total{status=~"5.."}[30m]))
            /
            sum(rate(http_requests_total[30m]))
          ) > (6 * 0.001)
        for: 15m
        labels:
          severity: high
        annotations:
          summary: "에러 예산이 6시간 내 소진될 속도로 에러 발생 중"

      # 1x burn rate (30일 내 에러 예산 소진 — 서서히 악화)
      - alert: SLOBurnRateWarning
        expr: |
          (
            sum(rate(http_requests_total{status=~"5.."}[6h]))
            /
            sum(rate(http_requests_total[6h]))
          ) > (1 * 0.001)
        for: 3h
        labels:
          severity: warning
        annotations:
          summary: "에러 예산이 정상 속도로 소진 중 — 추세 확인 필요"

Burn Rate 기반 알림의 장점:

  • 짧은 시간에 많은 에러 → Critical (빠른 대응)
  • 긴 시간에 걸쳐 서서히 악화 → Warning (추세 모니터링)
  • 에러 예산이 충분하면 → 알림 없음 (불필요한 노이즈 제거)

8. 알림 리뷰 프로세스

알림은 한 번 설정하고 방치하면 시간이 지남에 따라 노이즈가 쌓입니다. 정기적인 리뷰가 필요합니다.

주간 알림 리뷰

매주 On-call 핸드오프 시 다음을 확인합니다:

확인 항목 질문 조치
총 알림 건수 이번 주 알림이 몇 건이었는가? 50건 초과 시 노이즈 분석
대응 비율 실제 조치가 필요했던 알림 비율은? 50% 미만이면 규칙 재설계
반복 알림 같은 알림이 반복 발생하는가? 근본 원인 해결 또는 임계값 조정
미응답 알림 무시된 알림이 있는가? 제거하거나 심각도 변경
놓친 장애 알림 없이 발견된 장애가 있는가? 새 알림 규칙 추가

월간 알림 건전성 지표

Signal-to-Noise Ratio = (대응 필요 알림 수) / (전체 알림 수) × 100%

목표: 80% 이상
위험: 50% 미만이면 팀이 알림을 무시하기 시작할 가능성이 높음

알림 생애주기 관리

단계 활동
생성 알림 규칙 작성 + Runbook 작성 + 담당 팀 지정
운영 발생 빈도, 대응률, MTTR 추적
튜닝 임계값 조정, for 값 변경, 그룹핑 개선
폐기 대응률 0%, 서비스 변경으로 무의미해진 알림 제거
주의
알림을 제거할 때는 "이 알림 없이도 문제를 감지할 수 있는가"를 반드시 확인합니다. 노이즈라고 무조건 삭제하면 감시 사각지대가 생길 수 있습니다. 증상 기반 알림으로 대체 가능한지 먼저 확인한 후 제거합니다.

9. 도구별 알림 설정 비교

기능 Prometheus + Alertmanager CloudWatch Alarms Datadog Monitors
알림 조건 PromQL (강력한 표현력) 단순 임계값, Math Expression 메트릭 쿼리 + 복합 조건
그룹핑 group_by 지원 미지원 (개별 알람) 멀티 알림 그룹
억제 inhibit_rules 미지원 다운타임 스케줄
라우팅 라벨 기반 계층적 라우팅 SNS Topic Team/Service 기반
Burn Rate 직접 구현 (PromQL) 미지원 SLO 모니터링 기능 내장
비용 오픈소스 (인프라 비용만) 알람 수 × 평가 비용 라이선스 비용
에스컬레이션 외부 연동 필요 (PagerDuty) 미지원 에스컬레이션 체인

CloudWatch Alarm 설정 예시

{
  "AlarmName": "HighErrorRate-OrderService",
  "MetricName": "5XXError",
  "Namespace": "AWS/ApplicationELB",
  "Statistic": "Sum",
  "Period": 300,
  "EvaluationPeriods": 3,
  "Threshold": 50,
  "ComparisonOperator": "GreaterThanThreshold",
  "AlarmActions": ["arn:aws:sns:ap-northeast-2:123456789:critical-alerts"],
  "TreatMissingData": "notBreaching"
}

CloudWatch는 EvaluationPeriodsfor 절과 유사한 효과를 줍니다. 위 설정은 "5분 간격으로 3회 연속(15분) 임계값을 넘으면 알림"입니다.

10. 보안 고려사항

Security Note
알림 시스템은 인프라 상태 정보를 외부 채널(Slack, PagerDuty, 이메일)로 전송합니다. 알림 메시지에 민감한 인프라 정보가 포함되지 않도록 주의해야 합니다.
위험 예시 대응
알림에 내부 IP/호스트명 노출 "10.0.1.45에서 DB 연결 실패" 서비스명으로 대체
알림에 사용자 정보 포함 "user_id: 12345의 결제 실패" 집계 수치만 알림, 상세는 로그
Webhook URL 유출 Slack Webhook URL이 코드에 노출 Secret Manager로 관리
알림 채널 접근 제어 모든 직원이 Critical 알림 채널 접근 역할 기반 채널 분리
Alertmanager API 미인증 외부에서 Silence 생성 가능 네트워크 격리 + 인증 적용

11. 비용/운영 고려사항

항목 비용 발생 요인 최적화 방향
CloudWatch Alarm 알람 수 × 평가 빈도 불필요한 알람 정리, 복합 알람 사용
PagerDuty 사용자 수 기반 라이선스 On-call 인원만 라이선스 부여
Datadog Monitors 모니터 수 무제한이나 알림 채널 비용 중복 모니터 통합
팀 비용 (가장 큼) 오탐 대응에 소요되는 엔지니어 시간 Signal-to-Noise Ratio 80% 이상 유지

알림 비용에서 가장 큰 부분은 도구 비용이 아니라 엔지니어의 시간입니다. 오탐 1건을 확인하는 데 5분이 걸린다면, 하루 30건의 오탐은 2.5시간의 생산성 손실입니다.

12. 자주 하는 실수

1. 모든 메트릭에 알림을 설정하는 것

"일단 알림을 걸어놓자"는 접근은 노이즈를 만듭니다. 알림을 추가하기 전에 "이 알림이 울리면 내가 뭘 할 것인가"를 먼저 정의합니다.

2. 임계값을 감으로 설정하는 것

"CPU 80%면 위험하지 않을까?"가 아니라, 과거 데이터를 분석하여 "서비스 영향이 시작되는 지점"을 찾아야 합니다. p99 응답 시간이 SLO를 초과하기 시작하는 CPU 수준이 실제 임계값입니다.

3. 알림을 끄는 것으로 문제를 해결하는 것

"이 알림 시끄러우니까 꺼버리자"는 근본 원인을 외면하는 것입니다. 알림이 시끄러우면 두 가지 중 하나입니다: - 임계값이 부적절하다 → 조정 - 실제 문제가 반복된다 → 근본 원인을 해결

4. 알림 Runbook을 작성하지 않는 것

알림만 있고 Runbook이 없으면 새로운 On-call 엔지니어가 "이게 뭔지" 파악하는 데 시간을 낭비합니다. 모든 알림에는 "이 알림이 울리면 이것을 확인하고 이렇게 조치하라"는 문서가 필요합니다.

5. 사후 알림만 설정하는 것

"디스크 100% 도달" 알림은 이미 서비스가 중단된 후입니다. predict_linear()이나 추세 기반 알림으로 문제가 발생하기 전에 감지해야 합니다.

13. 정리

  • 알림 피로는 "알림이 많아서" 생기는 것이 아니라 "의미 없는 알림이 많아서" 생깁니다. 모든 알림에 구체적인 행동이 연결되어야 합니다.
  • 증상 기반 알림이 원인 기반 알림보다 커버리지가 높고 오탐이 적습니다. 원인은 대시보드와 Runbook에서 확인합니다.
  • 심각도를 명확히 분류하고, 각 레벨에 맞는 알림 채널과 에스컬레이션 정책을 설계합니다. Critical은 전화, Warning은 Slack이 적합합니다.
  • for 절, 비율 기반 임계값, 그룹핑, 억제를 활용하여 노이즈를 구조적으로 줄입니다.
  • 주간/월간 알림 리뷰를 통해 Signal-to-Noise Ratio를 80% 이상으로 유지합니다. 알림은 설정 후 방치하면 반드시 노이즈가 쌓입니다.

참고 문서

반응형