🤖

본 콘텐츠의 이미지 및 내용은 AI로 생성되었습니다.

⚠️

본 콘텐츠의 이미지 및 내용을 무단으로 복제, 배포, 수정하여 사용할 경우 저작권법에 의해 법적 제재를 받을 수 있습니다.

이미지 로딩 중...

Prometheus 트러블슈팅 완벽 가이드 - 슬라이드 1/13
A

AI Generated

2025. 11. 4. · 12 Views

Prometheus 트러블슈팅 완벽 가이드

Prometheus 모니터링 시스템에서 자주 발생하는 문제들과 해결 방법을 다룹니다. 메트릭 수집 실패, 쿼리 성능 문제, 저장소 관리 등 실무에서 겪는 이슈들을 코드로 해결합니다.


카테고리:Python
언어:Python
메인 태그:#Prometheus
서브 태그:
#Monitoring#Troubleshooting#Metrics#Performance

들어가며

이 글에서는 Prometheus 트러블슈팅 완벽 가이드에 대해 상세히 알아보겠습니다. 총 12가지 주요 개념을 다루며, 각각의 개념에 대한 설명과 실제 코드 예제를 함께 제공합니다.

목차

  1. 메트릭_수집_실패_디버깅
  2. 높은_카디널리티_문제_해결
  3. 쿼리_성능_최적화
  4. 디스크_공간_부족_모니터링
  5. 메트릭_만료_시간_설정
  6. 스크랩_타임아웃_조정
  7. 메트릭_이름_충돌_해결
  8. 레이트_계산_오류_수정
  9. 메모리_부족_문제_진단
  10. Alert_규칙_테스트
  11. 서비스_디스커버리_실패_처리
  12. 중복_메트릭_제거

1. 메트릭 수집 실패 디버깅

개요

Prometheus가 타겟에서 메트릭을 수집하지 못할 때 상태를 확인하고 재시도 로직을 구현하는 방법입니다.

코드 예제

from prometheus_client import Counter, Gauge
import requests

scrape_errors = Counter('scrape_errors_total', 'Total scrape errors')
target_up = Gauge('target_up', 'Target availability', ['target'])

def check_target(url):
    try:
        response = requests.get(f"{url}/metrics", timeout=5)
        target_up.labels(target=url).set(1)
        return response.text
    except Exception as e:
        scrape_errors.inc()
        target_up.labels(target=url).set(0)
        print(f"Scrape failed: {e}")

설명

타겟의 메트릭 엔드포인트를 호출하고 성공/실패 여부를 메트릭으로 기록합니다. 타임아웃과 예외 처리로 안정성을 확보합니다.


2. 높은 카디널리티 문제 해결

개요

레이블이 너무 많아 메모리 사용량이 증가하는 문제를 해결하기 위해 레이블을 제한하는 방법입니다.

코드 예제

from prometheus_client import Counter
import hashlib

request_counter = Counter('http_requests_total',
                         'HTTP requests',
                         ['method', 'status', 'endpoint_hash'])

def record_request(method, status, endpoint):
    # 엔드포인트를 해시로 변환하여 카디널리티 감소
    endpoint_hash = hashlib.md5(endpoint.encode()).hexdigest()[:8]
    request_counter.labels(
        method=method,
        status=status,
        endpoint_hash=endpoint_hash
    ).inc()

설명

URL 경로를 해시값으로 변환하여 무한히 증가하는 레이블 값을 제한합니다. 이를 통해 메모리 사용량을 크게 줄일 수 있습니다.


3. 쿼리 성능 최적화

개요

PromQL 쿼리가 느릴 때 시간 범위와 스텝을 조정하여 성능을 개선하는 방법입니다.

코드 예제

from prometheus_api_client import PrometheusConnect

prom = PrometheusConnect(url="http://localhost:9090")

# 비효율적인 쿼리
# result = prom.custom_query_range(
#     query="rate(http_requests_total[5m])",
#     start_time="2025-01-01T00:00:00Z",
#     end_time="2025-01-02T00:00:00Z",
#     step="1s"  # 너무 작은 스텝
# )

# 최적화된 쿼리
result = prom.custom_query_range(
    query="rate(http_requests_total[5m])",
    start_time="2025-01-01T00:00:00Z",
    end_time="2025-01-02T00:00:00Z",
    step="60s"  # 적절한 스텝
)

설명

쿼리의 스텝 크기를 적절히 조정하면 데이터 포인트 수가 줄어들어 쿼리 성능이 크게 향상됩니다. 1초에서 60초로 변경하면 60배 빨라집니다.


4. 디스크 공간 부족 모니터링

개요

Prometheus 저장소의 디스크 사용량을 모니터링하고 임계치를 초과하면 알림을 보내는 방법입니다.

코드 예제

from prometheus_client import Gauge
import shutil

disk_usage = Gauge('prometheus_disk_usage_bytes',
                   'Disk usage in bytes',
                   ['path'])
disk_usage_percent = Gauge('prometheus_disk_usage_percent',
                           'Disk usage percentage',
                           ['path'])

def monitor_disk(path='/var/lib/prometheus'):
    total, used, free = shutil.disk_usage(path)
    disk_usage.labels(path=path).set(used)
    disk_usage_percent.labels(path=path).set((used/total)*100)

    if (used/total) > 0.85:
        print(f"WARNING: Disk usage above 85% at {path}")

설명

디스크 사용량을 바이트와 퍼센트로 측정하여 메트릭으로 기록합니다. 85% 이상일 때 경고를 출력합니다.


5. 메트릭 만료 시간 설정

개요

오래된 시계열 데이터를 자동으로 삭제하여 저장 공간을 확보하는 retention 설정 방법입니다.

코드 예제

# prometheus.yml 설정
storage_config = """
global:
  scrape_interval: 15s
  evaluation_interval: 15s

storage:
  tsdb:
    retention.time: 15d
    retention.size: 50GB

scrape_configs:
  - job_name: 'my_app'
    static_configs:
      - targets: ['localhost:8000']
"""

# 설정 검증 함수
def validate_retention(retention_time, retention_size):
    assert retention_time.endswith('d') or retention_time.endswith('h')
    assert retention_size.endswith('GB') or retention_size.endswith('MB')
    print("Retention policy validated")

설명

데이터 보관 기간을 15일 또는 50GB로 제한하여 자동으로 오래된 데이터를 삭제합니다. 두 조건 중 먼저 도달하는 기준이 적용됩니다.


6. 스크랩 타임아웃 조정

개요

타겟 응답이 느릴 때 스크랩 타임아웃을 조정하여 수집 실패를 방지하는 방법입니다.

코드 예제

# prometheus.yml 설정
scrape_config = """
scrape_configs:
  - job_name: 'slow_service'
    scrape_interval: 30s
    scrape_timeout: 25s  # interval보다 작아야 함
    static_configs:
      - targets: ['slow-api:8080']
"""

def validate_scrape_config(interval, timeout):
    interval_sec = int(interval.rstrip('s'))
    timeout_sec = int(timeout.rstrip('s'))

    if timeout_sec >= interval_sec:
        raise ValueError("Timeout must be less than interval")
    print(f"Valid config: {timeout_sec}s timeout, {interval_sec}s interval")

설명

스크랩 타임아웃은 반드시 스크랩 간격보다 작아야 합니다. 느린 서비스의 경우 둘 다 늘려서 안정적으로 수집합니다.


7. 메트릭 이름 충돌 해결

개요

여러 서비스에서 같은 이름의 메트릭을 사용할 때 레이블로 구분하는 방법입니다.

코드 예제

from prometheus_client import Counter, CollectorRegistry

# 각 서비스마다 별도의 레지스트리 사용
registry_a = CollectorRegistry()
registry_b = CollectorRegistry()

requests_a = Counter('http_requests_total',
                     'Requests from service A',
                     ['service'],
                     registry=registry_a)
requests_a.labels(service='api-gateway').inc()

requests_b = Counter('http_requests_total',
                     'Requests from service B',
                     ['service'],
                     registry=registry_b)
requests_b.labels(service='user-service').inc()

설명

별도의 레지스트리를 사용하거나 service 레이블로 구분하여 메트릭 이름 충돌을 방지합니다. 각 서비스를 독립적으로 관리할 수 있습니다.


8. 레이트 계산 오류 수정

개요

rate() 함수 사용 시 시간 범위를 잘못 설정하여 부정확한 값이 나오는 문제를 해결하는 방법입니다.

코드 예제

# 잘못된 예: 시간 범위가 너무 짧음
# rate(http_requests_total[30s])  # scrape_interval이 15s일 때

# 올바른 예: 최소 2배 이상의 시간 범위 사용
correct_query = """
rate(http_requests_total[1m])  # scrape_interval이 15s일 때 적절
"""

def validate_rate_range(scrape_interval_sec, rate_range_sec):
    min_range = scrape_interval_sec * 2
    if rate_range_sec < min_range:
        raise ValueError(
            f"Rate range should be at least {min_range}s "
            f"(2x scrape interval)"
        )
    print("Rate range validated")

설명

rate() 함수의 시간 범위는 스크랩 간격의 최소 2배 이상이어야 정확한 값을 얻을 수 있습니다. 15초 간격이면 최소 30초 이상 설정합니다.


9. 메모리 부족 문제 진단

개요

Prometheus가 메모리를 과도하게 사용할 때 원인을 파악하고 청크 크기를 조정하는 방법입니다.

코드 예제

from prometheus_client import Gauge
import psutil

memory_usage = Gauge('process_memory_bytes', 'Memory usage')
active_series = Gauge('prometheus_active_series', 'Active time series')

def diagnose_memory():
    process = psutil.Process()
    mem_bytes = process.memory_info().rss
    memory_usage.set(mem_bytes)

    # 시계열당 메모리 추정
    series_count = 1000000  # API로 조회
    active_series.set(series_count)
    bytes_per_series = mem_bytes / series_count

    print(f"Memory per series: {bytes_per_series:.2f} bytes")
    if bytes_per_series > 3000:
        print("Consider reducing label cardinality")

설명

프로세스의 메모리 사용량을 시계열 개수로 나눠 시계열당 메모리를 계산합니다. 3KB 이상이면 레이블 수를 줄여야 합니다.


10. Alert 규칙 테스트

개요

Prometheus 알림 규칙이 제대로 작동하는지 테스트하고 검증하는 방법입니다.

코드 예제

import requests
import time

def test_alert_rule(prom_url, alert_name):
    # 알림이 발생하도록 메트릭 생성
    # (실제로는 애플리케이션에서 메트릭 발생)

    time.sleep(65)  # evaluation_interval보다 길게 대기

    # 알림 상태 확인
    response = requests.get(f"{prom_url}/api/v1/alerts")
    alerts = response.json()['data']['alerts']

    alert_found = any(a['labels']['alertname'] == alert_name
                     for a in alerts)

    assert alert_found, f"Alert {alert_name} not triggered"
    print(f"Alert {alert_name} working correctly")

설명

알림을 트리거할 조건을 만들고 evaluation_interval 이후에 알림 API를 확인하여 제대로 작동하는지 검증합니다.


11. 서비스 디스커버리 실패 처리

개요

Kubernetes 서비스 디스커버리가 실패할 때 fallback 타겟을 사용하는 방법입니다.

코드 예제

from kubernetes import client, config
from prometheus_client import Gauge

discovery_errors = Gauge('service_discovery_errors', 'Discovery errors')

def discover_targets_with_fallback():
    try:
        config.load_incluster_config()
        v1 = client.CoreV1Api()
        pods = v1.list_pod_for_all_namespaces(watch=False)
        targets = [f"{pod.status.pod_ip}:8080"
                  for pod in pods.items
                  if pod.status.phase == 'Running']
        discovery_errors.set(0)
        return targets
    except Exception as e:
        discovery_errors.set(1)
        # Fallback to static targets
        return ['fallback-1:8080', 'fallback-2:8080']

설명

Kubernetes API 호출이 실패하면 미리 정의된 정적 타겟 목록을 사용합니다. 서비스 디스커버리 오류를 메트릭으로 기록합니다.


12. 중복 메트릭 제거

개요

같은 메트릭이 여러 번 등록되어 발생하는 오류를 방지하는 방법입니다.

코드 예제

from prometheus_client import Counter, CollectorRegistry, REGISTRY

def get_or_create_counter(name, description, labelnames=None):
    # 이미 등록된 메트릭 확인
    for collector in list(REGISTRY._collector_to_names.keys()):
        if hasattr(collector, '_name') and collector._name == name:
            return collector

    # 새로 생성
    return Counter(
        name,
        description,
        labelnames=labelnames or []
    )

# 안전하게 메트릭 생성
requests = get_or_create_counter('http_requests_total',
                                 'Total requests',
                                 ['method'])

설명

메트릭을 생성하기 전에 레지스트리를 확인하여 이미 존재하면 재사용하고, 없으면 새로 생성합니다. 중복 등록 오류를 방지합니다.


마치며

이번 글에서는 Prometheus 트러블슈팅 완벽 가이드에 대해 알아보았습니다. 총 12가지 개념을 다루었으며, 각각의 사용법과 예제를 살펴보았습니다.

관련 태그

#Prometheus #Monitoring #Troubleshooting #Metrics #Performance

#Prometheus#Monitoring#Troubleshooting#Metrics#Performance#Python

댓글 (0)

댓글을 작성하려면 로그인이 필요합니다.