Micrometer 입문 1편. 메트릭의 벤더 중립 facade — MeterRegistry · dimensional metrics(태그) · 지원 백엔드(Prometheus · Datadog · CloudWatch · New Relic · StatsD) · Observability 3 pillar 속 위치 · Observation API/Tracing 개요. 앱이 메트릭을 내보내는 계측 계층의 큰 그림.
이 글은 Micrometer 입문에서 운영까지 시리즈 1편이에요. 9편 풀 시리즈의 시작이고, 첫 글은 큰 그림을 잡는 자리예요. Micrometer 가 무엇인지, 왜 "메트릭의 SLF4J"라고 불리는지, MeterRegistry 와 태그가 어떻게 맞물리는지, 어떤 백엔드를 지원하는지를 한 번에 정리해요. 메트릭을 시각화하는 Grafana 시리즈와 연결해서 읽으면 관측 스택 전체가 한 그림으로 잡혀요.
이 시리즈는 Micrometer 공식 문서, Spring Boot Actuator 공식 가이드, 여러 observability 학습 자료 등 공개 자료를 참고해 한국어 학습 노트로 풀어쓴 자료입니다.
Spring Boot 프로젝트에 spring-boot-starter-actuator 와 micrometer-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 레퍼런스를 확인할 수 있어요.
시리즈 다른 편 (앞뒤 글 모음)
다음 글: