Home Metrics Overview
Post
Cancel

Metrics Overview

Metrics

목차


Metrics의 역할

Metrics는 시스템 상태를 숫자로 표현한 시계열 데이터다. 로그는 개별 사건의 상세 정보, 메트릭은 시스템 전체의 집계 통계를 제공한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
Logs (개별 사건):
- 특정 요청이 언제 실패했는가?
- 어떤 에러가 발생했는가?

Metrics (집계 통계):
- 시간대별 에러율은?
- 평균 응답 시간은?
- CPU 사용량은?
- 초당 요청 수는?

Traces (요청 흐름):
- 이 요청이 어느 서비스를 거쳤는가?
- 각 단계에서 시간은 얼마나 걸렸는가?

Metrics의 필요성

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
실시간 모니터링:
- 접속자 100명 vs 10만 명 → 즉시 파악
- CPU 50% vs 95% → 임계값으로 알림

성능 분석:
- 이번 주 vs 지난 주 비교
- 배포 전후 성능 변화

용량 계획:
- 일일 최대 요청 수: 1M
- 필요 서버 수: ?
- 진행 추세로 언제까지 충분? (capacity planning)

비용 최적화:
- 메모리 사용: 50% → 자동 스케일 다운 가능
- 비용 절감 기회 발굴

Metric Type

Metric의 종류

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Counter (계수기)
- 계속 증가하는 값 (절대 감소하지 않음)
- 예: 총 요청 수, 총 에러 수, 총 바이트 처리
- 연산: Rate = delta / time (초당 요청 수)

Gauge (게이지)
- 현재 값 (증감 가능)
- 예: 현재 메모리 사용, 활성 연결 수, CPU 사용률
- 특징: 순간값 (스냅샷)

Histogram (히스토그램)
- 값의 분포 (버킷으로 나눔)
- 예: 응답 시간 분포 (0-10ms, 10-50ms, 50-100ms...)
- 연산: 퍼센타일 (p50, p95, p99) 계산 가능

Summary (요약)
- 값의 통계 요약 (평균, 합, 개수)
- 예: 응답 시간의 평균, 합계, 개수

예시

1
2
3
4
5
6
7
8
9
10
11
12
13
14
Counter:
http_requests_total{method="GET", status="200"} 12345
→ GET 요청이 12345건 성공

Gauge:
memory_usage_bytes{instance="server1"} 2147483648
→ server1의 메모리 사용: 2GB

Histogram (내부적으로 여러 버킷):
http_request_duration_seconds_bucket{le="0.1"} 1000
http_request_duration_seconds_bucket{le="0.5"} 5000
http_request_duration_seconds_bucket{le="1.0"} 8000
→ 100ms 이하: 1000건, 500ms 이하: 5000건...
→ p50 ≈ 100ms, p95 ≈ 500ms 계산 가능

RED Method

“request rate, error rate, duration은 왜 기본 지표인가?”

RED Method (Rate, Errors, Duration)는 서비스의 건강성을 빠르게 판단하는 세 가지 핵심 지표다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Request Rate (처리량)
- 초당 얼마나 많은 요청을 처리하는가?
- 정상 범위: 1000 RPS
- 급감 → 문제 가능성
- 급증 → 부하 증가

Error Rate (에러율)
- 요청 중 몇 %가 실패하는가?
- 정상: 0.1% 이하
- 1% → 문제 (100개 중 1개 실패)
- 5% → 심각 (20개 중 1개 실패)

Duration (응답 시간)
- 평균 얼마나 걸리는가?
- 정상: 50-100ms
- 500ms → 느림
- 5초 → 타임아웃 가능

RED 메트릭 수집

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
32
33
34
35
36
37
38
39
40
from prometheus_client import Counter, Histogram
import time

# Request Rate
request_total = Counter(
    'http_requests_total',
    'Total HTTP requests',
    ['method', 'endpoint', 'status']
)

# Duration
request_duration = Histogram(
    'http_request_duration_seconds',
    'HTTP request duration',
    ['method', 'endpoint']
)

# 미들웨어
def middleware(app):
    def handle_request(environ, start_response):
        start_time = time.time()
        method = environ['REQUEST_METHOD']
        path = environ['PATH_INFO']
        
        try:
            # 요청 처리
            response = app(environ, start_response)
            status = 200
        except Exception as e:
            status = 500
            response = str(e)
        
        # 메트릭 기록
        duration = time.time() - start_time
        request_total.labels(method=method, endpoint=path, status=status).inc()
        request_duration.labels(method=method, endpoint=path).observe(duration)
        
        return response
    
    return handle_request

RED 대시보드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
대시보드 항목:

[Rate]
- Total RPS
- RPS by endpoint
- RPS trend (1h, 24h)

[Errors]
- Error rate (%)
- Errors by status code (4xx, 5xx)
- Error trend

[Duration]
- p50 latency
- p95 latency
- p99 latency
- Duration by endpoint

USE Method

USE Method란?

USE Method (Utilization, Saturation, Errors)는 인프라/자원의 건강성을 판단하는 세 가지 지표다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Utilization (사용률)
- CPU 사용률
- 메모리 사용률
- 디스크 사용률
- 네트워크 대역폭 사용률

Saturation (포화도)
- 처리 대기열 길이
- CPU 대기 시간
- I/O 대기 시간

Errors (에러)
- 디스크 읽기 에러
- 네트워크 패킷 손실
- 메모리 할당 실패

USE vs RED

1
2
3
4
5
6
7
8
9
서비스 모니터링 → RED
┌─ Request Rate
├─ Error Rate
└─ Duration

인프라 모니터링 → USE
┌─ Utilization (CPU, Memory, Disk)
├─ Saturation (Queue, Wait time)
└─ Errors (System errors)

USE 메트릭 수집

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# CPU
cpu_usage_percent: 45%

# Memory
memory_used_bytes: 4GB / 8GB = 50%

# Disk
disk_used_bytes: 450GB / 500GB = 90%  # ⚠️ 높음

# Network
network_bytes_in_rate: 100 Mbps / 1000 Mbps = 10%

# Saturation
cpu_queue_length: 2  # CPU 대기 프로세스
disk_io_wait_percent: 5%  # I/O 대기

SLI와 SLO

“SLI와 SLO는 무엇이 다른가?”

SLI (Service Level Indicator)는 실제 서비스 품질을 측정하는 지표, SLO (Service Level Objective)는 목표 수준을 정의하는 정책다.

1
2
3
4
5
6
7
8
9
10
11
12
13
SLI (Service Level Indicator): 측정 지표
- "99.9%의 요청이 200ms 이내에 응답했다"
- "99.99%의 시간 서비스가 가용했다"
- 실제 데이터

SLO (Service Level Objective): 목표값
- "99.9% 가용성을 유지하겠다"
- "평균 응답 시간 100ms 이하를 목표로 한다"
- 약속, 목표

SLA (Service Level Agreement): 계약
- "99.9% 가용성 보장, 위반 시 환불"
- 사업 계약

SLI/SLO 정의 예시

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
서비스: "주문 처리 API"

SLO (목표):
- 가용성: 99.9% (월 43분 다운타임 허용)
- 응답 시간: p99 < 500ms
- 에러율: < 0.1%

SLI (측정):
- 가용성 = (성공한 요청) / (전체 요청)
- 응답 시간 = 응답 시간 히스토그램의 p99
- 에러율 = (5xx 상태 코드 요청) / (전체 요청)

현재 상태:
- 가용성: 99.95% ✓ (목표 초과)
- 응답 시간 p99: 250ms ✓ (목표 달성)
- 에러율: 0.05% ✓ (목표 달성)

Error Budget

SLO와 실제의 차이를 “Error Budget”이라 하며, 배포 전에 얼마나 실패할 수 있는지 정량화한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
SLO: 99.9% (월 1000분 중 실패 허용: 1000 * (1 - 0.999) = 1분)

현재 누적:
- 1주: 0분 사용 (100% 달성)
- 2주: 5초 사용 (계획 초과 배포로 다운)
- 3주: 30초 사용 (긴급 패치로 다운)

남은 Error Budget:
1분 - 35초 = 25초 (이 달 남은 실패 허용 시간)

의사결정:
- 남은 budget이 충분 → 자신감 있게 배포
- budget이 부족 → 신중하게 배포 (이미 초과 위험)
- budget 없음 → 배포 금지, 안정성 개선 우선

Cardinality

“cardinality가 높으면 왜 문제가 되는가?”

Cardinality는 Label 조합의 개수이며, 높을수록 메모리/비용 증가한다.

1
2
3
4
5
6
7
8
9
10
11
12
낮은 Cardinality:
http_requests_total{method="GET", status="200"}
http_requests_total{method="GET", status="500"}
http_requests_total{method="POST", status="200"}
→ 3개 조합

높은 Cardinality (위험):
http_requests_total{method="GET", status="200", user_id="123"}
http_requests_total{method="GET", status="200", user_id="456"}
http_requests_total{method="GET", status="200", user_id="789"}
... (사용자 수만큼)
→ 사용자 수 만큼 증가!

Cardinality 문제

1
2
3
4
5
6
7
8
9
사용자별 메트릭:
- 사용자 100명 → 100개 시계열
- 사용자 1만 명 → 1만 개 시계열
- 사용자 100만 명 → 100만 개 시계열 ← 메모리 부족!

비용:
- 메트릭 저장소 비용 (시계열 개수 기준)
- 쿼리 성능 저하
- 캐시 비효율

높은 Cardinality 피하기

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# ❌ 나쁜 예 (user_id가 Cardinality 폭발)
from prometheus_client import Counter

request_by_user = Counter(
    'requests_by_user',
    'Requests per user',
    ['user_id']  # 사용자가 많으면 문제!
)

# ✓ 좋은 예 (고정된 Label만 사용)
request_total = Counter(
    'http_requests_total',
    'Total HTTP requests',
    ['method', 'status']  # 고정된 값만 사용
)

# ✓ 별도의 조회 방식 사용
user_request_count = Counter(
    'user_requests_total',
    'Total requests by user',
    ['tier']  # gold, silver, bronze 같은 카테고리만
)

Label 설계 원칙

1
2
3
4
5
6
7
8
9
10
11
12
✓ 사용할 수 있는 Label:
- method: GET, POST, PUT, DELETE (4-10개)
- status: 200, 400, 500 (10개 이내)
- endpoint: /api/users, /api/orders (수십 개)
- tier: gold, silver, bronze (수개)
- region: us-east, eu-west (수개)

❌ 사용하면 안 되는 Label:
- user_id (수백만 개)
- request_id (무한)
- timestamp (무한)
- trace_id (무한)

Metric 설계

좋은 Metric 설계

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
1. 비즈니스 지표
   - 주문 수 (매분)
   - 매출 (매시간)
   - 사용자 가입 (매일)

2. 기술 지표 (RED)
   - Request rate
   - Error rate
   - Duration (p50, p95, p99)

3. 자원 지표 (USE)
   - CPU, Memory, Disk 사용률
   - Network 사용
   - I/O 대기

4. 도메인 특화 지표
   - 데이터베이스: 쿼리 시간, slow query 수
   - 캐시: hit rate, miss rate
   - 메시지 큐: 큐 깊이, consumer lag

Naming 규칙

1
2
3
4
5
6
7
8
9
10
11
12
<namespace>_<subsystem>_<name>_<unit>

예시:
http_request_duration_seconds
├─ http: namespace
├─ request: subsystem
├─ duration: name
└─ seconds: unit

규칙:
- 소문자, 언더스코어로 구분
- 단위는 suffix로 (seconds, bytes, percent)

정리

개념설명
Counter계속 증가하는 값 (총 요청 수)
Gauge현재값 (메모리 사용, CPU)
Histogram값의 분포 (응답 시간 분포)
REDRequest Rate, Error Rate, Duration
USEUtilization, Saturation, Errors
SLI실제 서비스 품질 측정 지표
SLO목표 서비스 수준
CardinalityLabel 조합 개수 (높으면 문제)

This post is licensed under CC BY 4.0 by the author.