모니터링 도구 비교 분석 2025

23 min read
comparemonitoringprometheusdatadognew-relicgrafanaobservabilityapm

Prometheus vs Datadog vs New Relic vs Grafana - 모니터링 플랫폼 선택 가이드

📊 모니터링 도구 비교 분석 2025

애플리케이션과 인프라 모니터링을 위한 최적의 관측성(Observability) 플랫폼 선택 가이드


📊 개요

비교 대상

  • Prometheus + Grafana: 오픈소스 모니터링 스택
  • Datadog: 클라우드 기반 통합 모니터링
  • New Relic: Full-stack 관측성 플랫폼
  • Elastic Stack (ELK): 로그 중심 모니터링
  • AWS CloudWatch: AWS 네이티브 모니터링
  • Dynatrace: AI 기반 APM

평가 기준

  • 메트릭 수집 능력
  • 로그 분석
  • APM (Application Performance Monitoring)
  • 분산 추적
  • 알림 기능
  • 비용
  • 확장성

📈 상세 비교표

핵심 특성 비교

| 특성 | Prometheus | Datadog | New Relic | ELK Stack | | --------------- | ---------- | ---------- | ---------- | ------------- | | 호스팅 | 자체 | SaaS | SaaS | 자체/클라우드 | | 가격 | 무료 | 높음 | 높음 | 무료/유료 | | 설정 복잡도 | 높음 | 낮음 | 중간 | 높음 | | 확장성 | ⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ | | 통합 | ⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ | | 실시간성 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐ |

기능 비교

| 기능 | Prometheus | Datadog | New Relic | ELK Stack | | --------------- | ---------- | ---------- | ---------- | ---------- | | 메트릭 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐ | | 로그 | ❌ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | | APM | ❌ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ | | 분산 추적 | ❌ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ | | 인프라 | ⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐ | | 사용자 경험 | ❌ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ❌ |

가격 비교 (월 기준)

| 규모 | Prometheus | Datadog | New Relic | ELK Cloud | | -------------- | ---------- | ------- | --------- | --------- | | 10 호스트 | $0 | $150 | $750 | $95 | | 50 호스트 | $0 | $750 | $3,750 | $475 | | 100 호스트 | $0 | $1,500 | $7,500 | $950 | | 500 호스트 | $0 | $7,500 | $37,500 | $4,750 |

운영 비용 별도


💼 사용 사례별 구현

🏢 대규모 마이크로서비스

추천: Prometheus + Grafana + Jaeger

# prometheus.yml - Prometheus 설정
global:
  scrape_interval: 15s
  evaluation_interval: 15s
  external_labels:
    cluster: "production"
    region: "ap-northeast-2"

# 알림 매니저
alerting:
  alertmanagers:
    - static_configs:
        - targets: ["alertmanager:9093"]

# 규칙 파일
rule_files:
  - "alerts/*.yml"
  - "recording/*.yml"

# 서비스 디스커버리
scrape_configs:
  # Kubernetes 파드 자동 발견
  - job_name: "kubernetes-pods"
    kubernetes_sd_configs:
      - role: pod
    relabel_configs:
      - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scrape]
        action: keep
        regex: true
      - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_path]
        action: replace
        target_label: __metrics_path__
        regex: (.+)
      - source_labels:
          [__address__, __meta_kubernetes_pod_annotation_prometheus_io_port]
        action: replace
        regex: ([^:]+)(?::\d+)?;(\d+)
        replacement: $1:$2
        target_label: __address__
      - action: labelmap
        regex: __meta_kubernetes_pod_label_(.+)
      - source_labels: [__meta_kubernetes_namespace]
        action: replace
        target_label: kubernetes_namespace
      - source_labels: [__meta_kubernetes_pod_name]
        action: replace
        target_label: kubernetes_pod_name

  # Node Exporter
  - job_name: "node"
    static_configs:
      - targets: ["node-exporter:9100"]

  # 커스텀 애플리케이션 메트릭
  - job_name: "app-metrics"
    metrics_path: "/metrics"
    static_configs:
      - targets: ["app-service:8080"]
# alerts.yml - 알림 규칙
groups:
  - name: service_alerts
    interval: 30s
    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
          team: backend
        annotations:
          summary: "High error rate on {{ $labels.service }}"
          description: "{{ $labels.service }} has {{ $value | humanizePercentage }} error rate"

      - alert: HighMemoryUsage
        expr: |
          (1 - (node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes))
          * 100 > 85
        for: 5m
        labels:
          severity: warning
        annotations:
          summary: "High memory usage on {{ $labels.instance }}"
          description: "Memory usage is {{ $value | humanize }}%"

      - alert: PodCrashLooping
        expr: |
          rate(kube_pod_container_status_restarts_total[15m]) > 0
        for: 5m
        labels:
          severity: critical
        annotations:
          summary: "Pod {{ $labels.namespace }}/{{ $labels.pod }} is crash looping"
// Go 애플리케이션 계측
package main

import (
    "github.com/prometheus/client_golang/prometheus"
    "github.com/prometheus/client_golang/prometheus/promauto"
    "github.com/prometheus/client_golang/prometheus/promhttp"
)

var (
    httpDuration = promauto.NewHistogramVec(prometheus.HistogramOpts{
        Name: "http_request_duration_seconds",
        Help: "Duration of HTTP requests.",
        Buckets: prometheus.DefBuckets,
    }, []string{"path", "method", "status"})

    httpRequests = promauto.NewCounterVec(prometheus.CounterOpts{
        Name: "http_requests_total",
        Help: "Total number of HTTP requests.",
    }, []string{"path", "method", "status"})

    activeConnections = promauto.NewGauge(prometheus.GaugeOpts{
        Name: "http_active_connections",
        Help: "Number of active HTTP connections.",
    })
)

// 미들웨어
func prometheusMiddleware(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        timer := prometheus.NewTimer(httpDuration.WithLabelValues(
            r.URL.Path, r.Method, ""))

        activeConnections.Inc()
        defer activeConnections.Dec()

        rw := &responseWriter{ResponseWriter: w, statusCode: http.StatusOK}
        next.ServeHTTP(rw, r)

        timer.ObserveDuration()
        httpRequests.WithLabelValues(
            r.URL.Path, r.Method, strconv.Itoa(rw.statusCode),
        ).Inc()
    })
}

// Grafana 대시보드 (JSON)
{
  "dashboard": {
    "title": "Application Metrics",
    "panels": [
      {
        "title": "Request Rate",
        "targets": [
          {
            "expr": "sum(rate(http_requests_total[5m])) by (service)"
          }
        ]
      },
      {
        "title": "Error Rate",
        "targets": [
          {
            "expr": "sum(rate(http_requests_total{status=~\"5..\"}[5m])) by (service)"
          }
        ]
      },
      {
        "title": "Response Time (P95)",
        "targets": [
          {
            "expr": "histogram_quantile(0.95, rate(http_request_duration_seconds_bucket[5m]))"
          }
        ]
      }
    ]
  }
}

📱 SaaS 애플리케이션

추천: Datadog

# Datadog APM 통합
from ddtrace import patch_all, tracer
from datadog import initialize, statsd
import logging

# 자동 계측
patch_all()

# Datadog 초기화
initialize(
    api_key="YOUR_API_KEY",
    app_key="YOUR_APP_KEY",
    host_name="production-web-01"
)

# 커스텀 메트릭
class MetricsMiddleware:
    def __init__(self, app):
        self.app = app

    def __call__(self, environ, start_response):
        path = environ.get('PATH_INFO', '/')
        method = environ.get('REQUEST_METHOD', 'GET')

        # 요청 시작
        statsd.increment('web.requests', tags=[f'path:{path}', f'method:{method}'])

        with tracer.trace('web.request', service='webapp', resource=path):
            # 커스텀 태그
            span = tracer.current_span()
            if span:
                span.set_tag('http.method', method)
                span.set_tag('http.url', path)
                span.set_tag('customer.tier', get_customer_tier())

            start_time = time.time()

            def custom_start_response(status, headers):
                duration = (time.time() - start_time) * 1000
                status_code = int(status.split()[0])

                # 메트릭 전송
                statsd.histogram('web.request.duration', duration,
                    tags=[f'path:{path}', f'method:{method}', f'status:{status_code}'])

                if status_code >= 500:
                    statsd.increment('web.errors',
                        tags=[f'path:{path}', f'status:{status_code}'])

                if span:
                    span.set_tag('http.status_code', status_code)

                return start_response(status, headers)

            return self.app(environ, custom_start_response)

# 비즈니스 메트릭
@tracer.wrap('business.logic')
def process_order(order_id):
    try:
        # 주문 처리 로직
        order = get_order(order_id)

        # 커스텀 메트릭
        statsd.increment('orders.processed',
            tags=[f'region:{order.region}', f'product:{order.product}'])

        statsd.histogram('order.amount', order.total_amount,
            tags=[f'currency:{order.currency}'])

        # 로그 연관
        logger.info(f"Processing order {order_id}",
            extra={
                'dd.trace_id': tracer.current_span().trace_id,
                'order_id': order_id,
                'amount': order.total_amount
            })

        process_payment(order)
        update_inventory(order)
        send_notification(order)

        return order

    except Exception as e:
        statsd.increment('orders.failed',
            tags=[f'error:{type(e).__name__}'])
        raise

# Datadog 대시보드 설정 (Terraform)
resource "datadog_dashboard" "app_dashboard" {
  title = "Application Dashboard"

  widget {
    timeseries_definition {
      title = "Request Rate by Endpoint"
      request {
        q = "sum:web.requests{*} by {path}.as_rate()"
        display_type = "line"
      }
    }
  }

  widget {
    query_value_definition {
      title = "Error Rate"
      request {
        q = "sum:web.errors{*}.as_rate() / sum:web.requests{*}.as_rate() * 100"
        aggregator = "avg"
      }
      custom_unit = "%"
      precision = 2
    }
  }

  widget {
    heatmap_definition {
      title = "Response Time Distribution"
      request {
        q = "avg:web.request.duration{*} by {path}"
      }
    }
  }
}

🔍 로그 중심 모니터링

추천: ELK Stack

# Filebeat 설정
filebeat.inputs:
  - type: container
    paths:
      - '/var/lib/docker/containers/*/*.log'
    processors:
      - add_docker_metadata:
          host: "unix:///var/run/docker.sock"
      - decode_json_fields:
          fields: ["message"]
          target: "json"
          overwrite_keys: true

  - type: log
    enabled: true
    paths:
      - /var/log/nginx/access.log
    processors:
      - dissect:
          tokenizer: '%{clientip} - - [%{timestamp}] "%{method} %{uri} HTTP/%{version}" %{status} %{size} "%{referrer}" "%{agent}"'
          field: "message"
          target_prefix: "nginx"

output.elasticsearch:
  hosts: ["elasticsearch:9200"]
  indices:
    - index: "filebeat-nginx-%{+yyyy.MM.dd}"
      when.contains:
        container.name: "nginx"
    - index: "filebeat-app-%{+yyyy.MM.dd}"
      when.contains:
        container.name: "app"

# Logstash 파이프라인
input {
  beats {
    port => 5044
  }
}

filter {
  if [service] == "api" {
    grok {
      match => {
        "message" => "%{TIMESTAMP_ISO8601:timestamp} %{LOGLEVEL:level} %{DATA:logger} - %{GREEDYDATA:msg}"
      }
    }

    if [level] == "ERROR" {
      mutate {
        add_tag => [ "error", "alert" ]
      }
    }

    # 응답시간 추출
    if [msg] =~ /Request completed/ {
      grok {
        match => {
          "msg" => "Request completed: %{WORD:method} %{URIPATH:path} - %{NUMBER:duration:float}ms"
        }
      }

      mutate {
        add_field => { "metric_type" => "response_time" }
      }
    }
  }

  # GeoIP 변환
  if [clientip] {
    geoip {
      source => "clientip"
      target => "geoip"
    }
  }
}

output {
  elasticsearch {
    hosts => ["elasticsearch:9200"]
    index => "logs-%{[@metadata][beat]}-%{+YYYY.MM.dd}"
  }

  # 에러 알림
  if "error" in [tags] {
    email {
      to => "devops@company.com"
      subject => "Error Alert: %{service}"
      body => "Error detected:\n\nService: %{service}\nLevel: %{level}\nMessage: %{msg}\nHost: %{host}"
    }
  }
}

# Kibana 대시보드 설정
PUT _ingest/pipeline/parse_logs
{
  "processors": [
    {
      "grok": {
        "field": "message",
        "patterns": ["%{COMBINEDAPACHELOG}"]
      }
    },
    {
      "date": {
        "field": "timestamp",
        "target_field": "@timestamp",
        "formats": ["dd/MMM/yyyy:HH:mm:ss Z"]
      }
    },
    {
      "convert": {
        "field": "response",
        "type": "integer"
      }
    }
  ]
}

☁️ 풀스택 관측성

추천: New Relic

// New Relic APM 설정
require("newrelic");

const newrelic = require("newrelic");
const express = require("express");
const app = express();

// 커스텀 계측
app.use((req, res, next) => {
  // 트랜잭션 이름 설정
  newrelic.setTransactionName(`${req.method} ${req.route?.path || req.path}`);

  // 커스텀 속성
  newrelic.addCustomAttribute("customer_id", req.user?.id);
  newrelic.addCustomAttribute("api_version", req.headers["api-version"]);

  next();
});

// 비즈니스 메트릭
async function processPayment(order) {
  return newrelic.startSegment("payment:process", true, async () => {
    const startTime = Date.now();

    try {
      const result = await paymentGateway.charge({
        amount: order.total,
        currency: order.currency,
        customer: order.customerId,
      });

      // 커스텀 이벤트
      newrelic.recordCustomEvent("PaymentProcessed", {
        orderId: order.id,
        amount: order.total,
        currency: order.currency,
        gateway: "stripe",
        duration: Date.now() - startTime,
        success: true,
      });

      // 커스텀 메트릭
      newrelic.recordMetric("Custom/Payment/Amount", order.total);
      newrelic.recordMetric("Custom/Payment/Duration", Date.now() - startTime);

      return result;
    } catch (error) {
      // 에러 추적
      newrelic.noticeError(error, {
        orderId: order.id,
        amount: order.total,
        gateway: "stripe",
      });

      newrelic.recordCustomEvent("PaymentFailed", {
        orderId: order.id,
        error: error.message,
        errorCode: error.code,
      });

      throw error;
    }
  });
}

// Browser 모니터링
app.get("/", (req, res) => {
  const browserTimingHeader = newrelic.getBrowserTimingHeader({
    hasToRemoveScriptWrapper: true,
  });

  res.send(`
    <html>
      <head>
        ${browserTimingHeader}
        <script>
          // 커스텀 페이지 액션
          newrelic.addPageAction('customAction', {
            userId: '${req.user?.id}',
            feature: 'homepage'
          });
        </script>
      </head>
      <body>
        <!-- content -->
      </body>
    </html>
  `);
});

// Synthetic 모니터링 스크립트
const syntheticScript = `
  // New Relic Synthetics
  $browser.get('https://app.example.com').then(function() {
    return $browser.findElement($driver.By.id('login-button')).click();
  }).then(function() {
    return $browser.findElement($driver.By.id('username')).sendKeys($secure.USERNAME);
  }).then(function() {
    return $browser.findElement($driver.By.id('password')).sendKeys($secure.PASSWORD);
  }).then(function() {
    return $browser.findElement($driver.By.id('submit')).click();
  }).then(function() {
    return $browser.wait(function() {
      return $browser.findElement($driver.By.className('dashboard')).isDisplayed();
    }, 10000);
  });
`;

🏢 실제 기업 사례

Prometheus 사용

  • SoundCloud: 발명한 회사
  • DigitalOcean: 인프라 모니터링
  • 카카오: Kubernetes 모니터링
  • 쿠팡: 마이크로서비스

Datadog 사용

  • Airbnb: 전체 인프라
  • Samsung: 글로벌 서비스
  • Peloton: 실시간 모니터링
  • 토스: 금융 서비스

New Relic 사용

  • MLB: 스포츠 스트리밍
  • Domino's: 주문 시스템
  • Under Armour: 이커머스
  • 배민: 배달 플랫폼

ELK Stack 사용

  • Netflix: 로그 분석
  • LinkedIn: 보안 모니터링
  • 네이버: 검색 로그
  • 라인: 메시징 로그

🔧 통합 및 확장

에코시스템 비교

| 도구 | 통합 수 | 주요 통합 | | -------------- | ------- | ------------------------- | | Prometheus | 100+ | Kubernetes, Docker, Cloud | | Datadog | 450+ | 모든 주요 서비스 | | New Relic | 300+ | APM, 브라우저, 모바일 | | ELK | 200+ | Beats, Logstash 플러그인 |

확장성 한계

  • Prometheus: 단일 서버 한계 (페더레이션 필요)
  • Datadog: 비용 증가
  • New Relic: 데이터 보관 제한
  • ELK: 운영 복잡도

💰 TCO 분석

50대 서버 기준 (연간)

| 항목 | Prometheus | Datadog | New Relic | ELK | | ------------- | ---------- | -------- | --------- | -------- | | 라이선스 | $0 | $9,000 | $45,000 | $0 | | 인프라 | $5,000 | $0 | $0 | $10,000 | | 운영 인력 | 1명 | 0.2명 | 0.2명 | 1명 | | 총 비용 | ~$65,000 | ~$21,000 | ~$57,000 | ~$70,000 |


🎯 선택 가이드

Prometheus + Grafana 선택 시

✅ 오픈소스 선호
✅ Kubernetes 환경
✅ 메트릭 중심
✅ 비용 민감
❌ 로그/APM 필요
❌ 운영 인력 부족

Datadog 선택 시

✅ 통합 플랫폼 원함
✅ 빠른 구축
✅ 다양한 통합
✅ 글로벌 서비스
❌ 높은 비용
❌ 데이터 주권

New Relic 선택 시

✅ APM 중심
✅ 사용자 경험 중요
✅ 풀스택 관측성
✅ 코드 레벨 분석
❌ 높은 비용
❌ 인프라 모니터링만

ELK Stack 선택 시

✅ 로그 분석 중심
✅ 유연한 검색
✅ 보안 분석
✅ 비용 통제
❌ 실시간 메트릭
❌ APM 기능


📚 추가 리소스

공식 문서

모니터링 모범 사례

  • USE Method (Utilization, Saturation, Errors)
  • RED Method (Rate, Errors, Duration)
  • Four Golden Signals (Google SRE)
  • 분산 추적 구현

한국 커뮤니티

  • Prometheus 한국 사용자 모임
  • Elastic 한국 사용자 그룹
  • DevOps Korea
  • SRE Korea

💡 핵심 조언: 모니터링은 "도구"가 아닌 "문화"입니다. 비싼 도구를 쓴다고 좋은 모니터링이 되는 것이 아닙니다. 작은 규모라면 Prometheus + Grafana로 시작하고, 성장하면서 Datadog이나 New Relic을 고려하세요. 중요한 것은 무엇을 측정하고 어떻게 대응할지 아는 것입니다.

Found this helpful? Share it with others!
Tweet

🔗 Related Content

You might also be interested in these articles

🏗️ stack

🤖 AI-Powered App Stack

프로덕션 레벨 AI 애플리케이션 구축을 위한 검증된 기술 스택 - LangChain, FastAPI, Vector DB로 RAG 시스템 구현

13 min read
python, fastapi +13
Read more
🏗️ stack

🏢 Enterprise Microservices Stack

대규모 트래픽과 복잡한 비즈니스 로직을 위한 마이크로서비스 아키텍처 - Go, gRPC, Kubernetes로 구축하는 확장 가능한 시스템

14 min read
go, grpc +13
Read more

Found this helpful?

Help us improve this content by contributing on GitHub or sharing your feedback with the community.