Micrometer 입문 1편 — 메트릭의 벤더 중립 facade·큰 그림

2026-05-25Micrometer 입문에서 운영까지

Micrometer 입문 1편. 메트릭의 벤더 중립 facade — MeterRegistry · dimensional metrics(태그) · 지원 백엔드(Prometheus · Datadog · CloudWatch · New Relic · StatsD) · Observability 3 pillar 속 위치 · Observation API/Tracing 개요. 앱이 메트릭을 내보내는 계측 계층의 큰 그림.

📚 Micrometer 입문에서 운영까지 · 1편 — 메트릭의 벤더 중립 facade·큰 그림

이 글은 Micrometer 입문에서 운영까지 시리즈 1편이에요. 9편 풀 시리즈의 시작이고, 첫 글은 큰 그림을 잡는 자리예요. Micrometer 가 무엇인지, 왜 "메트릭의 SLF4J"라고 불리는지, MeterRegistry 와 태그가 어떻게 맞물리는지, 어떤 백엔드를 지원하는지를 한 번에 정리해요. 메트릭을 시각화하는 Grafana 시리즈와 연결해서 읽으면 관측 스택 전체가 한 그림으로 잡혀요.

📚 학습 노트

이 시리즈는 Micrometer 공식 문서, Spring Boot Actuator 공식 가이드, 여러 observability 학습 자료 등 공개 자료를 참고해 한국어 학습 노트로 풀어쓴 자료입니다.

Spring Boot 프로젝트에 spring-boot-starter-actuatormicrometer-registry-prometheus 의존성을 추가하고 /actuator/metrics 엔드포인트를 직접 열어 보면 본문이 머리에 훨씬 잘 박혀요.

이번 글의 범위

이번 글은 Micrometer 의 계측 계층 전체를 훑어요.

자리 내용
개념 벤더 중립 facade — 코드는 한 번, 백엔드는 설정으로
핵심 API MeterRegistry · Meter(Counter · Timer · Gauge · DistributionSummary) · Tag
dimensional metrics 태그가 차원이 되는 방식
지원 백엔드 Prometheus · Datadog · CloudWatch · New Relic · StatsD 등
Observability 속 위치 3 pillar 중 Metrics 계층
Observation API / Tracing 구 Spring Cloud Sleuth 대체, 후속편 예고

왜 처음엔 어렵게 느껴질까

Micrometer 를 처음 마주하면 막막한 이유가 두 가지예요.

첫째, 라이브러리·수집기·대시보드가 따로 놀아요. Micrometer 는 앱이 메트릭을 생성하는 계측 계층이고, Prometheus 는 그걸 긁어 가는 수집기이고, Grafana 는 그걸 시각화하는 도구예요. 그런데 Spring Boot 로 처음 Actuator 를 켜면 이 셋이 한꺼번에 얽혀서 어디가 어디인지 잘 안 보여요.

둘째, 메트릭은 로그처럼 눈에 잘 안 보여요. 로그는 콘솔에 찍히니까 뭔가 일어나고 있다는 게 즉시 느껴지는데, 메트릭은 숫자 시계열로 쌓이다가 나중에 그래프로 봐야 비로소 의미가 생기거든요. 처음에는 "이게 지금 뭘 하고 있는 거지?" 감이 안 잡혀요.

해결은 Micrometer 의 자리를 하나로 압축하는 거예요. Micrometer = 앱 코드와 메트릭 백엔드 사이의 번역기. 이 한 줄만 잡히면 나머지 구조는 자연스럽게 따라와요.

Micrometer의 자리

"메트릭의 SLF4J"

Java 로깅을 해 봤다면 SLF4J 를 알 거예요. 로거를 LoggerFactory.getLogger(...) 로 만들면 실제 구현체가 Logback 이든 Log4j2 든 코드를 건드리지 않고 설정만 바꿀 수 있잖아요. Micrometer 가 메트릭에서 정확히 그 역할이에요.

// 코드에서는 Micrometer API 만 사용
MeterRegistry registry = ...; // 어떤 구현체인지 코드는 신경 X
Counter.builder("orders.created")
    .tag("region", "us-east")
    .register(registry)
    .increment();

여기서 registry 가 Prometheus 구현체인지, Datadog 구현체인지는 코드에서 몰라도 돼요. Spring Boot 의 Actuator 자동 설정이 클래스패스에 있는 micrometer-registry-* 의존성을 보고 알아서 주입해 줘요. 코드는 그대로인데 운영 환경에서는 Datadog, 로컬에서는 Prometheus — 이 전환이 application.yml 한 줄로 끝나요.

회사의 관점 비유

Micrometer 의 자리를 회사로 비유하면 이래요.

회사의 메트릭 흐름:
  - 각 팀이 일일 실적 수치를 기록
  - 보고 포맷은 팀마다 다를 수 있음
  - 경영진 → "표준 양식으로 올려줘" (공통 인터페이스)
  - 양식을 채우는 건 팀 (앱 계측)
  - 데이터를 받아 분석하는 건 BI 도구 (Prometheus · Datadog)

Micrometer = 경영진이 정한 표준 양식
  - 앱이 양식에 숫자를 채움 (Counter · Timer · Gauge)
  - 어느 BI 도구에 넘길지는 설정으로 결정

Observability 3 pillar 속 위치

Grafana 시리즈에서 Observability 의 3 pillar 를 다뤘는데, 메트릭을 모아 보여주는 시각화 쪽은 Grafana 시리즈 에서 자세히 다뤘어요. Micrometer 는 그 3 pillar 중 Metrics 계층의 생산 쪽 을 담당해요.

Observability 3 Pillar:
  ┌─────────────────────────────────────────┐
  │ Metrics (지금 상태) ← Micrometer 의 자리  │
  │   앱이 숫자를 생성 → 백엔드가 수집         │
  ├─────────────────────────────────────────┤
  │ Logs (발생한 일)                          │
  │   SLF4J + Logback · Log4j2 등            │
  ├─────────────────────────────────────────┤
  │ Traces (요청의 여정)                     │
  │   Micrometer Tracing (구 Sleuth) · OTel  │
  └─────────────────────────────────────────┘

잠깐, 여기서 함정이 하나 있어요. Micrometer 가 Metrics 만 다루는 게 아니에요. Micrometer 1.10 이후로 Observation API 가 들어오면서 Traces 도 같은 API 안에서 처리할 수 있게 됐어요. 뒤에서 자세히 볼게요.

MeterRegistry — 모든 것의 입구

Meter · Registry · Tag 관계

Micrometer 의 핵심 구조는 세 개예요.

MeterRegistry
  └─ Meter 들의 집합 (등록소)
       ├─ Counter    (누적 카운트 — 단조 증가)
       ├─ Timer      (시간 + 횟수 — latency 측정)
       ├─ Gauge      (현재 값 — 큐 크기, 스레드 수 등)
       ├─ DistributionSummary (분포 측정 — 페이로드 크기 등)
       ├─ LongTaskTimer        (긴 작업의 진행 시간)
       └─ FunctionCounter / FunctionTimer (외부 카운터 래핑)

Tag 는 각 Meter 에 붙는 key=value 레이블이에요. Meter 는 이름 + Tag 조합으로 식별되고, 같은 이름이라도 다른 Tag 를 가지면 서로 다른 시계열이 돼요.

간단한 Java 코드 예

import io.micrometer.core.instrument.*;
import io.micrometer.core.instrument.simple.SimpleMeterRegistry;

public class BasicExample {
    public static void main(String[] args) {
        // 가장 단순한 인메모리 레지스트리 (테스트용)
        MeterRegistry registry = new SimpleMeterRegistry();

        // Counter — 주문 생성 횟수
        Counter orderCounter = Counter.builder("orders.created")
            .tag("region", "us-east")
            .tag("type", "online")
            .description("Number of orders created")
            .register(registry);

        orderCounter.increment();
        orderCounter.increment(3.0); // 한 번에 여러 개

        // Timer — API 응답 시간
        Timer timer = Timer.builder("http.server.requests")
            .tag("uri", "/api/orders")
            .tag("method", "POST")
            .register(registry);

        timer.record(() -> {
            // 실제 API 호출 로직
        });

        // Gauge — 현재 큐 크기
        Queue<String> queue = new LinkedList<>();
        Gauge.builder("queue.size", queue, Collection::size)
            .tag("queue", "order-processing")
            .register(registry);

        System.out.println(registry.get("orders.created").counter().count()); // 4.0
    }
}

여기서 중요한 게 register(registry) 호출이에요. Meter 는 생성만 해서는 아무 의미가 없고, 반드시 Registry 에 등록해야 데이터가 수집돼요.

Spring Boot 에서의 자동 설정

Spring Boot 에서는 MeterRegistry 빈을 직접 만들지 않아도 Actuator 가 알아서 주입해 줘요.

@Service
@RequiredArgsConstructor
public class OrderService {

    private final MeterRegistry registry;

    public void createOrder(Order order) {
        // 비즈니스 로직 실행
        processOrder(order);

        // 메트릭 기록
        registry.counter("orders.created",
            "region", order.getRegion(),
            "type", order.getType()
        ).increment();
    }
}

또는 @Timed 어노테이션으로 더 간단하게 Timer 를 박을 수 있어요.

@Timed(value = "orders.create.time", description = "Order creation latency")
public Order createOrder(CreateOrderRequest req) {
    // ...
}

dimensional metrics — 태그가 차원이다

태그 없는 메트릭의 한계

태그(Tag) 가 없으면 메트릭은 단순 숫자 하나예요.

http_requests_total = 5000

이게 어느 엔드포인트에서 발생한 건지, 성공인지 실패인지, 어느 리전인지 — 아무것도 몰라요.

태그가 붙으면 다차원이 된다

http_requests_total{uri="/api/orders", method="POST", status="200"} = 4800
http_requests_total{uri="/api/orders", method="POST", status="500"} = 200
http_requests_total{uri="/api/users", method="GET", status="200"}  = 3200

이제 질문에 답할 수 있어요. "POST /api/orders 의 에러율은?" → 200/(4800+200) = 4%. 이게 dimensional metrics 의 핵심이에요.

여기서 실무 함정이 하나 있어요. 태그 값에 동적 ID(user_id, request_id, session_id 같은 것) 를 절대 넣으면 안 돼요. 사용자가 100만 명이면 태그 조합이 100만 가지 시계열이 되고, Prometheus 나 Datadog 이 메모리 폭발(cardinality explosion) 을 일으켜요. 태그 값은 항상 유한한 집합에서 골라야 해요.

⚠️ 자주 틀리는 함정

태그 값에 userId, requestId, sessionId 같은 동적 식별자를 쓰면 cardinality 폭발이 일어납니다. 태그 값은 region, status, method, environment 처럼 유한하고 예측 가능한 값만 허용해야 해요.

Micrometer 의 common tags

공통 태그(예: 서비스 이름, 버전, 환경)는 매번 붙이지 않고 레지스트리 레벨에서 전역 설정이 가능해요.

// Spring Boot application.yml
management:
  metrics:
    tags:
      application: order-service
      environment: production
      region: us-east-1

이렇게 하면 이 앱에서 생성되는 모든 메트릭에 저 세 태그가 자동으로 붙어요.

지원 백엔드 한눈에

Micrometer 는 공식적으로 다음 백엔드를 지원해요. Micrometer 공식 문서 에서 전체 목록을 확인할 수 있어요.

┌──────────────────────────────────┬────────────────────────────────────┐
│ 백엔드                            │ 방식 · 특징                         │
├──────────────────────────────────┼────────────────────────────────────┤
│ Prometheus                       │ Pull — /actuator/prometheus 노출    │
│                                  │ OSS · 가장 흔한 조합                │
├──────────────────────────────────┼────────────────────────────────────┤
│ Datadog                          │ Push — Datadog API 로 직접 전송     │
│                                  │ SaaS · 유료                        │
├──────────────────────────────────┼────────────────────────────────────┤
│ AWS CloudWatch                   │ Push — CloudWatch PutMetricData     │
│                                  │ AWS 환경 네이티브                   │
├──────────────────────────────────┼────────────────────────────────────┤
│ New Relic                        │ Push — New Relic Metrics API        │
│                                  │ SaaS · APM 통합                    │
├──────────────────────────────────┼────────────────────────────────────┤
│ StatsD                           │ Push — UDP 로 전송 (매우 가벼움)    │
│                                  │ 오래된 메트릭 시스템 연동            │
├──────────────────────────────────┼────────────────────────────────────┤
│ Graphite                         │ Push — TCP/UDP                     │
│                                  │ 레거시 시스템                       │
├──────────────────────────────────┼────────────────────────────────────┤
│ InfluxDB                         │ Push — InfluxDB HTTP API           │
│                                  │ 시계열 DB 직접 연동                 │
├──────────────────────────────────┼────────────────────────────────────┤
│ OpenTelemetry (OTLP)             │ Push — OTLP 프로토콜               │
│                                  │ 표준 계층, OTel Collector 연동      │
├──────────────────────────────────┼────────────────────────────────────┤
│ Azure Monitor                    │ Push — Azure Application Insights  │
│                                  │ Azure 환경 네이티브                 │
└──────────────────────────────────┴────────────────────────────────────┘

여기서 핵심 차이는 Pull vs Push 예요.

Pull: Prometheus → 앱의 /actuator/prometheus 를 주기적으로 스크랩
Push: 앱 → Datadog · CloudWatch 등으로 주기적으로 밀어냄

Spring Boot 프로젝트에서 백엔드 전환은 의존성 + 설정 변경만으로 끝나요.

<!-- Prometheus: pull 방식 -->
<dependency>
    <groupId>io.micrometer</groupId>
    <artifactId>micrometer-registry-prometheus</artifactId>
</dependency>

<!-- Datadog: push 방식 -->
<dependency>
    <groupId>io.micrometer</groupId>
    <artifactId>micrometer-registry-datadog</artifactId>
</dependency>
# Datadog 으로 전환 시 추가 설정
management:
  datadog:
    metrics:
      export:
        api-key: ${DATADOG_API_KEY}
        step: 30s

앱 코드의 Counter.builder(...), Timer.builder(...) 는 전혀 안 건드려도 돼요. 이게 facade 의 핵심이에요.

Observation API · Micrometer Tracing 큰 그림

구 Spring Cloud Sleuth 의 후계자

Spring Boot 2.x 시절 분산 추적(tracing) 은 Spring Cloud Sleuth 가 담당했어요. Brave 라이브러리를 래핑해서 TraceId, SpanId 를 자동으로 붙여줬죠. 그런데 Spring Boot 3.x 부터 Spring Cloud Sleuth 가 공식 지원 종료됐고, 그 역할을 Micrometer Tracing 이 흡수했어요.

헷갈리기 쉬운 지점이 있어요. Micrometer Tracing 은 Micrometer 의 Metrics API 와 별개로 존재하는 독립 모듈이에요. 단지 같은 Micrometer 프로젝트 우산 아래에 있을 뿐이에요.

Observation API — metrics + traces 를 하나로

Micrometer 1.10 에서 나온 Observation API 는 한 번의 계측으로 Metrics 와 Traces 를 동시에 생성할 수 있어요.

// Observation API 사용 예
Observation observation = Observation.createNotStarted("orders.create", registry)
    .contextualName("Creating order")
    .lowCardinalityKeyValue("region", "us-east")
    .start();

try (Observation.Scope scope = observation.openScope()) {
    // 비즈니스 로직
    Order order = processOrder(request);
    observation.event(Observation.Event.of("order.validated"));
    return order;
} catch (Exception e) {
    observation.error(e);
    throw e;
} finally {
    observation.stop();
}

이 코드 한 블록이 자동으로 Timer(메트릭) 와 Span(트레이싱) 을 동시에 생성해요. 두 관점을 분리해서 박지 않아도 되는 거죠.

지원 Tracing 백엔드

Micrometer Tracing 지원 백엔드:
  - Zipkin (Brave 또는 OTel bridge)
  - Jaeger (OTel bridge)
  - OpenTelemetry (OTLP)
  - Wavefront (VMware Aria Operations for Applications)

함정 정리

사고 1: Micrometer 와 Prometheus 를 같은 것으로 오해

원인 — Spring Boot + Prometheus 조합을 자주 보다 보니 "Micrometer = Prometheus" 로 기억하는 경우가 있어요.

해결 — Micrometer 는 계측 계층(instrumentation layer), Prometheus 는 수집 백엔드(backend) 예요. 둘은 역할이 완전히 달라요. Micrometer 는 백엔드 없이 SimpleMeterRegistry 로도 동작해요.

사고 2: Counter 를 Gauge 로 착각

원인 — "현재 요청 수"를 표현하려는데 Counter 를 쓰면 계속 증가만 해서 의미가 없어요.

해결 — Counter 는 단조 증가 카운트(총 처리량), Gauge 는 현재 순간의 값(현재 연결 수, 큐 크기)이에요. "지금 몇 개냐"는 Gauge, "지금까지 몇 번 했냐"는 Counter 예요.

사고 3: 태그에 동적 ID 사용 → cardinality 폭발

원인 — 사용자 추적을 위해 user_id 를 태그로 박아요.

해결 — 태그 값은 반드시 유한 집합이어야 해요. userId 대신 userTier(free/premium), region(us/kr/eu) 같이 집약된 값을 써요. cardinality 폭발은 Prometheus 메모리 OOM 의 가장 흔한 원인이에요.

사고 4: register(registry) 빠뜨림

원인Counter.builder("name").tag("k","v").description("...") 까지 쓰고 .register(registry) 를 빠뜨리면 아무 데이터도 쌓이지 않아요. 컴파일 에러도 안 나요.

해결.register(registry) 는 빌더의 마지막 단계이자 필수예요. Counter 등은 register 없이는 아무것도 하지 않아요.

사고 5: 같은 Meter 를 매 요청마다 새로 만듦

원인 — 서비스 메서드 안에서 Counter.builder(...).register(registry) 를 매 요청마다 호출해요.

해결 — Registry 는 같은 이름+태그 조합의 Meter 를 캐싱하니까 중복 등록은 안전하지만, 매번 빌더를 생성하는 오버헤드가 있어요. Meter 는 필드나 생성자에서 한 번 만들어서 재사용하는 게 모범 패턴이에요.

사고 6: Timer 를 ms 단위로 수동 계산

원인long start = System.currentTimeMillis(); ... timer.record(elapsed, TimeUnit.MILLISECONDS); 처럼 직접 계산해요.

해결timer.record(() -> {...}) 또는 timer.recordCallable(() -> {...}) 을 쓰면 Timer 가 알아서 나노초 정밀도로 측정해요. 직접 계산하면 단위 실수나 Exception 처리 누락 위험이 있어요.

사고 7: Spring Boot 자동 설정 Meter 와 커스텀 Meter 이름 충돌

원인 — Spring Boot Actuator 가 자동으로 http.server.requests, jvm.memory.used 같은 Meter 를 생성하는데, 커스텀 Meter 에 같은 이름을 써서 충돌이 생겨요.

해결 — 커스텀 Meter 는 앱 이름이나 도메인 prefix 를 붙이는 게 관례예요. orders.created, payment.processed 처럼요. Spring Boot 자동 Meter 는 http., jvm., system., process., tomcat. prefix 를 써요.

사고 8: Push 백엔드에서 interval 설정 누락

원인 — Datadog · CloudWatch 등 Push 방식 백엔드는 기본 step(전송 주기) 이 1분이에요. 짧은 스파이크를 잡아야 하는 상황에서 1분 resolution 이면 놓칠 수 있어요.

해결management.datadog.metrics.export.step, management.cloudwatch.metrics.export.step 으로 주기를 조절해요. 단, step 이 짧아질수록 API 호출 비용이 늘어요.

사고 9: DistributionSummary 를 Timer 와 혼동

원인 — 시간 외의 크기(페이로드 bytes, 배치 크기 등)도 Timer 로 박는 실수예요.

해결 — DistributionSummary 는 단위가 없는 수량 의 분포를 측정해요. 페이로드 크기, 파일 크기, 배치 사이즈, 가격 같은 거죠. Timer 는 시간(nanoseconds) 전용이에요.

사고 10: Micrometer Tracing 과 Metrics 의 의존성 분리 실수

원인 — Micrometer Tracing 을 쓰려면 micrometer-tracing-bridge-brave 또는 micrometer-tracing-bridge-otel 중 하나를 명시해야 해요. 이걸 빼면 Observation API 가 tracing 을 내보내지 않아요.

해결spring-boot-starter-actuator + 메트릭 레지스트리 + tracing bridge 세 가지를 세트로 의존성에 명시해요.

운영 권장 패턴

Pattern 1: 표준 Spring Boot + Prometheus 스택

<!-- pom.xml -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
    <groupId>io.micrometer</groupId>
    <artifactId>micrometer-registry-prometheus</artifactId>
    <scope>runtime</scope>
</dependency>
# application.yml
management:
  endpoints:
    web:
      exposure:
        include: health, info, prometheus, metrics
  metrics:
    tags:
      application: ${spring.application.name}
      environment: ${ENVIRONMENT:local}

이렇게만 해도 /actuator/prometheus 가 열리고 Prometheus 가 스크랩할 수 있어요.

Pattern 2: 커스텀 Meter 를 서비스 필드로 관리

@Service
public class OrderService {

    private final Counter createdCounter;
    private final Counter failedCounter;
    private final Timer processingTimer;

    public OrderService(MeterRegistry registry) {
        this.createdCounter = Counter.builder("orders.created")
            .description("Successfully created orders")
            .register(registry);
        this.failedCounter = Counter.builder("orders.failed")
            .description("Failed order attempts")
            .register(registry);
        this.processingTimer = Timer.builder("orders.processing.time")
            .description("Order processing latency")
            .publishPercentiles(0.5, 0.95, 0.99)  // p50, p95, p99
            .register(registry);
    }

    public Order createOrder(CreateOrderRequest req) {
        return processingTimer.record(() -> {
            try {
                Order order = doCreate(req);
                createdCounter.increment();
                return order;
            } catch (Exception e) {
                failedCounter.increment();
                throw e;
            }
        });
    }
}

Pattern 3: MeterBinder 로 외부 라이브러리 계측

외부 라이브러리나 내부 풀의 상태를 Micrometer 에 연결할 때 MeterBinder 를 써요.

@Component
public class CustomConnectionPoolMetrics implements MeterBinder {

    private final HikariDataSource dataSource;

    public CustomConnectionPoolMetrics(HikariDataSource dataSource) {
        this.dataSource = dataSource;
    }

    @Override
    public void bindTo(MeterRegistry registry) {
        Gauge.builder("db.pool.active", dataSource,
                ds -> ds.getHikariPoolMXBean().getActiveConnections())
            .description("Active DB connections")
            .register(registry);

        Gauge.builder("db.pool.idle", dataSource,
                ds -> ds.getHikariPoolMXBean().getIdleConnections())
            .description("Idle DB connections")
            .register(registry);
    }
}

Pattern 4: 멀티 레지스트리 (복합 백엔드)

운영 중 백엔드를 이중화하거나 SaaS + OSS 를 동시에 쓸 때 CompositeMeterRegistry 를 활용해요.

@Bean
public MeterRegistry meterRegistry() {
    CompositeMeterRegistry composite = new CompositeMeterRegistry();
    composite.add(new PrometheusMeterRegistry(PrometheusConfig.DEFAULT));
    composite.add(new DatadogMeterRegistry(datadogConfig, Clock.SYSTEM));
    return composite;
}

이렇게 하면 같은 메트릭이 Prometheus 와 Datadog 둘 다로 나가요.

Pattern 5: 공통 태그 자동화

팀 전체가 동일한 공통 태그 셋을 쓰도록 자동 설정을 박아요.

@Bean
MeterRegistryCustomizer<MeterRegistry> metricsCommonTags(
        @Value("${spring.application.name}") String appName) {
    return registry -> registry.config()
        .commonTags(
            "application", appName,
            "environment", System.getenv().getOrDefault("ENV", "local"),
            "version", getClass().getPackage().getImplementationVersion()
        );
}

Pattern 6: SLI 기반 alert 을 위한 histogram

단순 평균 latency 가 아니라 p99 기반 SLO 를 운영하려면 histogram 을 켜야 해요.

Timer sliTimer = Timer.builder("api.latency")
    .tag("endpoint", "/api/orders")
    .publishPercentiles(0.5, 0.95, 0.99)   // 클라이언트 사이드 percentile
    .publishPercentileHistogram()           // 서버 사이드 histogram (Prometheus histogram_quantile 용)
    .sla(Duration.ofMillis(100),            // SLO 버킷 경계
         Duration.ofMillis(300),
         Duration.ofMillis(1000))
    .register(registry);

publishPercentileHistogram() 을 켜면 Prometheus 에서 histogram_quantile(0.99, ...) 쿼리로 정확한 p99 를 계산할 수 있어요.

시험 직전 한 번 더 — Micrometer 큰 그림 압축 노트

Micrometer 의 자리

  • 메트릭의 SLF4J — 계측 코드는 한 번, 백엔드는 설정으로 교체
  • 앱 코드 ↔ 메트릭 백엔드 사이의 번역기
  • Spring Boot Actuator 가 자동 빈 주입

MeterRegistry 핵심

  • MeterRegistry = 모든 Meter 의 등록소
  • Meter 종류 — Counter(단조 증가) · Timer(시간+횟수) · Gauge(현재 값) · DistributionSummary(크기 분포) · LongTaskTimer · FunctionCounter
  • .register(registry) 없으면 아무것도 수집 안 됨
  • Meter 는 생성자/필드에서 한 번만 생성 후 재사용

Tag (dimensional metrics)

  • 이름 + Tag 조합 = 고유 시계열
  • 태그 값은 반드시 유한 집합 (동적 ID 금지)
  • common tags — 레지스트리 레벨 전역 설정 가능
  • cardinality 폭발 = 태그 값 무한 증가 → OOM 위험

지원 백엔드

  • Pull — Prometheus(/actuator/prometheus 노출)
  • Push — Datadog · CloudWatch · New Relic · StatsD · InfluxDB · OTLP
  • 전환 시 의존성 + 설정만 변경, 앱 코드 그대로

Observability 속 위치

  • 3 pillar 중 Metrics 생산 계층
  • Logs = SLF4J 계층 (별개)
  • Traces = Micrometer Tracing (Observation API 통합)

Observation API

  • Micrometer 1.10+에서 도입
  • 한 번 계측으로 Metrics + Traces 동시 생성
  • 구 Spring Cloud Sleuth 대체 (Spring Boot 3.x)
  • 구현체 — Brave bridge · OTel bridge 선택

사고

  • Micrometer = Prometheus 오해 (계측 ≠ 수집)
  • Counter ↔ Gauge 혼동 (총량 vs 현재값)
  • 태그에 동적 ID → cardinality 폭발
  • .register(registry) 누락 → 데이터 0
  • 같은 Meter 매 요청 생성 → 오버헤드
  • Timer 단위 수동 계산 → 실수 위험
  • Push step 설정 누락 → resolution 거침
  • Tracing bridge 의존성 누락

패턴

  • 표준 스택 — actuator + micrometer-registry-prometheus + yaml 설정
  • 커스텀 Meter — 서비스 필드로 선언, 생성자에서 한 번 등록
  • MeterBinder — 외부 라이브러리 상태를 Micrometer 에 연결
  • CompositeMeterRegistry — 복합 백엔드 동시 전송
  • 공통 태그 — MeterRegistryCustomizer 로 팀 표준화
  • SLI histogram — publishPercentileHistogram() + sla() 로 p99 SLO

공식 문서: Micrometer 공식 docs 에서 전체 Meter 타입 · 지원 백엔드 · Observation API 레퍼런스를 확인할 수 있어요.

시리즈 다른 편 (앞뒤 글 모음)

다음 글:

답글 남기기

error: Content is protected !!