Observability/Observability

EP03 [시리즈 1: Observability의 개념과 방향성] #3 메트릭 유형과 시계열 데이터의 기초 개념

ygtoken 2025. 3. 19. 13:21
728x90

 

이번 글에서는 프로메테우스와 그라파나를 활용한 Observability 구성 시리즈의 세 번째 포스트로, 메트릭 유형에 대한 심층적인 이해와 시계열 데이터의 기초 개념에 대해 알아보겠습니다.


📌 시계열 데이터의 이해

시계열 데이터는 시간의 흐름에 따라 수집된 데이터 포인트들의 집합입니다. Observability 영역에서 메트릭은 대부분 시계열 형태로 저장되고 분석됩니다.

✅ 시계열 데이터의 특징

  • 타임스탬프: 각 데이터 포인트는 정확한 발생 시간과 함께 기록됩니다.
  • 순차적 정렬: 시간 순서대로 정렬되어 추세와 패턴을 볼 수 있습니다.
  • 규칙적 간격: 일반적으로 일정한 간격(예: 10초, 1분)으로 수집됩니다.
  • 변화 추적: 시간에 따른 값의 변화를 추적하여 동향을 파악할 수 있습니다.

시계열 데이터 구조

✅ 시계열 데이터베이스

시계열 데이터는 일반적인 관계형 데이터베이스(RDBMS)와는 다른 특성을 가지고 있어, 이를 효율적으로 저장하고 관리하기 위한 특수한 데이터베이스가 필요합니다.

▶️ 시계열 데이터베이스의 특징:

  • 높은 쓰기 처리량: 초당 수천, 수만 개의 데이터 포인트를 기록할 수 있습니다.
  • 효율적인 압축: 시간에 따른 변화 패턴을 활용하여 데이터를 효율적으로 압축합니다.
  • 시간 기반 쿼리 최적화: 특정 시간 범위에 대한 쿼리가 매우 빠릅니다.
  • 다운샘플링: 오래된 데이터는 낮은 해상도로 압축하여 저장 공간을 절약합니다.

▶️ 주요 시계열 데이터베이스:

  • 프로메테우스(Prometheus): 모니터링 중심의 시계열 데이터베이스
  • 인플럭스DB(InfluxDB): 고성능 시계열 데이터베이스
  • 타이머스케일DB(TimescaleDB): PostgreSQL 확장 기반 시계열 데이터베이스
  • 그라파나 로키(Grafana Loki): 로그 중심 시계열 데이터베이스
  • 오픈TSDB(OpenTSDB): HBase 기반 분산 시계열 데이터베이스

📌 프로메테우스의 데이터 모델

프로메테우스는 강력한 시계열 데이터베이스를 내장하고 있으며, 고유한 데이터 모델을 가지고 있습니다.

✅ 프로메테우스 데이터 모델의 구성요소

▶️ 메트릭 이름과 레이블:

프로메테우스의 시계열 데이터는 메트릭 이름과 키-값 쌍의 레이블 집합으로 식별됩니다.

<metric_name>{<label_name>=<label_value>, ...}

예시:

http_requests_total{method="GET", status="200", path="/api/users"}
  • 메트릭 이름: 측정 중인 항목을 설명합니다(예: http_requests_total)
  • 레이블: 메트릭의 차원을 식별합니다(예: method="GET")

▶️ 샘플:

시계열의 실제 데이터 포인트는 다음 요소로 구성됩니다:

  • 부동 소수점 값
  • 밀리초 정밀도의 타임스탬프

프로메테우스 데이터 모델

 

✅ 레이블과 차원

프로메테우스에서 레이블은 시계열 데이터에 차원을 추가하는 매우 중요한 개념입니다.

▶️ 레이블의 중요성:

  • 다차원 데이터 모델: 동일한 메트릭에 대해 다양한 차원의 데이터를 구분할 수 있습니다.
  • 유연한 쿼리: 레이블을 기반으로 필터링, 집계, 조인 등의 연산을 수행할 수 있습니다.
  • 동적 대상 추적: 레이블을 통해 동적으로 변화하는 환경(예: 쿠버네티스 포드)을 효과적으로 추적할 수 있습니다.

▶️ 레이블 명명 규칙:

  • 레이블 이름은 문자, 숫자, 언더스코어(_)로 구성됩니다.
  • 레이블 이름은 문자나 언더스코어로 시작해야 합니다.
  • 레이블 값은 어떤 유니코드 문자열이든 가능합니다.

▶️ 효과적인 레이블 사용 사례:

  • 인스턴스 식별: instance="web-server-01"
  • 서비스 구분: service="payment-api"
  • 환경 구분: environment="production"
  • 지역 정보: region="us-west"
  • 팀 소유권: team="platform"
# 프로메테우스 대상 설정 예시 (prometheus.yml)
scrape_configs:
  - job_name: 'api_servers'
    static_configs:
      - targets: ['api-server-01:9090', 'api-server-02:9090']
        labels:
          environment: production
          service: user-api
          tier: frontend
      - targets: ['payment-service-01:9090', 'payment-service-02:9090']
        labels:
          environment: production
          service: payment-api
          tier: backend

📌 시계열 데이터 쿼리 기초

프로메테우스의 강력한 기능 중 하나는 PromQL(Prometheus Query Language)이라는 쿼리 언어입니다. PromQL을 사용하면 시계열 데이터를 효과적으로 검색하고 조작할 수 있습니다.

✅ 기본 쿼리 구조

▶️ 단순 쿼리:

특정 메트릭의 모든 시계열을 검색합니다.

http_requests_total

▶️ 레이블 필터링:

특정 레이블이 있는 시계열만 필터링합니다.

# method가 "GET"인 HTTP 요청만 선택
http_requests_total{method="GET"}

# status가 "5xx"로 시작하는 HTTP 요청만 선택
http_requests_total{status=~"5.."}

# env가 "dev"가 아닌 HTTP 요청만 선택
http_requests_total{env!="dev"}

▶️ 범위 벡터 선택:

특정 시간 범위의 데이터를 선택합니다.

# 지난 5분간의 HTTP 요청 데이터
http_requests_total[5m]

✅ 연산자와 함수

PromQL은 시계열 데이터를 조작하기 위한 다양한 연산자와 함수를 제공합니다.

▶️ 산술 연산자:

# 각 시계열 값에 2를 곱함
http_requests_total * 2

# 두 메트릭의 비율 계산
http_requests_total / http_requests_successful

▶️ 집계 함수:

# method 레이블별로 HTTP 요청 수 합계
sum(http_requests_total) by (method)

# status 레이블별 평균 요청 지연 시간
avg(request_duration_seconds) by (status)

# 모든 인스턴스의 최대 CPU 사용률
max(cpu_usage_percent)

▶️ 시간 기반 함수:

# 5분간의 초당 평균 요청 수
rate(http_requests_total[5m])

# 지난 1시간 동안의 요청 증가량
increase(http_requests_total[1h])

PromQL 예제와 시각화

📌 메트릭 설계 모범 사례

효과적인 시스템 관측을 위해서는 메트릭을 적절하게 설계하는 것이 중요합니다. 다음은 메트릭 설계에 관한 몇 가지 모범 사례입니다.

✅ 메트릭 명명 규칙

일관된 메트릭 이름 지정은 가독성과 유지보수성을 높이는 데 중요합니다.

▶️ 메트릭 이름 구조:

  • 단위 포함: 메트릭 이름에 단위를 포함시키면 이해하기 쉽습니다 (예: http_request_duration_seconds, memory_usage_bytes).
  • 카멜케이스 또는 스네이크케이스: 일관된 스타일을 유지하세요 (예: httpRequestTotal 또는 http_request_total).
  • 접두사 사용: 도메인이나 애플리케이션별로 접두사를 사용하여 구분합니다 (예: app_http_requests_total, system_memory_usage_bytes).

▶️ 명확한 이름 지정:

  • 무엇을 측정하는지 명확히: count, total, bytes, errors, duration_seconds 등의 접미사를 사용합니다.
  • 총계/카운터에는 _total 사용: 예를 들어, http_requests_total는 총 HTTP 요청 수를 나타냅니다.
  • 상태보다는 동작에 초점: is_alive 보다는 last_heartbeat_timestamp_seconds와 같이 직접 측정 가능한 값을 사용합니다.
# 프로메테우스 메트릭 정의 예시 (Go 코드)
# 좋은 예:
http_requests_total{method="GET", status="200", path="/api/users"}
http_request_duration_seconds{method="POST", status="201", path="/api/orders"}
memory_usage_bytes{instance="web-01", area="heap"}

# 나쁜 예:
api_metric_1 # 무엇을 측정하는지 불분명
get_users # 메트릭 유형과 단위가 불명확
is_database_connection_ok # 이진 상태보다는 마지막 연결 시간 등을 측정하는 것이 좋음

✅ 적절한 카디널리티 관리

카디널리티(고유한 시계열의 수)가 너무 높으면 성능 문제가 발생할 수 있습니다.

▶️ 카디널리티 관리 방법:

  • 필요한 레이블만 사용: 모든 가능한 정보를 레이블에 포함하려는 유혹을 피하세요.
  • 무한정 증가하는 레이블 피하기: 사용자 ID, 요청 ID, 타임스탬프 등은 레이블로 사용하지 마세요.
  • 레이블 값 제한: 가능한 경우 레이블 값의 수를 제한하세요(예: 모든 URL 경로 대신 주요 API 경로로 그룹화).
# 높은 카디널리티 방지 예시
# 나쁜 예 (무한정 증가하는 카디널리티):
http_requests_total{path="/user/12345", user_id="12345", request_id="abcd-1234-5678"}

# 좋은 예 (제한된 카디널리티):
http_requests_total{path="/user/:id", method="GET", status_code="200"}

✅ 목적에 맞는 메트릭 유형 선택

각 메트릭 유형은 특정 사용 사례에 적합합니다.

▶️ 유형 선택 가이드:

  • 카운터: 이벤트 발생 횟수나 변화량 측정 (예: 요청 수, 오류 수)
  • 게이지: 현재 상태나 값 측정 (예: 메모리 사용량, 활성 연결 수)
  • 히스토그램: 값의 분포와 백분위수 계산 (예: 응답 시간, 요청 크기)
  • 서머리: 클라이언트 측에서의 정확한 분위수 계산이 필요한 경우

매트릭 설계 모범 사례

📌 메트릭 수집과 저장

메트릭 데이터를 효과적으로 수집하고 저장하는 것은 성공적인 모니터링 시스템 구축의 핵심입니다.

✅ 프로메테우스의 메트릭 수집 방식

프로메테우스는 주로 풀(Pull) 기반 메트릭 수집 모델을 사용합니다.

▶️ 풀 모델의 특징:

  • 프로메테우스가 대상 시스템에서 메트릭을 가져옴: 설정된 주기(일반적으로 15초)마다 HTTP 엔드포인트에 요청하여 메트릭을 수집합니다.
  • 서비스 검색: 프로메테우스는 정적 구성, 파일, DNS, 쿠버네티스 등 다양한 방법으로 모니터링 대상을 발견할 수 있습니다.
  • 필터링과 재레이블링: 수집 전후에 메트릭 데이터를 변환하고 필터링할 수 있습니다.

▶️ 프로메테우스 구성 예시:

# prometheus.yml
global:
  scrape_interval: 15s  # 기본 스크래핑 주기
  evaluation_interval: 15s  # 규칙 평가 주기

# 스크래핑 대상 설정
scrape_configs:
  - job_name: 'api_servers'  # 작업(Job) 이름
    scrape_interval: 5s  # 이 작업에 대한 개별 스크래핑 주기 (전역 설정 재정의)
    metrics_path: '/metrics'  # 메트릭 엔드포인트 경로
    static_configs:  # 정적 대상 구성
      - targets: ['api-server-01:9090', 'api-server-02:9090']
        labels:  # 모든 메트릭에 추가될 레이블
          environment: 'production'
          tier: 'frontend'
    
  - job_name: 'kubernetes-nodes'
    kubernetes_sd_configs:  # 쿠버네티스 서비스 검색
      - role: node
        api_server: 'https://kubernetes.default.svc:443'
        tls_config:
          ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
        bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token
    
    # 레이블 재구성 (relabeling)
    relabel_configs:
      - source_labels: [__meta_kubernetes_node_name]
        regex: (.+)
        target_label: node_name
        replacement: $1

✅ 메트릭 저장 및 보존

프로메테우스는 메트릭 데이터를 로컬 시계열 데이터베이스에 저장합니다.

▶️ 데이터 저장 특성:

  • 시계열 식별자(fingerprint): 각 고유한 메트릭 이름과 레이블 조합에 대해 해시 값을 생성합니다.
  • 샘플 압축: 시간에 따른 변화 패턴을 활용하여 데이터를 효율적으로 압축합니다(일반적으로 1.3~2바이트/샘플).
  • 스토리지 계층: 메모리, WAL(Write-Ahead Log), 블록 저장소 등 여러 계층으로 구성됩니다.

▶️ 데이터 보존 정책:

  • 기본 보존 기간: 프로메테우스는 기본적으로 15일간 데이터를 보존합니다.
  • 스토리지 크기 제한: 디스크 공간에 따라 보존 기간을 조정할 수 있습니다.
  • 장기 보관: 장기간 데이터 보관을 위해 Thanos, Cortex와 같은 솔루션을 활용할 수 있습니다.

▶️ 보존 정책 설정 예시:

# prometheus.yml
storage:
  tsdb:
    path: /prometheus  # 데이터 저장 경로
    retention.time: 30d  # 데이터 보존 기간
    retention.size: 10GB  # 최대 스토리지 크기
    wal:
      replay-concurrency: 6  # WAL 리플레이 동시성 수준

📌 결론

이번 글에서 다룬 핵심 내용을 요약하면 다음과 같습니다:

  • 시계열 데이터의 이해
    • 시간에 따라 수집된 데이터 포인트의 집합으로 타임스탬프를 포함
    • 특수한 시계열 데이터베이스를 통해 효율적으로 관리
  • 프로메테우스 데이터 모델
    • 메트릭 이름과 레이블 조합으로 고유한 시계열 식별
    • 레이블을 통한 다차원 데이터 모델 지원
  • 메트릭 유형과 활용
    • 카운터: 증가만 하는 값 (요청 수, 오류 수)
    • 게이지: 증감 가능한 스냅샷 값 (CPU 사용률, 메모리)
    • 히스토그램/서머리: 값의 분포 측정 (응답 시간, 처리량)
  • 효과적인 메트릭 설계
    • 일관된 명명 규칙 적용
    • 카디널리티 관리를 통한 성능 최적화
    • 목적에 맞는 메트릭 유형 선택
  • 메트릭 수집과 저장
    • 풀(Pull) 기반의 메트릭 수집 방식
    • 효율적인 압축과 보존 정책 설정

적절한 시계열 데이터 관리와 쿼리 기술을 익히면 시스템의 동작을 더 깊이 이해하고, 문제 발생 시 신속하게 대응할 수 있는 기반을 마련할 수 있습니다.

728x90