[2026] 2026년 필수 기술 스택 | Kibana·Prometheus·Redis·Grafana·ELK 완벽 가이드

[2026] 2026년 필수 기술 스택 | Kibana·Prometheus·Redis·Grafana·ELK 완벽 가이드

이 글의 핵심

현대 개발자가 반드시 알아야 할 오픈소스 기술 스택. Kibana 로그 분석, Prometheus 모니터링, Redis 캐싱, Grafana 대시보드, ELK Stack 구축까지 실전 예제로 마스터하세요.

들어가며: 현대 기술 스택의 필수 요소

2026년 현재, 성공적인 서비스 운영을 위해서는 모니터링, 로그 분석, 캐싱, 메트릭 수집이 필수입니다. 이 글에서는 각 영역의 대표 오픈소스 도구들을 실전 예제와 함께 소개합니다. 다룰 기술 스택:

  • Redis: 인메모리 데이터 저장소 및 캐시
  • Elasticsearch: 분산 검색 및 분석 엔진
  • Kibana: 로그 시각화 및 분석
  • Prometheus: 메트릭 수집 및 모니터링
  • Grafana: 메트릭 대시보드
  • Jaeger: 분산 추적 (Tracing)

실무에서 마주한 현실

개발을 배울 때는 모든 게 깔끔하고 이론적입니다. 하지만 실무는 다릅니다. 레거시 코드와 씨름하고, 급한 일정에 쫓기고, 예상치 못한 버그와 마주합니다. 이 글에서 다루는 내용도 처음엔 이론으로 배웠지만, 실제 프로젝트에 적용하면서 “아, 이래서 이렇게 설계하는구나” 하고 깨달은 것들입니다. 특히 기억에 남는 건 첫 프로젝트에서 겪은 시행착오입니다. 책에서 배운 대로 했는데 왜 안 되는지 몰라 며칠을 헤맸죠. 결국 선배 개발자의 코드 리뷰를 통해 문제를 발견했고, 그 과정에서 많은 걸 배웠습니다. 이 글에서는 이론뿐 아니라 실전에서 마주칠 수 있는 함정들과 해결 방법을 함께 다루겠습니다.

목차

  1. Redis: 초고속 인메모리 데이터베이스
  2. ELK Stack: 로그 수집과 분석
  3. Prometheus: 메트릭 기반 모니터링
  4. Grafana: 통합 대시보드
  5. Jaeger: 분산 추적
  6. 기술 스택 비교와 선택
  7. 실전 아키텍처
  8. 베스트 프랙티스

1. Redis: 초고속 인메모리 데이터베이스

Redis란?

Redis(Remote Dictionary Server)는 인메모리 키-값 저장소로, 캐싱, 세션 관리, 실시간 분석에 사용됩니다.

주요 특징

  • 속도: 마이크로초 단위 응답 시간
  • 자료구조: String, List, Set, Hash, Sorted Set, Stream
  • 영속성: RDB, AOF 스냅샷
  • 클러스터링: 샤딩 및 복제 지원

Redis 아키텍처

다음은 mermaid를 활용한 상세한 구현 코드입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

flowchart TB
    subgraph App[Application Servers]
        A1[App 1]
        A2[App 2]
        A3[App 3]
    end
    
    subgraph Redis_Cluster[Redis Cluster]
        M1["Master 1\nSlots: 0-5460"]
        M2["Master 2\nSlots: 5461-10922"]
        M3["Master 3\nSlots: 10923-16383"]
        
        S1[Replica 1]
        S2[Replica 2]
        S3[Replica 3]
        
        M1 --> S1
        M2 --> S2
        M3 --> S3
    end
    
    A1 --> M1
    A2 --> M2
    A3 --> M3

실전 사용 예시

1. 캐싱

다음은 python를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고, 함수를 통해 로직을 구현합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

import redis
import json
r = redis.Redis(host='localhost', port=6379, decode_responses=True)
# 캐시 읽기
def get_user(user_id):
    # 캐시 확인
    cached = r.get(f"user:{user_id}")
    if cached:
        return json.loads(cached)
    
    # DB에서 조회
    user = db.query("SELECT * FROM users WHERE id = ?", user_id)
    
    # 캐시 저장 (10분)
    r.setex(f"user:{user_id}", 600, json.dumps(user))
    return user

2. 세션 관리

아래 코드는 python를 사용한 구현 예제입니다. 함수를 통해 로직을 구현합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

# 세션 저장
def create_session(user_id, session_data):
    session_id = generate_session_id()
    r.setex(
        f"session:{session_id}",
        3600,  # 1시간
        json.dumps({"user_id": user_id, **session_data})
    )
    return session_id
# 세션 조회
def get_session(session_id):
    data = r.get(f"session:{session_id}")
    return json.loads(data) if data else None

3. Rate Limiting

아래 코드는 python를 사용한 구현 예제입니다. 함수를 통해 로직을 구현합니다. 코드를 직접 실행해보면서 동작을 확인해보세요.

def check_rate_limit(user_id, limit=100, window=60):
    key = f"rate_limit:{user_id}"
    current = r.incr(key)
    
    if current == 1:
        r.expire(key, window)
    
    return current <= limit

4. 실시간 리더보드

아래 코드는 python를 사용한 구현 예제입니다. 코드를 직접 실행해보면서 동작을 확인해보세요.

# 점수 추가
r.zadd("leaderboard", {"user1": 1000, "user2": 1500})
# 상위 10명 조회
top10 = r.zrevrange("leaderboard", 0, 9, withscores=True)
for user, score in top10:
    print(f"{user}: {score}")

Redis 성능 팁

다음은 python를 활용한 상세한 구현 코드입니다. 비동기 처리를 통해 효율적으로 작업을 수행합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

# ✅ Pipeline으로 네트워크 왕복 최소화
pipe = r.pipeline()
for i in range(1000):
    pipe.set(f"key:{i}", f"value:{i}")
pipe.execute()
# ✅ Lua 스크립트로 원자적 연산
lua_script = """
local current = redis.call('GET', KEYS[1])
if tonumber(current) < tonumber(ARGV[1]) then
    return redis.call('SET', KEYS[1], ARGV[1])
end
return 0
"""
r.eval(lua_script, 1, "counter", 100)

일상 비유로 이해하기: 메모리를 아파트 건물로 생각해보세요. 스택은 엘리베이터 같아서 빠르지만 공간이 제한적입니다. 힙은 창고처럼 넓지만 물건을 찾는 데 시간이 걸립니다. 포인터는 “3층 302호”처럼 주소를 가리키는 메모지라고 보면 됩니다.

2. ELK Stack: 로그 수집과 분석

ELK Stack이란?

ELK는 Elasticsearch, Logstash, Kibana의 조합으로, 로그 수집·저장·분석·시각화를 위한 통합 솔루션입니다. 다음은 mermaid를 활용한 상세한 구현 코드입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

flowchart LR
    subgraph Sources[로그 소스]
        App[Application]
        Web[Web Server]
        DB[Database]
    end
    
    subgraph Logstash[Logstash]
        Input[Input]
        Filter[Filter]
        Output[Output]
        Input --> Filter --> Output
    end
    
    subgraph Elasticsearch[Elasticsearch Cluster]
        ES1[Node 1]
        ES2[Node 2]
        ES3[Node 3]
    end
    
    subgraph Kibana[Kibana]
        Dashboard[Dashboard]
        Discover[Discover]
        Visualize[Visualize]
    end
    
    App --> Logstash
    Web --> Logstash
    DB --> Logstash
    
    Logstash --> ES1
    ES1 <--> ES2
    ES2 <--> ES3
    
    ES1 --> Kibana

Elasticsearch

분산 검색 및 분석 엔진으로, JSON 문서를 인덱싱하고 빠르게 검색합니다.

인덱스 생성 및 문서 추가

다음은 bash를 활용한 상세한 구현 코드입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

# 인덱스 생성
curl -X PUT "localhost:9200/logs" -H 'Content-Type: application/json' -d'
{
  "mappings": {
    "properties": {
      "timestamp": {"type": "date"},
      "level": {"type": "keyword"},
      "message": {"type": "text"},
      "user_id": {"type": "keyword"}
    }
  }
}'
# 문서 추가
curl -X POST "localhost:9200/logs/_doc" -H 'Content-Type: application/json' -d'
{
  "timestamp": "2026-04-01T10:00:00Z",
  "level": "ERROR",
  "message": "Database connection failed",
  "user_id": "user123"
}'

검색 쿼리

다음은 python를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

from elasticsearch import Elasticsearch
es = Elasticsearch(['http://localhost:9200'])
# 에러 로그 검색
response = es.search(index="logs", body={
    "query": {
        "bool": {
            "must": [
                {"match": {"level": "ERROR"}},
                {"range": {"timestamp": {"gte": "now-1h"}}}
            ]
        }
    },
    "sort": [{"timestamp": {"order": "desc"}}],
    "size": 100
})
for hit in response['hits']['hits']:
    print(hit['_source'])

Logstash

데이터 수집 및 변환 파이프라인입니다.

Logstash 설정 예시

다음은 ruby를 활용한 상세한 구현 코드입니다. 반복문으로 데이터를 처리합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

# logstash.conf
input {
  file {
    path => "/var/log/app/*.log"
    start_position => "beginning"
  }
  
  tcp {
    port => 5000
    codec => json
  }
}
filter {
  # JSON 파싱
  json {
    source => "message"
  }
  
  # 날짜 파싱
  date {
    match => ["timestamp", "ISO8601"]
  }
  
  # 필드 추가
  mutate {
    add_field => { "environment" => "production" }
  }
  
  # Grok 패턴으로 로그 파싱
  grok {
    match => { "message" => "%{TIMESTAMP_ISO8601:timestamp} %{LOGLEVEL:level} %{GREEDYDATA:msg}" }
  }
}
output {
  elasticsearch {
    hosts => [localhost:9200]
    index => "logs-%{+YYYY.MM.dd}"
  }
  
  stdout {
    codec => rubydebug
  }
}

Kibana

Elasticsearch 데이터 시각화 도구입니다.

주요 기능

  1. Discover: 로그 검색 및 필터링
  2. Visualize: 차트, 그래프 생성
  3. Dashboard: 여러 시각화를 하나의 대시보드로
  4. Alerting: 조건 기반 알림

Kibana 쿼리 예시 (KQL)

아래 코드는 code를 사용한 구현 예제입니다. 코드를 직접 실행해보면서 동작을 확인해보세요.

# 에러 로그 검색
level: 중급
# 특정 사용자의 로그
user_id: "user123" AND status: 500
# 느린 API 요청
response_time > 1000 AND endpoint: "/api/*"

3. Prometheus: 메트릭 기반 모니터링

Prometheus란?

Prometheus는 시계열 데이터베이스 기반의 모니터링 및 알림 시스템입니다. Pull 모델로 메트릭을 수집합니다.

Prometheus 아키텍처

다음은 mermaid를 활용한 상세한 구현 코드입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

flowchart TB
    subgraph Targets[모니터링 대상]
        App1["App Server 1\n/metrics"]
        App2["App Server 2\n/metrics"]
        Node1[Node Exporter]
        DB[Database Exporter]
    end
    
    subgraph Prometheus[Prometheus Server]
        Scraper[Scraper]
        TSDB[Time Series DB]
        Rules[Alert Rules]
        
        Scraper --> TSDB
        TSDB --> Rules
    end
    
    subgraph Alerting[Alerting]
        AM[Alertmanager]
        Email[Email]
        Slack[Slack]
        PagerDuty[PagerDuty]
    end
    
    subgraph Visualization[시각화]
        Grafana[Grafana]
        PromUI[Prometheus UI]
    end
    
    App1 --> Scraper
    App2 --> Scraper
    Node1 --> Scraper
    DB --> Scraper
    
    Rules --> AM
    AM --> Email
    AM --> Slack
    AM --> PagerDuty
    
    TSDB --> Grafana
    TSDB --> PromUI

메트릭 타입

1. Counter (카운터)

증가만 하는 값 (요청 수, 에러 수) 아래 코드는 python를 사용한 구현 예제입니다. 필요한 모듈을 import하고, 함수를 통해 로직을 구현합니다. 코드를 직접 실행해보면서 동작을 확인해보세요.

from prometheus_client import Counter
request_count = Counter('http_requests_total', 'Total HTTP requests', ['method', 'endpoint'])
@app.route('/api/users')
def get_users():
    request_count.labels(method='GET', endpoint='/api/users').inc()
    return users

2. Gauge (게이지)

증가/감소하는 값 (CPU 사용률, 메모리) 아래 코드는 python를 사용한 구현 예제입니다. 필요한 모듈을 import하고, 함수를 통해 로직을 구현합니다. 코드를 직접 실행해보면서 동작을 확인해보세요.

from prometheus_client import Gauge
memory_usage = Gauge('memory_usage_bytes', 'Memory usage in bytes')
def update_metrics():
    import psutil
    memory_usage.set(psutil.virtual_memory().used)

3. Histogram (히스토그램)

값의 분포 (응답 시간, 요청 크기) 아래 코드는 python를 사용한 구현 예제입니다. 필요한 모듈을 import하고, 함수를 통해 로직을 구현합니다. 코드를 직접 실행해보면서 동작을 확인해보세요.

from prometheus_client import Histogram
response_time = Histogram('http_response_time_seconds', 'HTTP response time')
@app.route('/api/data')
@response_time.time()
def get_data():
    # 자동으로 응답 시간 측정
    return process_data()

4. Summary (요약)

분위수 계산 (P50, P95, P99) 아래 코드는 python를 사용한 구현 예제입니다. 필요한 모듈을 import하고, 함수를 통해 로직을 구현합니다. 코드를 직접 실행해보면서 동작을 확인해보세요.

from prometheus_client import Summary
latency = Summary('request_latency_seconds', 'Request latency')
@latency.time()
def process_request():
    # 처리
    pass

Prometheus 설정

다음은 yaml를 활용한 상세한 구현 코드입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

# prometheus.yml
global:
  scrape_interval: 15s
  evaluation_interval: 15s
scrape_configs:
  - job_name: 'node'
    static_configs:
      - targets: ['localhost:9100']
  
  - job_name: 'app'
    static_configs:
      - targets: ['localhost:8080']
    metrics_path: '/metrics'
  
  - job_name: 'kubernetes'
    kubernetes_sd_configs:
      - role: pod

PromQL 쿼리 예시

아래 코드는 promql를 사용한 구현 예제입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

# CPU 사용률 (5분 평균)
rate(cpu_usage_seconds_total[5m])
# 에러율 (지난 1시간)
sum(rate(http_requests_total{status=~"5.."}[1h])) / 
sum(rate(http_requests_total[1h]))
# P95 응답 시간
histogram_quantile(0.95, 
  rate(http_response_time_seconds_bucket[5m]))
# 메모리 사용률
(node_memory_MemTotal_bytes - node_memory_MemAvailable_bytes) / 
node_memory_MemTotal_bytes * 100

Alert Rules

다음은 yaml를 활용한 상세한 구현 코드입니다. 에러 처리를 통해 안정성을 확보합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

# alert.rules.yml
groups:
  - name: example
    rules:
      - alert: HighErrorRate
        expr: |
          sum(rate(http_requests_total{status=~"5.."}[5m])) /
          sum(rate(http_requests_total[5m])) > 0.05
        for: 10m
        labels:
          severity: critical
        annotations:
          summary: "High error rate detected"
          description: "Error rate is {{ $value }}%"
      
      - alert: HighMemoryUsage
        expr: node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes < 0.1
        for: 5m
        labels:
          severity: warning
        annotations:
          summary: "High memory usage on {{ $labels.instance }}"

4. Grafana: 통합 대시보드

Grafana란?

Grafana는 메트릭, 로그, 트레이스를 시각화하는 오픈소스 플랫폼입니다. Prometheus, Elasticsearch, MySQL 등 다양한 데이터 소스를 지원합니다.

주요 기능

  1. 대시보드: 여러 패널을 조합한 시각화
  2. 알림: 임계값 기반 알림
  3. 템플릿: 변수를 사용한 동적 대시보드
  4. 플러그인: 다양한 데이터 소스 및 패널

Grafana 대시보드 예시

다음은 json를 활용한 상세한 구현 코드입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

{
  "dashboard": {
    "title": "Application Monitoring",
    "panels": [
      {
        "title": "Request Rate",
        "targets": [
          {
            "expr": "rate(http_requests_total[5m])",
            "legendFormat": "{{method}} {{endpoint}}"
          }
        ],
        "type": "graph"
      },
      {
        "title": "Error Rate",
        "targets": [
          {
            "expr": "sum(rate(http_requests_total{status=~\"5..\"}[5m]))"
          }
        ],
        "type": "stat",
        "thresholds": [
          {"value": 0, "color": "green"},
          {"value": 0.01, "color": "yellow"},
          {"value": 0.05, "color": "red"}
        ]
      },
      {
        "title": "Response Time (P95)",
        "targets": [
          {
            "expr": "histogram_quantile(0.95, rate(http_response_time_seconds_bucket[5m]))"
          }
        ],
        "type": "graph"
      }
    ]
  }
}

Grafana 알림 설정

다음은 yaml를 활용한 상세한 구현 코드입니다. 에러 처리를 통해 안정성을 확보합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

# Grafana Alert
apiVersion: 1
groups:
  - name: app-alerts
    interval: 1m
    rules:
      - uid: high-error-rate
        title: High Error Rate
        condition: A
        data:
          - refId: A
            queryType: '
            relativeTimeRange:
              from: 600
              to: 0
            datasourceUid: prometheus-uid
            model:
              expr: 'rate(http_errors_total[5m]) > 10'
        noDataState: NoData
        execErrState: Alerting
        for: 5m
        annotations:
          summary: 'Error rate is too high'
        labels:
          severity: critical

5. Jaeger: 분산 추적

Jaeger란?

Jaeger는 마이크로서비스 환경에서 요청의 전체 흐름을 추적하는 분산 추적 시스템입니다.

Jaeger 아키텍처

다음은 mermaid를 활용한 상세한 구현 코드입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

flowchart TB
    subgraph Services[Microservices]
        S1[API Gateway]
        S2[Auth Service]
        S3[Order Service]
        S4[Payment Service]
    end
    
    subgraph Jaeger[Jaeger]
        Agent[Jaeger Agent]
        Collector[Collector]
        Storage["Storage\nElasticsearch/Cassandra"]
        UI[Jaeger UI]
    end
    
    S1 --> Agent
    S2 --> Agent
    S3 --> Agent
    S4 --> Agent
    
    Agent --> Collector
    Collector --> Storage
    Storage --> UI

OpenTelemetry로 Tracing 구현

다음은 python를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고, 함수를 통해 로직을 구현합니다, 에러 처리를 통해 안정성을 확보합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

from opentelemetry import trace
from opentelemetry.exporter.jaeger.thrift import JaegerExporter
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor
# Tracer 설정
trace.set_tracer_provider(TracerProvider())
tracer = trace.get_tracer(__name__)
jaeger_exporter = JaegerExporter(
    agent_host_name="localhost",
    agent_port=6831,
)
trace.get_tracer_provider().add_span_processor(
    BatchSpanProcessor(jaeger_exporter)
)
# Span 생성
@app.route('/api/order')
def create_order():
    with tracer.start_as_current_span("create_order") as span:
        span.set_attribute("user_id", user_id)
        span.set_attribute("order_id", order_id)
        
        # 하위 작업
        with tracer.start_as_current_span("check_inventory"):
            check_inventory(order_id)
        
        with tracer.start_as_current_span("process_payment"):
            process_payment(order_id)
        
        return {"order_id": order_id}

Trace 시각화

Jaeger UI에서 다음을 확인할 수 있습니다: 아래 코드는 code를 사용한 구현 예제입니다. 코드를 직접 실행해보면서 동작을 확인해보세요.

Trace: create_order (총 500ms)
├── check_inventory (100ms)
│   └── database_query (80ms)
├── process_payment (350ms)
│   ├── validate_card (50ms)
│   ├── charge_card (250ms)
│   └── send_receipt (50ms)
└── update_inventory (50ms)

6. 기술 스택 비교와 선택

종합 비교표

기술목적데이터 타입지연시간저장 방식주요 사용 사례
Redis캐싱, 세션키-값마이크로초인메모리캐시, 세션, Rate Limiting
Elasticsearch검색, 분석JSON 문서밀리초디스크로그 검색, 전문 검색
Prometheus메트릭 수집시계열초 단위디스크CPU, 메모리, 요청 수 모니터링
Grafana시각화---대시보드, 알림
Jaeger분산 추적Span밀리초디스크마이크로서비스 추적

선택 플로우차트

다음은 mermaid를 활용한 상세한 구현 코드입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

flowchart TD
    Start[무엇을 하고 싶나요?] --> Q1{데이터 타입은?}
    
    Q1 -->|로그| Q2{검색 필요?}
    Q2 -->|Yes| ELK[Elasticsearch + Kibana]
    Q2 -->|No| Loki[Loki + Grafana]
    
    Q1 -->|메트릭| Q3{시계열 데이터?}
    Q3 -->|Yes| Prom[Prometheus + Grafana]
    Q3 -->|No| InfluxDB[InfluxDB]
    
    Q1 -->|캐시/세션| Q4{영속성 필요?}
    Q4 -->|Yes| Redis_AOF[Redis + AOF]
    Q4 -->|No| Redis_Mem[Redis 인메모리]
    
    Q1 -->|분산 추적| Jaeger[Jaeger/Zipkin]

7. 실전 아키텍처

완전한 관측성(Observability) 스택

다음은 mermaid를 활용한 상세한 구현 코드입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

flowchart TB
    subgraph App[Application Layer]
        API[API Server]
        Worker[Background Worker]
        Service[Microservices]
    end
    
    subgraph Logs[로그 수집]
        Filebeat[Filebeat]
        Logstash[Logstash]
        ES[Elasticsearch]
        Kibana[Kibana]
    end
    
    subgraph Metrics[메트릭 수집]
        Prometheus[Prometheus]
        Grafana[Grafana]
    end
    
    subgraph Traces[분산 추적]
        Jaeger[Jaeger]
    end
    
    subgraph Cache[캐싱]
        Redis[Redis]
    end
    
    API --> Filebeat
    Worker --> Filebeat
    Service --> Filebeat
    Filebeat --> Logstash
    Logstash --> ES
    ES --> Kibana
    
    API --> Prometheus
    Worker --> Prometheus
    Service --> Prometheus
    Prometheus --> Grafana
    
    API --> Jaeger
    Service --> Jaeger
    
    API --> Redis
    Service --> Redis

Docker Compose 예시

다음은 yaml를 활용한 상세한 구현 코드입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

version: '3.8'
services:
  # Redis
  redis:
    image: redis:7-alpine
    ports:
      - "6379:6379"
    volumes:
      - redis-data:/data
    command: redis-server --appendonly yes
  
  # Elasticsearch
  elasticsearch:
    image: docker.elastic.co/elasticsearch/elasticsearch:8.12.0
    environment:
      - discovery.type=single-node
      - "ES_JAVA_OPTS=-Xms512m -Xmx512m"
    ports:
      - "9200:9200"
    volumes:
      - es-data:/usr/share/elasticsearch/data
  
  # Kibana
  kibana:
    image: docker.elastic.co/kibana/kibana:8.12.0
    ports:
      - "5601:5601"
    environment:
      - ELASTICSEARCH_HOSTS=http://elasticsearch:9200
    depends_on:
      - elasticsearch
  
  # Prometheus
  prometheus:
    image: prom/prometheus:latest
    ports:
      - "9090:9090"
    volumes:
      - ./prometheus.yml:/etc/prometheus/prometheus.yml
      - prometheus-data:/prometheus
    command:
      - '--config.file=/etc/prometheus/prometheus.yml'
      - '--storage.tsdb.path=/prometheus'
  
  # Grafana
  grafana:
    image: grafana/grafana:latest
    ports:
      - "3000:3000"
    environment:
      - GF_SECURITY_ADMIN_PASSWORD=admin
    volumes:
      - grafana-data:/var/lib/grafana
    depends_on:
      - prometheus
  
  # Jaeger
  jaeger:
    image: jaegertracing/all-in-one:latest
    ports:
      - "5775:5775/udp"
      - "6831:6831/udp"
      - "6832:6832/udp"
      - "5778:5778"
      - "16686:16686"  # UI
      - "14268:14268"
      - "14250:14250"
    environment:
      - COLLECTOR_ZIPKIN_HOST_PORT=:9411
volumes:
  redis-data:
  es-data:
  prometheus-data:
  grafana-data:

8. 베스트 프랙티스

Redis 베스트 프랙티스

1. 적절한 만료 시간 설정

아래 코드는 python를 사용한 구현 예제입니다. 코드를 직접 실행해보면서 동작을 확인해보세요.

# ✅ 캐시에는 항상 TTL 설정
r.setex("user:123", 600, json.dumps(user_data))  # 10분
# ❌ TTL 없으면 메모리 부족 위험
r.set("user:123", json.dumps(user_data))

2. 키 네이밍 규칙

아래 코드는 python를 사용한 구현 예제입니다. 코드를 직접 실행해보면서 동작을 확인해보세요.

# ✅ 명확한 네이밍
"user:123:profile"
"session:abc123"
"cache:product:456"
# ❌ 모호한 네이밍
"u123"
"s1"

3. 대용량 데이터 처리

아래 코드는 python를 사용한 구현 예제입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

# ✅ SCAN으로 안전하게 순회
cursor = 0
while True:
    cursor, keys = r.scan(cursor, match="user:*", count=100)
    for key in keys:
        process(key)
    if cursor == 0:
        break
# ❌ KEYS는 프로덕션에서 금지 (블로킹)
keys = r.keys("user:*")  # 위험!

Elasticsearch 베스트 프랙티스

1. 인덱스 라이프사이클 관리

다음은 json를 활용한 상세한 구현 코드입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

{
  "policy": {
    "phases": {
      "hot": {
        "actions": {
          "rollover": {
            "max_size": "50GB",
            "max_age": "1d"
          }
        }
      },
      "warm": {
        "min_age": "7d",
        "actions": {
          "shrink": {"number_of_shards": 1}
        }
      },
      "delete": {
        "min_age": "30d",
        "actions": {
          "delete": {}
        }
      }
    }
  }
}

2. 샤드 크기 최적화

# 샤드당 20-40GB 권장
# 인덱스 크기 100GB → 샤드 3-5개

3. 쿼리 최적화

다음은 python를 활용한 상세한 구현 코드입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

# ✅ 필터 컨텍스트 사용 (캐싱)
{
  "query": {
    "bool": {
      "filter": [
        {"term": {"status": "active"}},
        {"range": {"timestamp": {"gte": "now-1h"}}}
      ]
    }
  }
}
# ❌ 쿼리 컨텍스트 (스코어 계산 오버헤드)
{
  "query": {
    "match": {"status": "active"}
  }
}

Prometheus 베스트 프랙티스

1. 레이블 카디널리티 주의

아래 코드는 python를 사용한 구현 예제입니다. 코드를 직접 실행해보면서 동작을 확인해보세요.

# ✅ 낮은 카디널리티
http_requests_total{method="GET", endpoint="/api/users"}
# ❌ 높은 카디널리티 (user_id는 수백만 개)
http_requests_total{user_id="123456"}  # 위험!

2. 적절한 스크랩 간격

아래 코드는 yaml를 사용한 구현 예제입니다. 코드를 직접 실행해보면서 동작을 확인해보세요.

# 일반 애플리케이션: 15-30초
scrape_interval: 15s
# 고빈도 메트릭: 5초
scrape_interval: 5s
# 저빈도 메트릭: 1분
scrape_interval: 1m

3. Recording Rules로 쿼리 최적화

아래 코드는 yaml를 사용한 구현 예제입니다. 에러 처리를 통해 안정성을 확보합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

# 자주 사용하는 쿼리를 미리 계산
groups:
  - name: aggregations
    interval: 30s
    rules:
      - record: job:http_requests:rate5m
        expr: sum(rate(http_requests_total[5m])) by (job)
      
      - record: job:http_errors:rate5m
        expr: sum(rate(http_requests_total{status=~"5.."}[5m])) by (job)

실전 시나리오

시나리오 1: 전자상거래 모니터링

다음은 python를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고, 함수를 통해 로직을 구현합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

# 애플리케이션 메트릭
from prometheus_client import Counter, Histogram, Gauge
import redis
import logging
# Redis 캐시
cache = redis.Redis(host='localhost', port=6379)
# Prometheus 메트릭
order_count = Counter('orders_total', 'Total orders', ['status'])
order_amount = Histogram('order_amount_dollars', 'Order amount')
active_users = Gauge('active_users', 'Currently active users')
# Elasticsearch 로깅
logger = logging.getLogger('app')
logger.addHandler(LogstashHandler('localhost', 5000))
@app.route('/api/order', methods=['POST'])
def create_order():
    # 캐시 확인
    user = cache.get(f"user:{user_id}")
    if not user:
        user = db.get_user(user_id)
        cache.setex(f"user:{user_id}", 600, json.dumps(user))
    
    # 주문 처리
    order = process_order(request.json)
    
    # 메트릭 기록
    order_count.labels(status='success').inc()
    order_amount.observe(order['amount'])
    
    # 로그 기록
    logger.info(f"Order created: {order['id']}", extra={
        'user_id': user_id,
        'order_id': order['id'],
        'amount': order['amount']
    })
    
    return jsonify(order)

시나리오 2: 로그 기반 알림

다음은 ruby를 활용한 상세한 구현 코드입니다. 반복문으로 데이터를 처리합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

# Logstash 필터로 에러 감지 후 Slack 알림
filter {
  if [level] == "ERROR" {
    mutate {
      add_tag => [alert]
    }
  }
}
output {
  if "alert" in [tags] {
    http {
      url => "https://hooks.slack.com/services/YOUR/WEBHOOK/URL"
      http_method => "post"
      format => "json"
      content_type => "application/json"
      message => '{"text": "🚨 Error detected: %{message}"}'
    }
  }
}

정리

기술 스택 역할 요약

레이어기술역할
캐싱Redis데이터 캐싱, 세션 관리, Rate Limiting
로그ELK Stack로그 수집, 검색, 분석, 시각화
메트릭Prometheus시스템/애플리케이션 메트릭 수집
시각화Grafana통합 대시보드, 알림
추적Jaeger분산 요청 추적, 성능 분석

관측성의 3가지 기둥

아래 코드는 mermaid를 사용한 구현 예제입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

flowchart TB
    Observability["관측성\nObservability"]
    
    Logs["로그\nLogs"]
    Metrics["메트릭\nMetrics"]
    Traces["추적\nTraces"]
    
    Observability --> Logs
    Observability --> Metrics
    Observability --> Traces
    
    Logs --> ELK[ELK Stack]
    Metrics --> Prom[Prometheus + Grafana]
    Traces --> Jaeger[Jaeger]

시작 가이드

1단계: 기본 스택 구축

아래 코드는 bash를 사용한 구현 예제입니다. 코드를 직접 실행해보면서 동작을 확인해보세요.

# Docker Compose로 한 번에 실행
docker-compose up -d
# 접속 URL
# Kibana: http://localhost:5601
# Grafana: http://localhost:3000
# Prometheus: http://localhost:9090
# Jaeger: http://localhost:16686

2단계: 애플리케이션 계측

다음은 간단한 python 코드 예제입니다. 에러 처리를 통해 안정성을 확보합니다. 코드를 직접 실행해보면서 동작을 확인해보세요.

# 1. Redis 캐싱 추가
# 2. Prometheus 메트릭 노출
# 3. Structured 로깅 (JSON)
# 4. OpenTelemetry Tracing

3단계: 대시보드 구성

다음은 간단한 code 코드 예제입니다. 코드를 직접 실행해보면서 동작을 확인해보세요.

1. Grafana에서 Prometheus 데이터 소스 추가
2. 주요 메트릭 대시보드 생성
3. Kibana에서 로그 인덱스 패턴 설정
4. Jaeger에서 서비스 추적 확인

참고 자료

... 996 lines not shown ... Token usage: 63706/1000000; 936294 remaining Start-Sleep -Seconds 3