infra
Platform

모듈 맵

[Infra Ops] 애플리케이션 성능 모니터링과 대시보드 구성

0 / 52 완료

펼치기
0 / 52 완료0%

인프라 운영 & SRE · 45 / 52

[Infra Ops] 애플리케이션 성능 모니터링과 대시보드 구성

Pinpoint/Dynatrace APM 개념, JMX Exporter로 Prometheus 연동, Grafana 대시보드 구성, 알람 설정까지 — 장애를 사전에 감지하는 모니터링 실무

🚨INCIDENT ALERT
HIGH

서비스가 왜 느린지 팀에서 원인을 못 찾고 있습니다. CPU는 70%대, 메모리도 여유 있는데 응답 시간이 2~3초가 나옵니다. topfree로는 더 이상 파악이 안 됩니다.

APM(Application Performance Monitoring)이 있었다면 "특정 API의 DB 쿼리가 1.8초"라고 바로 짚어줬을 것입니다. 그리고 Prometheus + Grafana가 있었다면 JVM Heap이 배포 직후부터 서서히 올라가는 트렌드를 그래프로 볼 수 있었을 것입니다. 이 모듈은 그 관찰력을 실무에서 구현하는 방법을 다룹니다.

이번 챕터에서 배울 것
  • 1APM과 인프라 모니터링의 차이를 설명하고 어떤 상황에 APM이 필요한지 판단할 수 있다
  • 2Pinpoint, Jennifer, Dynatrace의 특징과 사용 환경을 구분할 수 있다
  • 3JMX Exporter를 Tomcat에 붙여 Prometheus가 JVM 메트릭을 수집하도록 구성할 수 있다
  • 4Prometheus scrape_config를 작성하고 target 상태를 확인할 수 있다
  • 5Grafana에서 JVM Heap/GC 패널을 구성하고 alert rule을 설정할 수 있다

APM 개념

💡개념

인프라 모니터링만으로는 부족한 이유

인프라 모니터링(CPU, 메모리, 디스크)은 "서버가 힘들다"는 신호는 줍니다. 하지만 "왜 힘든지", "어느 코드가 원인인지"는 알 수 없습니다. APM은 그 공백을 채웁니다.

APM이 할 수 있는 것:

  • 특정 HTTP 요청의 전체 처리 시간 측정
  • 요청 안에서 어떤 메서드, 어떤 DB 쿼리가 시간을 먹는지 추적
  • 느린 쿼리 Top 10을 자동으로 정렬
  • 서비스 간 호출 관계(Service Map) 시각화
  • 에러 발생 시 스택트레이스를 포함한 전체 컨텍스트 저장

APM 없이 장애를 찾는 현실:

"서비스 느림" 신고
→ top, free, df 확인 → 정상
→ 로그에서 Exception 검색
→ 느린 API가 어딘지 추측
→ 코드 리뷰 시작
→ 30분 경과

APM 있을 때:

"서비스 느림" 신고
→ APM 트랜잭션 목록 열기
→ /api/orders GET 평균 2.1초
→ 내부에서 DB 쿼리 1.8초
→ 해당 쿼리 즉시 확인
→ 5분 경과
💡개념

요청 하나가 어떻게 트레이스가 되나 — 계측에서 병목 시각화까지

APM이 "이 API의 DB 쿼리가 1.8초"라고 짚어주는 건 마법이 아닙니다. 앱에 심은 계측이 요청 하나를 구간별로 쪼개 시간을 재고, 그 조각(스팬)을 모아 하나의 트레이스로 잇기 때문입니다. 이 흐름을 알면 "왜 이 구간이 트레이스에 안 보이지", "APM을 켰더니 왜 느려졌지"를 어느 단계의 문제인지로 좁힐 수 있습니다.

TEXT
[요청 도착]  GET /api/orders
   │
   ① 계측 삽입      -javaagent · SDK가 프레임워크 · 드라이버에 훅
   │
   ② 트랜잭션 시작   요청 진입에 trace id · 루트 스팬 발급
   │
   ③ 스팬 기록       메서드 · DB 쿼리 · 외부 호출 구간의 시작 · 끝 시각
   │
   ④ context 전파    trace id를 HTTP 헤더로 다음 서비스에 넘김
   │
   ⑤ 수집 · 집계     스팬을 수집 서버로 전송 → 하나의 트레이스로 조립
   ▼
⑥ 시각화  scatter(응답 분포) · call tree(구간별 시간) · service map

각 단계가 하는 일과, 막혔을 때의 증상:

단계하는 일여기서 막히면
① 계측 삽입에이전트가 바이트코드 · 라이브러리에 훅계측 안 된 구간은 트레이스에 안 뜸(직접 계측 필요)
② 트랜잭션 시작진입점에 trace id · 루트 스팬 발급진입점 미계측이면 요청 자체가 안 잡힘
③ 스팬 기록각 구간의 시작 · 끝 시각 기록비동기 · 스레드 경계에서 context 끊기면 트레이스 단절
④ 전파traceparent 헤더로 다음 서비스에 넘김헤더 유실=분산 트레이스가 서비스별로 쪼개짐
⑤ 수집 · 집계스팬 전송 · 트레이스 조립 · 저장샘플링률 낮으면 느린 요청이 표본에서 빠짐 · 100% 수집이면 오버헤드 · 비용↑
⑥ 시각화느린 트랜잭션 · 병목 스팬 드릴다운버킷 · 집계가 거칠면 느린 소수(꼬리)가 평균에 묻힘

"서버는 멀쩡한데 왜 느린가"에 APM이 답하는 건 ③에서 구간마다 시간을 따로 재기 때문입니다. 그래서 트레이스가 비면 대개 ①계측 누락, 끊기면 ③·④의 context 전파 문제이고, APM을 켠 뒤 앱이 느려졌다면 ⑤샘플링 · 오버헤드를 먼저 의심합니다. 이 계측 · 트레이스 축은 뒤에서 다루는 JMX Exporter+Prometheus(메트릭 축)와 상보적입니다 — 메트릭은 "무엇이 얼마나", 트레이스는 "한 요청이 어디서" 느린지를 봅니다.

💡개념

주요 APM 솔루션 비교

APM 솔루션은 오픈소스 자체 호스팅부터 글로벌 SaaS 유료 서비스까지 범위가 넓어, 환경과 예산에 맞지 않는 선택을 하면 도입 후 운영 비용이나 유지 관리 부담이 기대를 초과하는 경우가 많습니다. 국내 공공·금융 환경에서는 규제 리포팅을 지원하는 상용 솔루션이 필요한 반면, 스타트업이나 온프레미스 팀에서는 무료 오픈소스로도 충분히 트랜잭션 추적이 가능합니다. 각 솔루션의 적합 환경과 핵심 특징을 파악해두면 "APM 도입" 논의가 나왔을 때 근거 있는 선택을 빠르게 제안할 수 있습니다.

APM 솔루션 비교 — 오픈소스 자체 호스팅(Pinpoint·Elastic APM, 무료·운영 부담)부터 상용 SaaS(Datadog·New Relic, 편리·비용)까지 범위가 넓음. 공공·금융은 규제 리포팅 지원 상용, 스타트업·온프레미스는 오픈소스가 적합 — 환경·예산·규제로 선택확대

팀장이 "APM 하나 도입해보자"고 했습니다. 구글에서 검색하면 Pinpoint, New Relic, Datadog, Dynatrace가 나옵니다. 오픈소스와 유료 SaaS의 차이도, 자바 전용과 멀티언어 지원의 차이도 처음에는 구분이 안 됩니다. 환경에 맞지 않는 APM을 도입하면 운영 비용이 기대 이상으로 들거나, 설치는 했는데 실제로 아무도 보지 않는 대시보드가 됩니다. 주요 솔루션의 특성을 파악해야 상황에 맞는 선택을 할 수 있습니다.

Pinpoint (오픈소스, 네이버 개발):

국내에서 가장 널리 쓰이는 무료 APM입니다. Java 에이전트를 Tomcat/Spring Boot JVM에 붙이면, 트랜잭션이 HBase에 저장되고 Web UI에서 Scatter Chart(응답시간 분포)와 Call Tree(메서드 추적)를 확인할 수 있습니다.

로컬 터미널
# Pinpoint Agent 설정 (Tomcat JAVA_OPTS에 추가)
# /opt/tomcat/bin/setenv.sh
JAVA_OPTS="$JAVA_OPTS -javaagent:/opt/pinpoint-agent/pinpoint-bootstrap.jar"
JAVA_OPTS="$JAVA_OPTS -Dpinpoint.agentId=was01"
JAVA_OPTS="$JAVA_OPTS -Dpinpoint.applicationName=my-service"
JAVA_OPTS="$JAVA_OPTS -Dpinpoint.collector.ip=pinpoint-collector-host"

Jennifer (제니퍼소프트, 국내 기업 필수):

금융, 공공기관, 대기업에서 가장 많이 보이는 상용 APM입니다. 실시간 트랜잭션 히트맵, 액티브 서비스 현황, 서버 자원을 통합 화면에서 보여줘, 운영팀이 대시보드 한 화면으로 전체 상황을 파악합니다. 국내 규제 환경에 맞는 리포팅 기능이 포함됩니다.

Dynatrace / New Relic (글로벌 SaaS APM):

에이전트 설치 후 자동으로 서비스 맵을 생성하고, ML 기반으로 이상 징후를 탐지합니다. 글로벌 SaaS 서비스나 MSA 환경에서 주로 선택합니다. 비용이 높지만 설치와 유지 관리가 단순합니다.

솔루션비용적합 환경특징
Pinpoint무료온프레미스, Java국내 오픈소스, HBase 필요
Jennifer유료국내 금융/공공한국 규제 리포팅, UI 직관적
DynatraceSaaS 과금글로벌, MSAAI 이상 탐지, 자동 서비스 맵
New RelicSaaS 과금스타트업~중견설정 최소, 다양한 언어 지원

JMX Exporter + Prometheus 연동

💡개념

JVM 메트릭을 Prometheus로 가져오는 방법

Grafana 대시보드에서 "Tomcat JVM 메모리를 보고 싶다"는 요구가 생겼습니다. 이미 Prometheus는 서버 OS 메트릭을 수집하고 있는데, JVM 내부 Heap과 GC 정보는 보이지 않습니다. JVM은 JMX라는 자체 관리 인터페이스로 내부 상태를 노출하는데, Prometheus는 이 형식을 직접 읽지 못합니다. JMX Exporter가 변환 다리 역할을 합니다. 설정 파일 하나와 JVM 시작 옵션 한 줄이 전부입니다.

Prometheus는 HTTP /metrics 엔드포인트에서 텍스트 형식 메트릭을 pull합니다. JVM은 JMX(Java Management Extensions)로 내부 상태를 노출합니다. 두 형식이 달라 JMX Exporter가 변환 역할을 합니다.

JMX Exporter는 Java 에이전트(-javaagent)로 동작해 JVM 내부 MBean 값을 HTTP로 노출합니다.

YAML
# /opt/jmx_exporter/config.yml
# 모든 MBean 수집 (기본 설정)
rules:
- pattern: ".*"
로컬 터미널
# /opt/tomcat/bin/setenv.sh — Tomcat 시작 시 JAVA_OPTS에 추가
JAVA_OPTS="$JAVA_OPTS -javaagent:/opt/jmx_exporter/jmx_prometheus_javaagent.jar=9090:/opt/jmx_exporter/config.yml"

9090 포트로 메트릭이 노출됩니다. Tomcat을 재시작한 후 확인합니다.

로컬 또는 서버
# 메트릭 노출 확인
curl http://localhost:9090/metrics | head -30

# JVM 관련 메트릭만 필터링
curl -s http://localhost:9090/metrics | grep jvm_memory_bytes
# 예시 출력:
# jvm_memory_bytes_used{area="heap",} 1.34217728E8
# jvm_memory_bytes_max{area="heap",} 5.36870912E8

방화벽에서 9090 포트를 Prometheus 서버 IP에서만 허용해야 합니다. 외부에 노출하면 JVM 내부 정보가 공개됩니다.

로컬 터미널
# iptables로 Prometheus 서버만 9090 허용
iptables -A INPUT -p tcp --dport 9090 -s <prometheus-server-ip> -j ACCEPT
iptables -A INPUT -p tcp --dport 9090 -j DROP
💡개념

Prometheus scrape 설정

JMX Exporter를 설치했는데 Grafana에 여전히 JVM 메트릭이 안 보입니다. Prometheus가 그 엔드포인트를 수집 대상으로 등록하지 않았기 때문입니다. Prometheus는 수동으로 타겟을 지정해야 데이터를 가져옵니다. prometheus.ymlscrape_configs에 등록하지 않으면 메트릭이 아무리 노출되어 있어도 수집되지 않습니다.

Prometheus에서 JMX Exporter 엔드포인트를 수집 대상으로 등록합니다.

YAML
# /etc/prometheus/prometheus.yml

global:
  scrape_interval: 15s      # 기본 수집 주기
  evaluation_interval: 15s  # alert rule 평가 주기

scrape_configs:
  - job_name: 'tomcat-jvm'
    static_configs:
      - targets:
          - 'app-server-01:9090'
          - 'app-server-02:9090'
    scrape_interval: 15s
    metrics_path: /metrics    # 기본값, 생략 가능

  - job_name: 'node-exporter'
    static_configs:
      - targets:
          - 'app-server-01:9100'
로컬 터미널
# 설정 파일 검증
promtool check config /etc/prometheus/prometheus.yml

# Prometheus 재시작
systemctl reload prometheus

APM 핵심 지표 — 성능 문제 드릴다운 흐름확대

실습

1JMX Exporter 메트릭 확인

JMX Exporter가 정상적으로 동작하면 JVM Heap, Non-Heap, GC 관련 메트릭이 텍스트 형식으로 출력됩니다. jvm_memory_bytes_used에서 현재 사용량을, jvm_memory_bytes_max에서 최대 허용치를 확인합니다. 이 두 값의 비율이 사용률입니다.

curl -s http://app-server:9090/metrics | grep jvm_memory
🔍실행 후 확인할 것
  • curl 응답에서 먼저 HTTP 200 확인 — 그 다음 jvm_memory_bytes_used{area="heap"} 줄을 찾는다. 이 메트릭이 없으면 JMX Exporter가 붙지 않은 것
  • curl ... | wc -l 로 출력 줄 수 확인 — 정상이면 300줄 이상. 30줄 미만이면 JVM 메트릭 수집 실패로 exporter 설정 점검 필요
  • jvm_gc_collection_seconds_count 값이 0이면 GC 미발생(정상), 수 분 안에 급격히 증가하면 Full GC 과부하 — Heap 사용률과 함께 확인해야 원인 판별 가능
2Prometheus target 수집 상태 확인

Prometheus API로 등록된 target의 상태를 확인합니다. health: up이면 정상 수집 중, health: down이면 연결 실패입니다. Grafana 데이터가 없을 때 이 명령으로 먼저 Prometheus-target 간 연결을 확인합니다.

curl -s http://prometheus:9090/api/v1/targets | python3 -m json.tool | grep -E 'health|scrapeUrl'
🔍실행 후 확인할 것
  • health 필드부터 확인 — up이면 정상, down이면 lastError 메시지를 즉시 읽는다. "connection refused"는 앱 미기동, "context deadline exceeded"는 방화벽 차단
  • lastScrape 시각이 15초 이상 지난 target은 수집 지연 — scrape_interval 설정(기본 15s)보다 응답이 느린 것. 30초 이상 지났으면 timeout 증가 검토
  • health: up이고 lastScrape가 최근인데 Grafana에 데이터가 없으면 — scrapeUrl이 잘못된 IP/포트를 가리키거나, Grafana의 Data Source가 Prometheus가 아닌 다른 소스로 설정된 조합 문제

Grafana 대시보드 구성

💡개념

JVM 모니터링 대시보드 패널 구성

"Tomcat이 느려졌다"는 신고가 들어왔을 때, CPU와 메모리는 정상인데 응답이 느립니다. JVM Heap이 꽉 차서 GC가 과도하게 돌고 있는 경우입니다. 하지만 이 상황을 OS 레벨 메트릭으로는 알 수 없습니다. JVM 전용 패널이 있어야 Heap 사용률과 GC 빈도를 즉시 확인할 수 있습니다. 핵심 패널 4개가 있으면 대부분의 JVM 성능 이슈를 진단할 수 있습니다.

Grafana에서 Prometheus를 Data Source로 등록한 후 JVM 모니터링 대시보드를 구성합니다. 핵심 패널 4개면 JVM 상태를 충분히 파악할 수 있습니다.

패널 1 — Heap 사용률 (%):

PROMQL
# Heap 사용률 계산
(jvm_memory_bytes_used{area="heap", job="tomcat-jvm"}
 / jvm_memory_bytes_max{area="heap", job="tomcat-jvm"}) * 100

패널 2 — GC 발생 빈도 (rate):

PROMQL
# 분당 GC 발생 횟수
rate(jvm_gc_collection_seconds_count{job="tomcat-jvm"}[5m]) * 60

패널 3 — GC 소요 시간 비율 (%):

PROMQL
# GC에 소비되는 CPU 시간 비율
rate(jvm_gc_collection_seconds_sum{job="tomcat-jvm"}[5m])
/ rate(jvm_gc_collection_seconds_count{job="tomcat-jvm"}[5m]) * 1000
# ms 단위로 환산

패널 4 — Thread 수:

PROMQL
jvm_threads_current{job="tomcat-jvm"}

Alert Rule — Heap 85% 초과 5분 지속:

Grafana의 Alert 탭에서 다음과 같이 설정합니다.

YAML
# Grafana Alert Rule (개념 표현)
condition: Heap 사용률 > 85
for: 5m       # 5분 이상 지속 시 알람
labels:
  severity: warning
annotations:
  summary: "JVM Heap 사용률 위험 수준"
  description: "{{ $labels.instance }} Heap {{ $value }}%"

Grafana 8.x 이상에서는 Unified Alerting을 사용하며, Alert > Contact Points에서 Slack/Email 연동을 설정합니다.

트러블슈팅

원인: 두 가지 가능성입니다. 첫째는 Tomcat JAVA_OPTS에 -javaagent 옵션이 제대로 반영되지 않은 것, 둘째는 방화벽에서 9090 포트를 차단하고 있는 것입니다.

로컬 터미널
# 1단계: Tomcat 프로세스에 -javaagent 옵션이 있는지 확인
ps aux | grep java | grep jmx_prometheus

# 없으면 setenv.sh 확인
cat /opt/tomcat/bin/setenv.sh | grep javaagent

# setenv.sh가 없거나 JAVA_OPTS에 미반영된 경우
# Tomcat 재시작 후 확인
systemctl restart tomcat

# 2단계: 9090 포트 리슨 확인
ss -tlnp | grep 9090

# 3단계: 방화벽 확인 (CentOS/RHEL)
firewall-cmd --list-ports | grep 9090
# 필요 시 오픈 (Prometheus 서버 IP만 허용 권장)
firewall-cmd --add-port=9090/tcp --permanent && firewall-cmd --reload

# 4단계: JMX Exporter 설정 파일 경로 확인
# -javaagent 옵션에 지정한 config.yml 경로가 실제로 존재하는지
ls -la /opt/jmx_exporter/config.yml

원인: Prometheus가 target에서 scrape에 실패하거나, PromQL 쿼리에서 job 레이블이 실제 설정과 다를 때 발생합니다.

로컬 또는 서버
# 1단계: Prometheus target 상태 확인
curl -s http://prometheus:9090/api/v1/targets \
  | python3 -m json.tool | grep -A5 "tomcat-jvm"
# health: "down"이면 scrape 실패

# 2단계: 수동으로 메트릭 수집 시뮬레이션
curl -s http://app-server:9090/metrics | head -5
# 직접 접근이 되는지 확인

# 3단계: Prometheus에서 메트릭 존재 여부 확인
curl -s "http://prometheus:9090/api/v1/query?query=jvm_memory_bytes_used" \
  | python3 -m json.tool | grep value

# 4단계: Grafana PromQL에서 job 레이블 확인
# jvm_memory_bytes_used{job="tomcat-jvm"} 의 job 값이
# prometheus.yml의 job_name과 정확히 일치하는지 확인
curl -s "http://prometheus:9090/api/v1/labels" | python3 -m json.tool

심화 — 대시보드 숫자가 거짓말을 하는 두 순간

💡개념

심화: pattern .* 뒤에 숨은 비용 — 메트릭 카디널리티 폭발

앞의 JMX Exporter 설정을 rules: - pattern: ".*"로 뒀는데, 이건 시작용 편의일 뿐 운영 기본값으로 두면 위험합니다. Prometheus를 안정적으로 운영하려면 '무엇을 수집하지 않을지'가 '무엇을 수집할지'만큼 중요합니다.

  • Prometheus의 비용은 시계열 수(카디널리티)로 결정된다: Prometheus는 (메트릭 이름 + 라벨 값 조합) 하나하나를 개별 시계열로 저장합니다. .*로 모든 MBean을 노출하면 시계열이 수천~수만 개가 되고, 메모리·디스크·쿼리 시간이 모두 이 수에 비례합니다.
  • unbounded 라벨 하나가 폭발을 부른다: path(요청 URL), user_id, session_id, trace_id처럼 값의 종류가 무한히 늘어나는 라벨을 하나만 붙여도 시계열이 수백만으로 튑니다. status_code(값 몇 개)는 안전하지만, URL·ID 같은 고카디널리티 라벨은 치명적입니다.
  • 증상은 대상이 아니라 Prometheus에서 터진다: head series 급증 → Prometheus 메모리 폭증·OOM, scrape 지연, 쿼리 타임아웃. 정작 앱은 멀쩡한데 모니터링 시스템이 먼저 쓰러집니다. prometheus_tsdb_head_series 값으로 상시 감시해야 합니다.
  • 다음 단계는 화이트리스트와 relabel: .* 대신 필요한 MBean만 pattern으로 좁히고, 불필요한 시계열은 metric_relabel_configsdrop으로 잘라냅니다. unbounded 값은 애초에 라벨로 만들지 않습니다(URL은 라우트 템플릿으로 정규화). 무거운 대시보드 쿼리는 recording rule로 미리 집계해 둡니다.

즉 "다 수집해두면 언젠가 쓰겠지"가 아니라, "이 라벨의 값이 몇 종류까지 늘 수 있나"를 노출 전에 따지는 것이 관측 파이프라인의 기본 위생입니다.

상황: latency 대시보드의 p99 라인이 며칠째 200ms로 안정적인데, 특정 고객군은 체감 5초의 지연을 반복 신고합니다. 그래프만 보면 아무 문제가 없어 보여, 신고를 '사용자 환경 탓'으로 넘길 뻔했습니다.

원인: 두 겹의 집계 함정입니다. 첫째, 패널이 여러 인스턴스의 p99를 avg()로 합쳐 보여주고 있었습니다 — 백분위수는 평균할 수 없습니다. 한 인스턴스만 5초여도 나머지의 낮은 p99와 평균되면 200ms로 희석됩니다. 둘째, 히스토그램 버킷의 최상단이 le="1"(1초)에서 끝나 그 이상은 전부 +Inf 한 버킷에 뭉개져, histogram_quantile이 상한을 넘는 꼬리를 볼 수 없었습니다. 여기에 rate 윈도우(5m)가 짧은 스파이크를 다시 평균으로 눌렀습니다.

진단: 집계를 풀어 인스턴스별·버킷별로 분해합니다.

PROMQL
# 인스턴스별로 분해 — 특정 노드만 튀는지 확인(avg로 뭉개지 않음)
histogram_quantile(0.99, sum by (le, instance) (rate(http_request_duration_seconds_bucket[5m])))

# 버킷 상한(le=5초)을 넘는 요청이 있는지 — +Inf 꼬리 확인
sum(rate(http_request_duration_seconds_bucket{le="+Inf"}[5m]))
  - sum(rate(http_request_duration_seconds_bucket{le="5"}[5m]))

그리고 APM 원본 트레이스나 액세스 로그의 실제 응답시간 최댓값과 대조해, 그래프의 '평온함'이 진짜인지 확인합니다.

해결: 백분위수 패널에서 avg()를 없애고 인스턴스별로 보거나, 원시 버킷을 합산한 위에서 histogram_quantile을 계산합니다. 버킷 경계를 실제 SLO(예: 3s·5s·10s)를 덮도록 넓히고, p99와 함께 max·p99.9 같은 꼬리 지표를 나란히 노출합니다. '평균은 꼬리를 숨긴다'는 원칙을 대시보드 설계에 박아, 소수 사용자의 심한 지연이 다수의 정상치에 묻히지 않게 합니다.

💼
실무 맥락
현업 패턴

실제 업무에서 이 지식이 쓰이는 상황:

서버 3대를 운영하면서 "가끔 응답이 늦어진다"는 민원이 들어올 때, APM이 있으면 30분 안에 원인을 찾고, 없으면 며칠을 추측합니다. APM 솔루션을 당장 도입하기 어려운 환경이라면, JMX Exporter + Prometheus + Grafana 조합이 비용 없이 구현 가능한 대안입니다.

실무 모니터링 스택 예시:

인프라 모니터링: Prometheus + Node Exporter → Grafana
JVM 모니터링:   JMX Exporter → Prometheus → Grafana
APM:            Pinpoint 에이전트 → Pinpoint Collector → Web UI
알람:           Grafana Alert → Slack webhook

신입 엔지니어가 자주 하는 실수:

  1. JMX Exporter 포트를 방화벽 예외 없이 설정해 Prometheus가 수집 못 함
  2. Heap alert를 순간 값으로 걸어 false positive 남발 → for 5m 조건 필수
  3. scrape_interval을 너무 짧게 설정해 모니터링 서버 자체가 부하

명령어·단축키 빠른 참조

JVM 메트릭을 Prometheus/Grafana로 관측할 때 쓰는 명령·쿼리를 모았습니다.

명령어/단축키용도자주 쓰는 예
curl …/metricsJMX Exporter 노출 메트릭 확인curl -s host:9090/metrics | grep jvm_memory
curl …/api/v1/targetsPrometheus 수집 대상 상태health:up이면 정상, down이면 lastError
curl …/api/v1/query?query=PromQL 즉석 실행?query=up(대상 생사), query=jvm_memory_bytes_used
promtool check configprometheus.yml 문법 검증재시작 전 필수
systemctl reload prometheus설정 무중단 반영scrape_config 변경 후
ss -tlnpexporter 포트 리슨 확인ss -tlnp | grep 9090
ps aux | grep javaagent-javaagent 반영 여부JMX Exporter 미부착 진단
firewall-cmd / iptables9090을 Prometheus IP만 허용외부 노출 차단
up == 0대상 다운 감지 규칙up == 0 for 1m
histogram_quantile(0.99, …)p99 지연 계산(백분위수는 avg 금지)histogram_quantile(0.99, sum by(le,instance)(rate(..._bucket[5m])))
rate(…_count[5m])초당 증가율(GC·요청)rate(jvm_gc_collection_seconds_count[5m])*60
prometheus_tsdb_head_series시계열 수(카디널리티) 감시.* 라벨 폭발 조기 감지

관련 모듈로 더 깊이:

다음 모듈에서는 장애가 발생했을 때 타임라인을 재구성하고 5-Why 분석으로 재발 방지 대책을 수립하는 장애 보고서 작성법을 다룹니다.

지식 확인

퀴즈 — 8문제

Q1

APM과 인프라 모니터링(CPU/메모리 등)의 핵심 차이는?

Q2

Prometheus가 JVM 메트릭을 직접 수집하지 못하는 이유와 JMX Exporter가 필요한 이유는?

Q3

Grafana alert 설정에서 'for 5m' 조건의 의미는?

Q4

Prometheus scrape_interval을 5초처럼 너무 짧게 설정하면 발생하는 문제는?

Q5

CPU·메모리는 정상인데 사용자는 '느리다'고 한다. APM이 추적해야 할 핵심 지표는?

Q6

Prometheus는 대상이 노출한 메트릭을 주기적으로 가져오는 pull 방식이다. 대상 서버가 죽으면 이를 어떻게 감지하나?

Q7

[심화] JMX Exporter를 pattern .* 로 두고 라벨에 요청 URL과 session_id를 붙였더니, 앱은 멀쩡한데 Prometheus 메모리가 폭증하고 쿼리가 느려졌다. 근본 원인은?

Q8

[심화] Grafana의 p99 응답시간 패널은 200ms로 평온한데 일부 사용자는 5초를 겪는다. 이 패널은 여러 인스턴스의 p99를 avg()로 합쳐 보여준다. 가장 먼저 의심할 것은?

0 / 8 답변

🧪 실습으로 확인하기

Nginx 설치 및 기동

초급

Linux 서버에 Nginx를 설치하고 systemd 서비스로 등록하여 80포트에서 응답하는 상태까지 만든다.

40📋 3단계💻 직접 환경
실습 시작하기 →

이것도 배워보세요