Pingu
영차영차! Backend

DDoS 공격을 겪고 나서 알게 된 모니터링의 가치

2026년 2월 1일
7개 태그
Prometheus
Spring Boot
모니터링
Observability
Micrometer
Grafana
Kotlin

DDoS 공격을 겪고 나서 알게 된 모니터링의 가치

들어가며

"결제가 안 되는데요?"

금요일 오후 3시, 갑자기 들어온 CS 문의였다. 처음에는 단순한 버그인 줄 알았습니다. 하지만 곧이어 두 번째, 세 번째... 문의가 쇄도하기 시작했습니다.

"서비스가 너무 느려요" "페이지가 안 열려요" "에러가 계속 나요"

뭔가 이상했다.

Chapter 1: 문제의 시작 - "뭔가 이상한데?"

상황: 프로모션 기간 중 비정상적인 트래픽 폭증

특정 프로모션 기간 중이었습니다. 평소 50-100 TPS를 처리하던 시스템이 갑자기 응답이 느려지기 시작했습니다. 처음에는 "프로모션이라서 트래픽이 많은가보다"라고 생각했습니다.

하지만 시간이 지나도 상황이 나아지지 않았습니다. 오히려 더 악화되었습니다.

로그만으로는 부족했다

당시 우리가 할 수 있었던 것은 로그를 확인하는 것뿐이었습니다:

# Cloud Run 로그 확인
gcloud logging read "resource.type=cloud_run_revision" --limit=100

# 로그에서 패턴 찾기
grep "ERROR" logs.txt | wc -l

문제점:

  • 로그를 파싱해서 집계해야 함 → 시간이 오래 걸림
  • 실시간으로 트렌드를 파악하기 어려움
  • "지금 TPS가 얼마인지" 즉시 알 수 없음
  • "어느 엔드포인트가 문제인지" 한눈에 보기 어려움

15분의 고민

결제 API가 느려지고, 일부 사용자 요청이 실패하기 시작했습니다. 하지만 우리는 "지금 무슨 일이 일어나고 있는지" 정확히 알 수 없었습니다.

  • 정상적인 프로모션 트래픽인가?
  • 특정 엔드포인트에 문제가 있는가?
  • 서버 리소스가 부족한가?
  • 외부 공격인가?

로그만으로는 답을 찾을 수 없었습니다.

Chapter 2: 원인 발견 - "이건 공격이야"

로그 분석을 통한 패턴 발견

급하게 로그를 분석한 결과, 특정 해외 IP 대역에서 결제 API 엔드포인트로 향하는 반복적이고 규칙적인 요청 패턴을 발견했습니다.

2025-01-15 15:23:45 [INFO] GET /api/payment/process - IP: 203.0.113.1 - Status: 200
2025-01-15 15:23:45 [INFO] GET /api/payment/process - IP: 203.0.113.2 - Status: 200
2025-01-15 15:23:45 [INFO] GET /api/payment/process - IP: 203.0.113.3 - Status: 200
... (수백 건 반복)

이건 DDoS 공격이었습니다.

실제 공격 상황

당시 Vercel 대시보드에서 확인한 실제 공격 상황입니다:

DDoS 공격 대시보드

DDoS 공격 대시보드

공격 특징:

  • 트래픽 폭증: 평시 대비 20배 이상의 트래픽 증가
  • 최대 TPS: 1,000+ TPS 이상의 비정상적 트래픽
  • 공격 패턴: 특정 해외 IP 대역에서 결제 API 엔드포인트로 집중 공격
  • 영향 범위: 결제 API를 포함한 전체 서비스 응답 시간 급증

즉각적인 대응: Vercel 방화벽 활용

다행히 우리는 Vercel을 사용하고 있었고, Vercel의 내장 방화벽 기능을 통해 빠르게 대응할 수 있었습니다:

1. Vercel 방화벽 설정 (1분 이내)

Vercel 대시보드에서 즉시 방화벽 규칙을 설정했습니다:

  1. Firewall Rules 메뉴 접근
  2. Block 규칙 추가
  3. 악성 IP 대역 차단: 특정 국가 및 IP 대역 즉각 차단
  4. Rate Limiting: 엔드포인트별 요청 제한 설정

Vercel의 장점:

  • 즉시 적용: 설정 변경 후 몇 초 내 반영
  • UI 기반 설정: 코드 수정 없이 대시보드에서 바로 설정
  • 자동 차단: 공격 패턴 감지 시 자동으로 차단

2. Spring Cloud Gateway Rate Limiter (추가 방어)

Vercel 방화벽으로 1차 차단 후, 백엔드 레벨에서도 추가 방어를 구축했습니다:

  • Redis 기반 Rate Limiter: Spring Cloud Gateway 단에 적용
  • 엔드포인트별 제한: 결제 API 등 중요 엔드포인트에 더 엄격한 제한
  • IP 기반 차단: 악성 IP 패턴을 Redis에 저장하여 추가 차단

3. 인프라 자동 확장

  • Cloud Run 자동 스케일링: 트래픽 증가에 따라 자동으로 인스턴스 확장
  • 가용 자원 확보: 공격 트래픽을 처리할 수 있는 충분한 리소스 확보

결과: 15분 내 안정화 완료

Vercel 방화벽의 효과

Vercel을 사용한 덕분에:

  • 빠른 대응: 코드 배포 없이 대시보드에서 즉시 차단 가능
  • 정상 사용자 보호: 공격 트래픽만 차단하고 정상 사용자는 정상 처리
  • 서비스 중단 없음: 공격 기간 동안에도 서비스는 계속 운영

"Vercel의 방화벽 기능 덕분에 빠르게 대응할 수 있었습니다"

하지만 뭔가 아쉬웠다

공격은 막았지만, 뭔가 아쉬웠습니다:

  • 사후 대응: 공격이 발생한 후에야 발견
  • 수동 분석: 로그를 직접 파싱해서 패턴을 찾아야 함
  • 재발 방지: 다음 공격을 미리 감지할 방법이 없음

"다음에는 미리 알아챌 수 있어야 해"

Chapter 3: 해결책 - 모니터링 시스템 구축

왜 모니터링이 필요한가?

DDoS 공격을 겪고 나니, 실시간으로 시스템 상태를 파악할 수 있는 모니터링 시스템이 절실히 필요했습니다:

  1. 실시간 TPS 모니터링: 트래픽이 비정상적으로 증가하는지 즉시 파악
  2. 응답 시간 추적: 특정 엔드포인트가 느려지는지 실시간 확인
  3. 에러율 모니터링: 에러가 급증하는지 즉시 알림
  4. 리소스 사용량: CPU, 메모리 사용량을 실시간으로 확인

"다음 공격이 오면, Grafana 대시보드에서 즉시 알아챌 수 있어야 해"

선택: Prometheus + Grafana

여러 모니터링 솔루션을 검토했지만, Prometheus + Grafana를 선택한 이유:

  • 오픈소스: 비용 부담 없음
  • Spring Boot 통합: Actuator만 추가하면 자동으로 메트릭 수집
  • 강력한 쿼리: PromQL로 복잡한 메트릭 분석 가능
  • 시각화: Grafana로 아름다운 대시보드 구성 가능
  • 알림: 특정 임계값 초과 시 자동 알림 설정 가능

Chapter 4: 구축 과정 - "이제부터가 진짜다"

전체 아키텍처

모니터링 시스템의 전체 구조는 다음과 같습니다:

다이어그램 로딩 중...

핵심 구성 요소

  1. Spring Boot Actuator: 애플리케이션 메트릭 수집
  2. Micrometer: 메트릭 표준화 (Prometheus 형식 지원)
  3. Prometheus: 시계열 데이터베이스 및 수집기
  4. Grafana: 메트릭 시각화 대시보드

"이제 단계별로 구축해보자"

단계별 설정 방법: 실전 가이드

1단계: 의존성 추가

build.gradle.kts:

dependencies {
    // Spring Boot Actuator (메트릭 수집)
    implementation("org.springframework.boot:spring-boot-starter-actuator")
    
    // Micrometer Prometheus (Prometheus 메트릭 노출)
    implementation("io.micrometer:micrometer-registry-prometheus")
}

Maven (pom.xml):

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>
    <dependency>
        <groupId>io.micrometer</groupId>
        <artifactId>micrometer-registry-prometheus</artifactId>
    </dependency>
</dependencies>

2단계: application.properties 설정

application.properties:

# Actuator 엔드포인트 노출 설정
management.endpoints.web.exposure.include=health,info,prometheus,metrics
management.endpoint.health.show-details=when-authorized

# Prometheus 메트릭 수집 활성화
management.prometheus.metrics.export.enabled=true

# 애플리케이션 이름을 메트릭 태그로 추가
management.metrics.tags.application=${spring.application.name}

⚠️ 중요: Spring Boot 3.5부터 설정 키가 변경되었습니다:

  • management.metrics.export.prometheus.enabled (구버전)
  • management.prometheus.metrics.export.enabled (신버전)

3단계: 메트릭 엔드포인트 확인

애플리케이션 실행 후 다음 URL로 접근:

# Prometheus 메트릭 (가장 중요!)
curl http://localhost:8080/actuator/prometheus

# Health Check
curl http://localhost:8080/actuator/health

# 전체 메트릭 목록
curl http://localhost:8080/actuator/metrics

Prometheus 엔드포인트 응답 예시:

# HELP jvm_memory_used_bytes The amount of used memory
# TYPE jvm_memory_used_bytes gauge
jvm_memory_used_bytes{area="heap",id="PS Survivor Space"} 1.048576E7
jvm_memory_used_bytes{area="heap",id="PS Old Gen"} 2.097152E8
jvm_memory_used_bytes{area="heap",id="PS Eden Space"} 1.6777216E8

# HELP http_server_requests_seconds Duration of HTTP server request handling
# TYPE http_server_requests_seconds summary
http_server_requests_seconds_count{method="GET",status="200",uri="/api/users"} 150.0
http_server_requests_seconds_sum{method="GET",status="200",uri="/api/users"} 2.5

4단계: Prometheus 설정

prometheus.yml:

global:
  scrape_interval: 15s
  external_labels:
    cluster: 's-class-platform'
    environment: 'dev'

scrape_configs:
  - job_name: 'api-gateway'
    scrape_interval: 15s
    metrics_path: '/actuator/prometheus'
    static_configs:
      - targets:
          - 'localhost:8080'  # 로컬 개발 환경
        labels:
          service: 'api-gateway'
          environment: 'dev'
  
  - job_name: 'lms-service'
    scrape_interval: 15s
    metrics_path: '/actuator/prometheus'
    static_configs:
      - targets:
          - 'localhost:8085'  # 로컬 개발 환경
        labels:
          service: 'lms-service'
          environment: 'dev'

Docker로 Prometheus 실행:

docker run -d \
  -p 9090:9090 \
  -v $(pwd)/prometheus.yml:/etc/prometheus/prometheus.yml \
  prom/prometheus:latest

5단계: Grafana 대시보드 설정

5.1 Grafana 설치 및 접속

docker run -d \
  -p 3000:3000 \
  --name=grafana \
  -e "GF_SECURITY_ADMIN_PASSWORD=admin" \
  grafana/grafana:latest

접속: http://localhost:3000 (admin/admin)

5.2 Prometheus Data Source 추가

  1. Configuration → Data Sources → Add data source
  2. Prometheus 선택
  3. URL: http://localhost:9090 (Prometheus 서버 주소)
  4. Save & Test 클릭

5.3 주요 메트릭 쿼리 예시

TPS (Transactions Per Second):

rate(http_server_requests_seconds_count[1m])

평균 응답 시간:

rate(http_server_requests_seconds_sum[1m]) / 
rate(http_server_requests_seconds_count[1m])

JVM 힙 메모리 사용량:

jvm_memory_used_bytes{area="heap"}

GC 시간:

rate(jvm_gc_pause_seconds_sum[1m])

서비스별 필터링:

# api-gateway만 필터링
jvm_memory_used_bytes{service="api-gateway", area="heap"}

# lms-service만 필터링
jvm_memory_used_bytes{service="lms-service", area="heap"}

모니터링 가능한 메트릭 종류

JVM 메트릭

  • jvm_memory_used_bytes: 메모리 사용량 (힙, 비힙)
  • jvm_memory_max_bytes: 최대 메모리
  • jvm_gc_pause_seconds: GC 일시 정지 시간
  • jvm_threads_live_threads: 활성 스레드 수
  • jvm_classes_loaded_classes: 로드된 클래스 수

HTTP 메트릭

  • http_server_requests_seconds_count: 요청 수
  • http_server_requests_seconds_sum: 총 응답 시간
  • http_server_requests_seconds_max: 최대 응답 시간
  • http_server_requests_seconds: 응답 시간 분포

데이터베이스 메트릭 (HikariCP)

  • hikari_connections_active: 활성 연결 수
  • hikari_connections_idle: 유휴 연결 수
  • hikari_connections_pending: 대기 중인 연결 수

시스템 메트릭

  • system_cpu_usage: CPU 사용률
  • process_cpu_usage: 프로세스 CPU 사용률
  • system_memory_total_bytes: 전체 메모리
  • system_memory_free_bytes: 사용 가능한 메모리

Cloud Run 배포 시 고려사항

1. Prometheus 설정 (Cloud Run 서비스 URL)

prometheus-config.yaml:

scrape_configs:
  - job_name: 'api-gateway'
    scrape_interval: 15s
    metrics_path: '/actuator/prometheus'
    static_configs:
      - targets:
          - 'api-gateway-452628026107.asia-northeast3.run.app'  # Cloud Run URL
        labels:
          service: 'api-gateway'
          environment: 'dev'
          region: 'asia-northeast3'

2. Cloud Run에 Prometheus 배포

Dockerfile:

FROM prom/prometheus:latest

COPY prometheus-config.yaml /etc/prometheus/prometheus.yml

EXPOSE 9090

배포 스크립트:

#!/bin/bash

GCP_PROJECT_ID="your-project-id"
GCP_REGION="asia-northeast3"
PROMETHEUS_SERVICE_NAME="prometheus"

# 이미지 빌드 및 푸시
gcloud builds submit \
  --tag asia-northeast3-docker.pkg.dev/${GCP_PROJECT_ID}/repo/${PROMETHEUS_SERVICE_NAME}:latest \
  --project=${GCP_PROJECT_ID} \
  --region=${GCP_REGION} \
  .

# Cloud Run에 배포
gcloud run deploy ${PROMETHEUS_SERVICE_NAME} \
  --image=asia-northeast3-docker.pkg.dev/${GCP_PROJECT_ID}/repo/${PROMETHEUS_SERVICE_NAME}:latest \
  --region=${GCP_REGION} \
  --platform=managed \
  --allow-unauthenticated \
  --port=9090 \
  --memory=512Mi \
  --cpu=1 \
  --min-instances=1 \
  --max-instances=3 \
  --project=${GCP_PROJECT_ID}

3. Grafana도 Cloud Run에 배포

Dockerfile:

FROM grafana/grafana:latest

EXPOSE 3000

배포 스크립트:

gcloud run deploy grafana \
  --image=asia-northeast3-docker.pkg.dev/${GCP_PROJECT_ID}/repo/grafana:latest \
  --region=${GCP_REGION} \
  --platform=managed \
  --allow-unauthenticated \
  --port=3000 \
  --memory=512Mi \
  --cpu=1 \
  --min-instances=1 \
  --max-instances=2 \
  --set-env-vars GF_SECURITY_ADMIN_PASSWORD=admin \
  --project=${GCP_PROJECT_ID}

실제 사용 예시: S-Class 플랫폼

아키텍처 다이어그램

Prometheus Architecture

Prometheus Architecture

모니터링 대상 서비스

  1. api-gateway: API Gateway 메트릭 (라우팅, 인증, 부하 분산)
  2. lms-service: LMS 서비스 메트릭 (학생 관리, 수업 세션, AI 기능)

주요 모니터링 지표

API Gateway:

  • Gateway 라우트별 요청 수
  • 인증 실패율
  • 라우트별 응답 시간

LMS Service:

  • 학생 등록 수
  • 수업 세션 생성 수
  • AI 기능 처리 시간 (주제 추천, PPT 생성 등)

Grafana 대시보드 예시

모니터링 시스템을 구축한 후, 다음과 같은 Grafana 대시보드를 구성했습니다:

Grafana 대시보드 - 시스템 개요

Grafana 대시보드 - 시스템 개요

대시보드 구성:

  • Row 1: 시스템 개요 (CPU, 메모리, 스레드)
  • Row 2: HTTP 메트릭 (TPS, 응답 시간, 에러율)
  • Row 3: JVM 메트릭 (힙 메모리, GC 시간)
  • Row 4: 서비스별 메트릭 (api-gateway, lms-service)

JVM 메트릭 상세 모니터링

JVM 성능을 실시간으로 모니터링하여 메모리 누수나 GC 문제를 조기에 발견할 수 있습니다:

JVM 메트릭 상세

JVM 메트릭 상세

주요 지표:

  • 힙 메모리 사용량: Old Gen, Eden Space, Survivor Space별 모니터링
  • GC 시간: GC 일시 정지 시간 추적
  • 스레드 수: 활성 스레드 수 모니터링

HTTP 메트릭 및 응답 시간 분석

API 엔드포인트별 요청 수와 응답 시간을 실시간으로 추적합니다:

HTTP 메트릭 분석

HTTP 메트릭 분석

주요 지표:

  • TPS (Transactions Per Second): 초당 요청 수
  • 평균 응답 시간: 엔드포인트별 응답 시간
  • 에러율: 4xx, 5xx 에러 비율
  • 상위 엔드포인트: 가장 많은 요청을 받는 엔드포인트 식별

Prometheus Targets 상태 확인

Prometheus가 정상적으로 메트릭을 수집하고 있는지 확인합니다:

Prometheus Targets

Prometheus Targets

확인 사항:

  • Target 상태: UP/DOWN 상태 확인
  • 마지막 스크랩 시간: 최근 메트릭 수집 시간
  • 스크랩 지속 시간: 메트릭 수집에 걸린 시간
  • 에러 메시지: 수집 실패 시 에러 원인 확인

서비스별 상세 메트릭

각 마이크로서비스(api-gateway, lms-service)별로 상세 메트릭을 모니터링합니다:

서비스별 메트릭

서비스별 메트릭

서비스별 주요 지표:

  • api-gateway: 라우팅, 인증, 부하 분산 메트릭
  • lms-service: 학생 관리, 수업 세션, AI 기능 메트릭

커스텀 메트릭 추가하기

비즈니스 메트릭을 추가하려면 MeterRegistry를 주입받아 사용합니다:

@Service
class OrderService(
    private val meterRegistry: MeterRegistry
) {
    
    private val orderCounter = Counter.builder("orders.total")
        .description("Total number of orders")
        .tag("status", "created")
        .register(meterRegistry)
    
    private val orderAmountGauge = Gauge.builder("orders.amount")
        .description("Total order amount")
        .register(meterRegistry) { getTotalOrderAmount() }
    
    fun createOrder(order: Order) {
        // 주문 생성 로직
        orderCounter.increment()
    }
}

트러블슈팅

1. 메트릭이 노출되지 않는 경우

확인 사항:

  • Actuator 의존성이 추가되었는지 확인
  • management.endpoints.web.exposure.includeprometheus가 포함되어 있는지 확인
  • management.prometheus.metrics.export.enabled=true 설정 확인

2. Spring Boot 3.5 설정 키 변경

Spring Boot 3.5부터 설정 키가 변경되었습니다:

# ❌ 구버전 (Spring Boot 3.4 이하)
management.metrics.export.prometheus.enabled=true

# ✅ 신버전 (Spring Boot 3.5 이상)
management.prometheus.metrics.export.enabled=true

3. Prometheus가 메트릭을 수집하지 않는 경우

확인 사항:

  • Prometheus 설정 파일의 targets URL이 올바른지 확인
  • 애플리케이션이 실행 중이고 /actuator/prometheus 엔드포인트가 접근 가능한지 확인
  • Prometheus UI에서 Targets 상태 확인: http://localhost:9090/targets

Chapter 5: 결과 - "이제 모든 게 보인다"

모니터링 시스템 구축 후

모니터링 시스템을 구축한 후, 우리는 다음과 같은 변화를 경험했습니다:

1. 실시간 가시성 확보

이전:

  • "서비스가 느린 것 같은데... 로그를 확인해봐야겠다"
  • 로그 파싱 → 패턴 분석 → 원인 추론 (10-15분 소요)

이후:

  • Grafana 대시보드만 보면 즉시 파악 가능
  • "아, TPS가 1,000을 넘었네. 이건 공격이야"
  • 1분 이내 문제 인지

2. 선제적 대응 가능

이전:

  • 공격이 발생한 후에야 발견
  • 수동으로 로그 분석해서 패턴 찾기

이후:

  • TPS가 평시 대비 3배 이상 증가하면 즉시 알림
  • 특정 엔드포인트의 응답 시간이 1초를 넘으면 알림
  • 공격이 시작되기 전에 미리 감지 가능

3. 데이터 기반 의사결정

이전:

  • "느린 것 같은데... 서버를 늘려야 하나?"
  • 추측 기반 의사결정

이후:

  • "메모리 사용률이 80%를 넘었네. 확장이 필요해"
  • 실제 메트릭 기반 의사결정

실제 사례: 두 번째 공격

몇 주 후, 비슷한 패턴의 공격이 다시 발생했습니다.

하지만 이번에는 달랐습니다:

  1. Grafana 알림: TPS가 500을 넘는 순간 Slack 알림 발송
  2. 즉시 대응:
    • Vercel 방화벽에서 즉시 IP 차단 (1분 이내)
    • Grafana 대시보드에서 공격 패턴 실시간 확인
    • Spring Cloud Gateway Rate Limiter로 추가 방어
  3. 실시간 모니터링: Grafana 대시보드에서 공격 패턴 실시간 확인
  4. 빠른 해결: 5분 이내 안정화 완료

"이제 우리는 눈이 생겼다"

다층 방어 체계

이제 우리는 다층 방어 체계를 구축했습니다:

[공격 트래픽]
    ↓
[1차: Vercel 방화벽] ← 즉시 차단 (UI 기반, 코드 배포 불필요)
    ↓ (일부 우회)
[2차: Spring Cloud Gateway Rate Limiter] ← Redis 기반 추가 차단
    ↓ (일부 우회)
[3차: Prometheus + Grafana 모니터링] ← 실시간 감지 및 알림
    ↓
[정상 트래픽만 통과]

각 레이어의 역할:

  • Vercel 방화벽: 가장 빠른 1차 차단, UI 기반 즉시 설정
  • Rate Limiter: 애플리케이션 레벨 추가 방어
  • 모니터링: 공격 패턴 실시간 감지 및 알림

마무리: 모니터링의 가치

왜 모니터링이 중요한가?

DDoS 공격을 겪고 나니, 모니터링의 가치를 절실히 느꼈습니다:

  1. 장애 예방: 문제가 발생하기 전에 미리 감지
  2. 빠른 대응: 문제 발생 시 즉시 원인 파악 및 해결
  3. 데이터 기반 의사결정: 추측이 아닌 실제 메트릭 기반 판단
  4. 팀 신뢰: "서비스가 잘 돌아가고 있어요"라는 확신

Chapter 6: 앞으로의 개선 방향

모니터링 시스템을 구축한 후, 현재 상태를 분석하고 앞으로 개선할 점들을 정리했습니다.

현재 상태 분석

현재 모니터링 상태

현재 모니터링 상태

현재 구축된 것:

  • ✅ Prometheus + Grafana 기본 모니터링
  • ✅ JVM, HTTP, 시스템 메트릭 수집
  • ✅ 실시간 대시보드 구성
  • ✅ DDoS 공격 감지 및 대응 체계

하지만 아직 부족한 것:

  • ❌ 자동 알림 시스템 (Slack/Email)
  • ❌ 비즈니스 메트릭 (주문 수, 결제 성공률 등)
  • ❌ 분산 추적 (Distributed Tracing)
  • ❌ 로그 통합 (ELK Stack 등)

개선 방향 1: 자동 알림 시스템 구축

현재 문제점:

  • Grafana 대시보드를 직접 확인해야만 문제를 인지
  • 공격이나 장애 발생 시 즉시 알림 받기 어려움

개선 계획:

  1. Grafana Alerting 설정

    • TPS가 평시 대비 3배 이상 증가 시 Slack 알림
    • 에러율이 5%를 넘으면 즉시 알림
    • 메모리 사용률이 90%를 넘으면 알림
    • 응답 시간이 1초를 넘으면 알림
  2. Alerting Rule 예시:

    groups:
      - name: s-class-alerts
        rules:
          - alert: HighTPS
            expr: rate(http_server_requests_seconds_count[5m]) > 500
            for: 2m
            annotations:
              summary: "높은 TPS 감지"
              description: "TPS가 500을 초과했습니다. DDoS 공격 가능성 확인 필요"
          
          - alert: HighErrorRate
            expr: rate(http_server_requests_seconds_count{status=~"5.."}[5m]) / rate(http_server_requests_seconds_count[5m]) > 0.05
            for: 1m
            annotations:
              summary: "높은 에러율 감지"
              description: "에러율이 5%를 초과했습니다"
  3. Slack 연동:

    • Grafana Alerting → Slack Webhook 연동
    • 알림 메시지에 대시보드 링크 포함
    • 심각도별 채널 분리 (Critical, Warning, Info)

예상 효과:

  • 문제 인지 시간: 15분 → 1분 이내
  • 수동 모니터링 시간: 80% 감소
  • 장애 대응 속도: 2배 향상

개선 방향 2: 비즈니스 메트릭 추가

현재 문제점:

  • 기술적 메트릭만 수집 (JVM, HTTP 등)
  • 비즈니스 지표(주문 수, 결제 성공률 등)는 별도로 확인 필요

개선 계획:

  1. 커스텀 메트릭 추가:

    @Service
    class PaymentService(
        private val meterRegistry: MeterRegistry
    ) {
        private val paymentCounter = Counter.builder("payments.total")
            .description("Total number of payments")
            .tag("status", "success")
            .register(meterRegistry)
        
        private val paymentAmountGauge = Gauge.builder("payments.amount")
            .description("Total payment amount")
            .register(meterRegistry) { getTotalPaymentAmount() }
        
        fun processPayment(payment: Payment) {
            // 결제 처리 로직
            if (payment.isSuccess()) {
                paymentCounter.increment(
                    Tags.of("status", "success", "pg", payment.pgName)
                )
            } else {
                paymentCounter.increment(
                    Tags.of("status", "failed", "pg", payment.pgName)
                )
            }
        }
    }
  2. 비즈니스 대시보드 구성:

    • 주문 수 추이
    • 결제 성공률 (PG사별)
    • 쿠폰 발급 수
    • 사용자 활성도

예상 효과:

  • 비즈니스 지표 실시간 파악
  • PG사별 성공률 비교 분석
  • 프로모션 효과 즉시 확인

개선 방향 3: 분산 추적 (Distributed Tracing) 도입

현재 문제점:

  • 마이크로서비스 간 호출 추적 어려움
  • 느린 요청의 원인 파악이 어려움
  • 서비스 간 의존성 파악 어려움

개선 계획:

  1. OpenTelemetry 도입:

    • Spring Cloud Sleuth → OpenTelemetry 마이그레이션
    • Jaeger 또는 Zipkin으로 추적 데이터 수집
    • Grafana Tempo로 통합 (Prometheus + Tempo)
  2. 추적 가능한 정보:

    • 요청이 거쳐간 모든 서비스
    • 각 서비스에서 소요된 시간
    • 서비스 간 호출 관계
    • 느린 요청의 병목 지점

예상 효과:

  • 느린 요청 원인 파악 시간: 30분 → 5분
  • 서비스 간 의존성 시각화
  • 성능 최적화 포인트 명확화

개선 방향 4: 로그 통합 및 분석

현재 문제점:

  • 각 서비스의 로그를 개별적으로 확인
  • 로그 기반 분석이 어려움
  • 에러 로그 추적이 비효율적

개선 계획:

  1. ELK Stack 또는 Loki 도입:

    • Elasticsearch + Logstash + Kibana
    • 또는 Grafana Loki (Prometheus와 통합 용이)
  2. 로그 수집 및 분석:

    • 모든 서비스 로그를 중앙 집중식으로 수집
    • 로그 기반 알림 설정
    • 에러 로그 자동 분석
  3. Prometheus + Loki 통합:

    • Grafana에서 메트릭과 로그를 동시에 확인
    • 특정 메트릭 이상 시 관련 로그 자동 조회

예상 효과:

  • 로그 분석 시간: 50% 감소
  • 에러 원인 파악 속도: 3배 향상
  • 로그 기반 인사이트 도출

개선 방향 5: AI 기반 이상 탐지

장기 계획:

  1. Anomaly Detection:

    • 정상 패턴 학습
    • 비정상 패턴 자동 감지
    • DDoS 공격 자동 차단
  2. 예측 분석:

    • 트래픽 예측
    • 리소스 사용량 예측
    • 장애 예측

개선 로드맵

Phase 1 (1개월):

  • ✅ 자동 알림 시스템 구축 (Slack 연동)
  • ✅ 비즈니스 메트릭 추가

Phase 2 (2-3개월):

  • ✅ 분산 추적 도입 (OpenTelemetry)
  • ✅ 로그 통합 (Grafana Loki)

Phase 3 (6개월):

  • ✅ AI 기반 이상 탐지
  • ✅ 자동 스케일링 정책 고도화

다음 단계

모니터링 시스템을 구축한 후, 다음 단계를 고려해볼 수 있습니다:

  • 알림 설정: 특정 임계값 초과 시 Slack/Email 알림
  • 대시보드 최적화: 팀이 자주 보는 메트릭 위주로 구성
  • 메트릭 태깅: 서비스, 환경, 인스턴스별로 태그 추가
  • 커스텀 메트릭: 비즈니스 로직에 맞는 커스텀 메트릭 추가 (주문 수, 결제 성공률 등)

교훈

"장애는 예방하는 것이 가장 좋지만, 발생했을 때 빠르게 대응하는 것도 중요하다"

모니터링 시스템을 구축하면서, 우리는 단순히 "서비스가 잘 돌아가고 있는지" 확인하는 것을 넘어, 서비스가 왜 잘 돌아가지 않는지를 즉시 파악할 수 있게 되었습니다.

다음 공격이 와도, 우리는 준비되어 있습니다.

마무리: 모니터링의 진화

우리가 배운 것

  1. 모니터링은 필수다

    • 로그만으로는 부족하다
    • 실시간 메트릭이 있어야 빠른 대응이 가능하다
    • 시각화된 데이터가 의사결정을 돕는다
  2. 다층 방어 체계의 중요성

    • Vercel 방화벽 (1차 차단)
    • Rate Limiter (2차 방어)
    • 모니터링 (3차 감지 및 알림)
  3. 지속적인 개선

    • 모니터링 시스템도 계속 발전시켜야 한다
    • 비즈니스 요구사항에 맞춰 메트릭을 추가해야 한다
    • 자동화를 통해 운영 부담을 줄여야 한다

앞으로의 여정

모니터링 시스템 구축은 끝이 아니라 시작입니다. 앞으로도:

  • 알림 시스템 구축: 자동화된 알림으로 더 빠른 대응
  • 비즈니스 메트릭 추가: 기술적 메트릭을 넘어 비즈니스 인사이트 도출
  • 분산 추적 도입: 마이크로서비스 환경에서의 완전한 가시성 확보
  • AI 기반 분석: 이상 탐지 및 예측 분석으로 선제적 대응

"모니터링은 한 번 구축하고 끝나는 것이 아니라, 지속적으로 발전시켜야 하는 시스템입니다."


다음 글에서는 Grafana Alerting 설정과 Slack 연동, 그리고 비즈니스 메트릭 추가 방법에 대해 더 자세히 다뤄보겠습니다.

참고 자료

댓글

?