Skip to content

TIL -2025-05-26 [Spring Actuator 기반 Promql, Grafana 시각화용 추천 PromQL, Spring Boot + Prometheus + Alertmanager + Slack 연동 + 부하 테스트 자동화 예제, Grafana 실습] #75

@soheeGit

Description

@soheeGit

📌 Spring Boot Actuator + Micrometer에서 Prometheus와 Grafana로 시각화할 때 실무에서 자주 쓰이는 PromQL 쿼리

1. HTTP 요청 수

sum(rate(http_server_requests_seconds_count[1m])) by (method, status)
  • 최근 1분간의 요청 수를 초당 비율로 집계
  • method, status 별 분류 가능 (GET, POST, 200, 500 등)
  • 트래픽 모니터링, API 사용량 파악에 유용

2. HTTP 요청 평균 응답 시간

sum(rate(http_server_requests_seconds_sum[1m])) by (uri) 
/ 
sum(rate(http_server_requests_seconds_count[1m])) by (uri)
  • 요청별 평균 응답 시간 (초)
  • uri 경로별로 집계 가능
  • 특정 API가 느린지 확인할 때 사용

3. JVM Heap 메모리 사용량

jvm_memory_used_bytes{area="heap"} 
/
jvm_memory_max_bytes{area="heap"}
  • JVM 힙 사용률 (0.0 ~ 1.0 사이)
  • 메모리 누수나 과도한 GC를 감지할 수 있음

4. 활성 스레드 수 (JVM Thread)

jvm_threads_live_threads
  • 현재 활성화된 JVM 스레드 개수
  • 스레드 누수나 고부하 감지에 사용

5. 애플리케이션 가용성 (UP 여부)

up{job="spring-app"}
  • Prometheus에서 수집 가능한지 여부
  • 0이면 애플리케이션이 죽었거나 scrape 실패한 것

📌 Grafana 시각화용 추천 PromQL

카테고리 PromQL 설명 추천 차트
① HTTP 요청 수 sum(rate(http_server_requests_seconds_count[1m])) by (uri) URI별 초당 요청 수 Bar chart, Time series (Lines)
② HTTP 응답 시간 sum(rate(http_server_requests_seconds_sum[1m])) by (uri) / sum(rate(http_server_requests_seconds_count[1m])) by (uri) URI별 평균 응답 시간 (초) Time series, Heatmap
③ JVM 힙 메모리 사용률 jvm_memory_used_bytes{area="heap"} / jvm_memory_max_bytes{area="heap"} 힙 사용률 (0.0~1.0) Gauge, Time series
④ CPU 사용률 (시스템 전체) 100 - (avg by (instance)(irate(node_cpu_seconds_total{mode="idle"}[1m])) * 100) 노드 전체 CPU 사용률 (%) Time series, Stat panel
⑤ 애플리케이션 상태 up{job="spring-app"} 1: 정상, 0: 다운 Single stat, Table, Status panel

📌 Spring Boot + Prometheus + Alertmanager + Slack 연동 + 부하 테스트 자동화 예제

1. Prometheus 설정 (prometheus.yml)

global:
  scrape_interval: 5s

rule_files:
  - "alert.rules.yml"

scrape_configs:
  - job_name: 'spring-local'
    metrics_path: '/actuator/prometheus'
    static_configs:
      - targets: ['host.docker.internal:8080']
      # - targets: ['app:8080']

alerting:
  alertmanagers:
    - static_configs:
        - targets: ['host.docker.internal:9093']
  • 5초마다 /actuator/prometheus에서 메트릭 수집
  • alert.rules.yml에 정의된 조건 충족 시 AlertManager(9093)로 알림 발송

2. 알림 조건 정의 (alert.rules.yml)

groups:
  - name: example
    rules:
      - alert: HighRequestRate
        expr: rate(http_server_requests_seconds_count[10s]) > 10
        for: 10s
        labels:
          severity: warning
        annotations:
          summary: "Request rate high"
  • 최근 10초 동안 요청 수가 초당 10건을 초과하면 HighRequestRate 알림 발생
  • 10초간 조건이 유지돼야 알림 전송
  • summary는 Slack에 전달되는 메시지 내용

3. AlertManager 설정 (alertmanager.yml)

route:
  receiver: 'slack-notifications'

receivers:
  - name: 'slack-notifications'
    slack_configs:
      - text: "{{ .CommonAnnotations.summary }}"
        # text: "일어나라!"
        api_url: 'https://hooks.slack.com/services/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'
        channel: 'alert'
        send_resolved: true
  • slack-notifications 수신기로 알림 전송
  • Slack Webhook API를 통해 #alert 채널로 전송
  • 알림 해제(resolved) 시에도 메시지 전송

4. 부하 테스트 스크립트 (test.sh)

#!/bin/bash

# --- 설정 ---
URL="http://localhost:8080/200"  # 테스트할 URL을 입력하세요.
TOTAL_REQUESTS=100000                           # 보낼 총 요청 수를 입력하세요.
CONCURRENT_USERS=5                           # 동시에 실행할 사용자(프로세스) 수를 입력하세요.
OUTPUT_FILE="load_test_results.log"           # 결과(HTTP 상태 코드)를 저장할 파일 이름
# ------------

# 변수 초기화
success_count=0
fail_count=0
request_count=0
pids=() # 백그라운드 프로세스 ID 저장 배열

# 이전 로그 파일 삭제 (선택 사항)
> "$OUTPUT_FILE"

echo "🚀 부하 테스트 시작..."
echo "-----------------------------------"
echo "대상 URL: $URL"
echo "총 요청 수: $TOTAL_REQUESTS"
echo "동시 사용자 수: $CONCURRENT_USERS"
echo "-----------------------------------"

start_time=$(date +%s)

# 요청을 보내는 함수
function send_request {
    local url=$1
    # curl: -s (silent), -o /dev/null (출력 버리기), -w "%{http_code}" (HTTP 상태 코드만 출력)
    http_code=$(curl -s -o /dev/null -w "%{http_code}" "$url")
    echo "$http_code" >> "$OUTPUT_FILE" # 파일에 상태 코드 기록
}

# 총 요청 수에 도달할 때까지 반복
while [ $request_count -lt $TOTAL_REQUESTS ]; do
    # 현재 실행 중인 백그라운드 작업 수 확인
    current_jobs=$(jobs -p | wc -l)

    # 설정된 동시 사용자 수보다 적게 실행 중이고, 총 요청 수에 도달하지 않았다면
    while [ $current_jobs -lt $CONCURRENT_USERS ] && [ $request_count -lt $TOTAL_REQUESTS ]; do
        send_request "$URL" & # 함수를 백그라운드로 실행
        pids+=($!)           # 백그라운드 프로세스 ID 저장
        request_count=$((request_count + 1))
        current_jobs=$(jobs -p | wc -l)
        # 진행 상황 표시 ( \r 을 사용하여 같은 줄에 덮어씀)
        echo -ne "요청 보냄: $request_count / $TOTAL_REQUESTS | 현재 동시 요청: $current_jobs \r"
    done

    # 동시 사용자 수에 도달했다면, 백그라운드 작업 중 하나가 끝날 때까지 기다림
    # -n 옵션: 실행 중인 작업 중 아무거나 하나가 종료되면 즉시 반환
    if [ $current_jobs -ge $CONCURRENT_USERS ]; then
        wait -n
    fi

    # 종료된 프로세스 ID 목록에서 제거 (선택 사항, 더 정확한 관리를 위해)
    # 실제로는 wait -n이 하나씩 처리하므로 이 부분은 단순화 가능
done

# 남아있는 모든 백그라운드 작업이 끝날 때까지 기다림
wait
echo -e "\n-----------------------------------" # 줄바꿈 후 구분선

end_time=$(date +%s)
duration=$((end_time - start_time))

echo "⏳ 모든 요청 완료. 결과 집계 중..."

# 결과 파일 분석
while read -r code; do
    if [[ $code -ge 200 && $code -lt 400 ]]; then
        success_count=$((success_count + 1))
    else
        fail_count=$((fail_count + 1))
    fi
done < "$OUTPUT_FILE"

echo "✅ 부하 테스트 종료."
echo "-----------------------------------"
echo "총 요청 수: $TOTAL_REQUESTS"
echo "성공 요청: $success_count"
echo "실패 요청: $fail_count"
echo "총 소요 시간: $duration"

if [ $duration -gt 0 ]; then
    # bc 계산기를 사용하여 초당 요청 수(RPS) 계산 (소수점 둘째 자리까지)
    rps=$(echo "scale=2; $TOTAL_REQUESTS / $duration" | bc)
    echo "초당 요청 수 (RPS): $rps"
else
    echo "소요 시간이 너무 짧아 RPS를 계산할 수 없습니다."
fi
echo "-----------------------------------"
echo "상세 결과(HTTP 상태 코드)는 $OUTPUT_FILE 파일을 확인하세요."
  • 10만 건의 HTTP 요청을 5개의 프로세스로 병렬 전송
  • 응답 코드별로 성공/실패 카운팅
  • 실행 시간 측정 및 초당 요청 수(RPS) 계산
  • Slack 알림 트리거 실습용으로 매우 유용

5. 컨테이너 실행 명령어

# Prometheus 컨테이너 실행
docker run -d \
  -p 9090:9090 \
  -v $(pwd)/prometheus.yml:/etc/prometheus/prometheus.yml \
  -v $(pwd)/alert.rules.yml:/etc/prometheus/alert.rules.yml \
  --name prometheus \
  prom/prometheus:latest

# Alertmanager 컨테이너 실행
docker run -d \
  -p 9093:9093 \
  -v $(pwd)/alertmanager.yml:/etc/alertmanager/alertmanager.yml \
  --name alertmanager \
  prom/alertmanager:latest

# 부하 테스트 실행
sh test.sh

# docker rm -f prometheus
# docker restart prometheus
# localhost:9090

# docker rm -f alertmanager
# docker restart alertmanager
# localhost:9093

6. 실습 결과 스크린샷

Image Image Image Image

📌 Grafana 실습 – Prometheus 기반 모니터링 대시보드 구축

1. Grafana 컨테이너 실행

docker run -d -p 3000:3000 grafana/grafana
  • 실행 후 웹 브라우저에서 접속: http://localhost:3000/login
  • 초기 로그인 정보:
    • ID: admin
    • PW: admin (로그인 후 반드시 비밀번호 변경)
Image Image

2. Prometheus 데이터 소스 연결

  • 경로

    • 왼쪽 사이드바 하단 → Connections 클릭 → Data sources → Add data source 선택
  • Prometheus 설정

    • Prometheus 선택 후, 아래처럼 설정
항목
URL http://host.docker.internal:9090
Access Server (default)
Save & Test 클릭하여 연결 테스트
Image Image

3. 대시보드 생성 및 시각화

  • 대시보드 생성
    • 상단 메뉴에서 Dashboard 클릭 → + New → Add visualization
Image
  • 데이터 소스 선택
    • Prometheus 선택
Image
  • 예시 메트릭
    • 메트릭 입력창에 PromQL을 입력 (예: HTTP 요청 수)
rate(http_server_requests_seconds_count[1m])
Image

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions