본문 바로가기
Database & Storage

Micrometer·Prometheus·Grafana로 스프링 부트 서비스 모니터링 대시보드 만들기

by yamoojin83 2025. 10. 10.

Micrometer·Prometheus·Grafana로 스프링 부트 서비스 모니터링 대시보드 만들기

운영 중인 서비스에서 장애가 터졌을 때, 가장 먼저 보는 것은 로그지만
“지금 시스템이 얼마나 버티고 있는지”를 알려주는 것은 결국 메트릭과 대시보드입니다.

이 글은 스프링 부트 애플리케이션을 기준으로 Micrometer → Prometheus → Grafana로 이어지는
관측성(Observability) 파이프라인을 한 번에 구축하는 과정을 정리합니다.

단순히 “설치 방법”을 나열하는 것이 아니라,
어떤 메트릭을 왜 수집해야 하는지, 대시보드에서 무엇을 봐야 하는지까지 운영 관점에서 설명합니다.

 

전체 관측성 파이프라인 다이어그램



1. 관측성 파이프라인 전체 구조 이해

먼저 큰 흐름부터 정리해 보겠습니다.

스프링 부트 애플리케이션 내부에서는 Micrometer가 메트릭을 수집하고,
이 메트릭을 /actuator/prometheus 엔드포인트로 노출합니다.

Prometheus는 이 엔드포인트를 주기적으로 스크레이핑(scraping)해 시계열 데이터베이스에 쌓고,
Grafana가 PromQL 쿼리를 통해 데이터를 조회해 대시보드로 시각화합니다.

즉, 흐름은 다음과 같습니다.
애플리케이션 → Micrometer → /actuator/prometheus → Prometheus → Grafana

 

2. 스프링 부트에서 Micrometer 활성화하기

2-1) 의존성 추가

스프링 부트 2.x/3.x에서는 Actuator와 Micrometer가 거의 기본값처럼 연동됩니다.
Prometheus로 내보내기 위해서는 다음 의존성이 필요합니다.

// build.gradle
dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-actuator'
    implementation 'io.micrometer:micrometer-registry-prometheus'
}

 

2-2) application.yml 설정

Actuator 엔드포인트와 Prometheus 노출 설정을 활성화합니다.
운영에서는 보안상 IP 필터링, BasicAuth, 별도 게이트웨이 등으로 보호하는 것을 권장합니다.

management:
  endpoints:
    web:
      exposure:
        include: health,info,prometheus
  endpoint:
    health:
      show-details: always
  metrics:
    tags:
      application: my-service

이제 애플리케이션을 실행하면 /actuator/health, /actuator/prometheus 엔드포인트를
브라우저 또는 curl로 확인할 수 있습니다.

 

2-3) 커스텀 비즈니스 메트릭 추가

기본 제공되는 JVM/HTTP 메트릭만으로는 부족할 때가 많습니다.
예를 들어, “주문 생성 API 호출 수” 같은 비즈니스 메트릭을 추가해 보겠습니다.

@RestController
@RequiredArgsConstructor
public class OrderController {

    private final Counter orderCreatedCounter;

    @Bean
    public Counter orderCreatedCounter(MeterRegistry registry) {
        return Counter.builder("order_created_total")
                .tag("service", "my-service")
                .description("Total number of created orders")
                .register(registry);
    }

    @PostMapping("/orders")
    public ResponseEntity<Void> createOrder(@RequestBody OrderRequest req) {
        // ... 주문 생성 로직 ...
        orderCreatedCounter.increment();
        return ResponseEntity.ok().build();
    }
}

이렇게 등록한 메트릭은 order_created_total이라는 이름으로 Prometheus에 노출되며,
나중에 Grafana에서 주문 수 추이, 피크 타임 등을 시각화하는 데 사용할 수 있습니다.

 

Prometheus 스크레이핑 흐름

3. Prometheus 설정: /actuator/prometheus 스크레이핑

3-1) Docker Compose로 Prometheus 띄우기

Prometheus는 단일 바이너리로도 실행 가능하지만,
테스트와 운영 모두에서 Docker Compose 구성이 가장 관리하기 편합니다.

version: "3.9"

services:
  prometheus:
    image: prom/prometheus:v2.54.0
    container_name: prometheus
    restart: always
    ports:
      - "9090:9090"
    volumes:
      - ./prometheus.yml:/etc/prometheus/prometheus.yml
      - prom_data:/prometheus

volumes:
  prom_data:

 

3-2) prometheus.yml에서 스프링 부트 타겟 등록

global:
  scrape_interval: 15s

scrape_configs:
  - job_name: "spring-boot-app"
    metrics_path: "/actuator/prometheus"
    static_configs:
      - targets: ["host.docker.internal:8080"]

여기서 targets는 Prometheus 컨테이너 기준에서 보이는 스프링 부트 애플리케이션 주소입니다.
로컬 개발 환경에서는 host.docker.internal:8080을 자주 사용하고,
운영 환경에서는 서비스 디스커버리 또는 내부 DNS 이름을 사용하는 경우가 많습니다.

Prometheus 웹 UI(http://localhost:9090)에 접속해 Status → Targets를 보면
스크레이핑 상태가 UP인지 확인할 수 있습니다.

 

4. Grafana에서 대시보드 만들기

4-1) Grafana Docker Compose 예시

services:
  grafana:
    image: grafana/grafana:11.0.0
    container_name: grafana
    restart: always
    ports:
      - "3000:3000"
    volumes:
      - grafana_data:/var/lib/grafana

volumes:
  grafana_data:

컨테이너가 기동되면 http://localhost:3000으로 접속해
기본 계정(admin/admin)으로 로그인 후 비밀번호를 변경합니다.

그 다음 Configuration → Data sources에서 Prometheus를 추가하고,
URL에 http://prometheus:9090 (Compose 네트워크 기준 이름)을 입력합니다.

 

4-2) 자주 쓰는 PromQL 쿼리 예시

이제 Grafana의 패널에서 PromQL을 작성해 보면 됩니다.
대표적인 예시는 다음과 같습니다.

# HTTP 요청 수 (5분 단위 증가율)
sum(rate(http_server_requests_seconds_count[5m])) by (uri, status)

# JVM 힙 사용량
jvm_memory_used_bytes{area="heap"}

# 주문 생성 수 (커스텀 메트릭)
sum(rate(order_created_total[5m]))

패널 타입은 시계열(Time series), Stat, Gauge 등을 적절히 섞어 사용합니다.
예를 들어, 전체 요청 수는 시계열, 에러 비율은 Stat, JVM 사용량은 Gauge로 표현하면
대시보드가 한눈에 들어오기 쉬워집니다.



Grafana 대시보드 예시



5. 운영 관점에서 꼭 고려해야 할 것들

5-1) 메트릭 태그(cardinality) 폭발 주의

Prometheus의 가장 큰 함정 중 하나가 label cardinality 폭발입니다.
예를 들어, 사용자 ID, 세션 ID 같은 값을 태그로 넣으면
메트릭 시계열 개수가 기하급수적으로 늘어나 스토리지와 조회 성능에 큰 부담을 줍니다.

태그에는 상대적으로 변화가 적은 값(서비스 이름, 인스턴스, 환경, 지역 등)만 두고,
빠르게 변하는 값은 로그나 트레이싱에 맡기는 것이 좋습니다.

5-2) 알람 조건은 “수치” + “기간”으로 정의

Grafana Alert 또는 Alertmanager를 사용할 때는
단일 시점 값이 아니라, 일정 기간 동안의 추세를 기준으로 알림을 설계해야 합니다.

예를 들어, “5분 동안 HTTP 5xx 비율이 5% 이상인 경우”와 같이
노이즈를 줄이면서도 실제 장애를 놓치지 않는 조건이 중요합니다.

5-3) 대시보드는 팀원 전체가 이해할 수 있어야 한다

운영 대시보드는 “예쁘게 만드는 것”보다
누가 봐도 같은 해석을 할 수 있는 구조가 더 중요합니다.

페이지 상단에는 전체 트래픽·에러·지연시간을 배치하고,
중간에는 주요 API, 하단에는 JVM/DB/외부 연동 상태를 배치하는 식으로
위에서 아래로 내려갈수록 자세한 정보를 보는 흐름을 만드는 것이 좋습니다.



6. 정리 및 체크리스트

  • 스프링 부트에서 Micrometer + Prometheus Registry 활성화했는가?
  • /actuator/prometheus 엔드포인트를 Prometheus에서 정상 스크레이핑하는가?
  • 비즈니스 메트릭(주문수, 로그인수 등)을 최소 1개 이상 정의했는가?
  • Grafana 대시보드에서 트래픽·에러·지연시간을 한 화면에서 볼 수 있는가?
  • 알람 조건과 책임자(누가 볼 것인가)가 명확하게 정의되어 있는가?

Micrometer·Prometheus·Grafana 조합은 한 번 패턴을 잡아두면
새로운 서비스가 추가될 때도 거의 같은 구조를 복사해 쓸 수 있습니다.

이 글에서 정리한 관측성 파이프라인을 기반으로,
운영 중인 서비스의 가시성과 안정성을 한 단계 끌어올릴 수 있기를 바랍니다.



 

 

👉 1편: Ubuntu 24.04에서 Nginx로 무료 SSL(HTTPS) 적용

👉 2편: UFW 방화벽 실전 규칙

👉 3편: systemd 서비스로 스프링부트 배포

👉 4편: Tomcat 10 설치+튜닝 체크리스트

👉 5편: Gradle 빌드 최적화로 빌드 50% 줄이기

👉 6편: Spring Security 6 JWT 로그인/리프레시 토큰

👉 7편: JPA N+1 완전 정복: 자동 감지부터 fetch join·EntityGraph·batch_size 실전 해결 전략

👉 8편: Docker로 PostgreSQL 운영(백업/복구/업그레이드)

👉 9편: Micrometer+Prometheus+Grafana 대시보드

👉 10편: Testcontainers로 DB 통합테스트