Spring Boot Actuator Metrics

Spring Boot Actuator를 추가하면 Micrometer 관련된 디펜던시를 추가하고, 자동설정(auto-configuration)을 해준다. 스프링부트는 CompositeMeterRegistry를 자동설정하고 클래스패스에서 찾은 MeterRegistry를 CompositeMeterRegistry에 등록한다. 새로운 MeterRegistry을 등록하려면 micrometer-registry-{system} 디펜던시를 런타임으로 추가해주면 된다. 또한 스프링부트는 자동설정한 MeterRegistry를 Metrics 클래스의 글로벌 스태틱 변수에 등록한다. 아래와 같이 MeterRegistry를 주입받고 Meter를 생성해서 사용하면 된다.

@Component
public class SampleBean {

    private final Counter counter;

    public SampleBean(MeterRegistry registry) {
        this.counter = registry.counter("received.messages");
    }

    public void handleMessage(String message) {
        this.counter.increment();
        // handle message implementation
    }

}

가능하면 스프링이 관리하는 MeterRegistry를 사용하는것이 좋다. Metrics의 정적 메소드는 가급적 사용하지 않는게 좋다. Metrics의 정적 메소드는 스프링이 관리하지 않는 global registry를 사용한다.

메트릭이 다른 빈에 의존하는 경우, MeterBind를 사용하면 좋다.

public class MyMeterBinderConfiguration {

    @Bean
    public MeterBinder queueSize(Queue queue) {
        return (registry) -> Gauge.builder("queueSize", queue::size).register(registry);
    }

}

MeterBind는 애플리케이션이나 컴포넌트에서 메트릭을 반복적으로 수집하는 경우에 유용할 수 있다. 기본적으로 MeterBind 빈의 모든 메트릭은 자동으로 Spring이 관리하는 MeterRegistry에 등록된다.

Registry를 추가로 설정하기 위해서 MeterRegistryCustomizer 빈을 등록할 수 있다. 아래는 공통 태그를 적용하는 예이다.

@Configuration(proxyBeanMethods = false)
public class MyMeterRegistryConfiguration {

    @Bean
    public MeterRegistryCustomizer<MeterRegistry> metricsCommonTags() {
        return (registry) -> registry.config().commonTags("region", "us-east-1");
    }

}

제네릭 타입에 특정한 타입을 지정하여, 특정 Registry만 커스터마이징 할 수 있다.

@Configuration(proxyBeanMethods = false)
public class MyMeterRegistryConfiguration {

    @Bean
    public MeterRegistryCustomizer<GraphiteMeterRegistry> graphiteMetricsNamingConvention() {
        return (registry) -> registry.config().namingConvention(this::name);
    }

    private String name(String name, Meter.Type type, String baseUnit) {
        return ...
    }

}

스프링부트는 MeterBinder 구현체를 제공해서 다양한 메트릭을 자동을 수집해준다.

스프링부트는 적용 가능한 경우 아래와 같은 메트릭을 수집한다.

  • JVM Metrics: JVM 관련된 메트릭 이름은 jvm. 으로 시작한다.
    • 스레드 사용률
    • 가비지 컬렉션 관련 메트릭
    • 다양한 메모리 및 버퍼풀
    • 로드/언로드된 클래스의 수
  • System Metrics
    • CPU Metrics
    • File Descriptor Metrics
    • Uptime Metrics
    • Disk space available
  • Kafka Consumer Metrics
  • ThreadPoolTaskExecutor, ThreadPoolTaskScheduler 메트릭
  • Log4j2 Metrics
  • Logback Metrics
  • Tomcat Metrics
  • Spring Integration Metrics
  • Spring MVC Metrics
  • Spring WebFlux Metrics
  • Http Client Metrics: RestTemplate, WebClient와 관련된 메트릭을 제공한다.
    • auto-configure된 빌더를 주입받아서, 객체를 생성해야 메트릭이 수집된다.
    • 또는 MetricsRestTemplateCustomizer, MetricsWebClientCustomizer 를 사용해서 수동으로 메트릭을 제공할 수 있다.
    • 관련된 메트릭 이름은 http.client.requests 으로 시작한다.
  • Jersey Server Metrics
  • Cache Metrics
  • DataSource Metrics
  • Spring Data Repository Metrics
    • Spring Boot는 Spring Data Repository 메소드 호출과 관련된 메트릭을 제공한다.
    • 메트릭 이름은 spring.data.repository.invocations 으로 시작한다.
    • @Timed 애노테이션은 Repository 클래스 및 메소드에 적용할 수 있다. 모든 레포지토리 메소드 호출에 대한 메트릭을 기록하지 않으려면 management.metrics.data.repository.autotime.enabled를 false로 설정하고, 메트릭 수집이 필요한 메소드(또는 클래스)에만 @Timed 애노테이션을 적용하면 된다.
  • Hibernate Metrics
    • org.hibernate:hibernate-micrometer 가 클래스패스에 존재하면 EntityManagerFactory 관련된 메트릭을 제공한다.
    • EntityManagerFactory 빈이름이 태그로 지정된다.
    • EntityManagerFactory 관련된 메트릭을 제공하려면 통계가 활성화 되어야 한다. hibernate.generate_statisticstrue로 설정하면 통계를 활성화 할 수 있다.
  • RabbitMQ Metrics

자세한 내용은 spring boot - production ready metrics meter 를 참고하길 바란다.

@Timed 애노테이션 지원

@Timed 애노테이션을 클래스 또는 메소드 레벨에 적용할 수 있다. 아래와 같이 클래스 레벨에 적용하는 경우, @RestController의 모든 요청과 관련된 메트릭을 수집한다.

@RestController
@Timed
public class MyController {

    @GetMapping("/api/addresses")
    public List<Address> listAddress() {
        return ...
    }

    @GetMapping("/api/people")
    public List<Person> listPeople() {
        return ...
    }

}

특정 메소드에 세부 정보를 변경하려는 경우, 아래와 같이 메소드 레벨과 클래스 레벨 애노테이션을 함께 사용할 수 있다.

@RestController
@Timed
public class MyController {

    @GetMapping("/api/addresses")
    public List<Address> listAddress() {
        return ...
    }

    @GetMapping("/api/people")
    @Timed(extraTags = { "region", "us-east-1" })
    @Timed(value = "all.people", longTask = true)
    public List<Person> listPeople() {
        return ...
    }

}

Kafka Metrics

스프링은 카프카 메트릭을 수집과 관련해서 자동설정을 위한 KafkaMetricsAutoConfiguration 클래스를 제공한다. KafkaMetricsAutoConfiguration 의 경우 MBeanServer가 빈으로 등록된 경우에만 KafkaConsumerMetrics 빈을 등록하기 때문에 spring.jmx.enabledtrue 로 설정해야만 동작한다.

KafkaConsumerMetrics 는 아래와 같은 메트릭을 수집한다.

consumer fetch manager metrics

  • records-lag : 파티션의 가장 최근 LAG
  • records-lag-avg : 파티션의 평균 LAG
  • records-lag-max : 해당 window에 최대 LAG
  • records-lead : The latest lead of the partition
  • records-lead-min : The min lead of the partition.
  • records-lead-avg : The average lead of the partition.
  • fetch-size-avg : 요청당 가져오는 평균 bytes 수
  • records-per-request-avg : 요청당 평균 레코드 수
  • bytes-consumed-total : 컨슘한 bytes 총 수
  • records-consumed-total : 컨슘한 레코드 총 수
  • fetch-total : fetch 요청 총 수
  • fetch-latency-avg : fetch 요청의 평균 latency
  • fetch-latency-max : fetch 요청의 최대 latency
  • fetch-throttle-time-avg : 평균 throttle 시간. quotas가 활성화 된 경우 브로커는 제한을 초과한 컨슈머를 제한하기 위해 fetch 요청을 지연시킨다. 이 메트릭은 fetch 요청에 throttling 시간이 평균적으로 얼마나 더해졌는지를 나타낸다.
  • fetch-throttle-time-max : 최대 throttle 시간

consumer coordinator-metrics

  • assigned-partitions : 컨슘머에 할당된 파티션 수
  • commit-rate : 초당 커밋이 호출된 횟수
  • join-rate : 초당 조인요청을 보낸 횟수
  • sync-rate : 초당 sync 요청을 보낸 횟수. Group synchronization는 rebalance 프로토콜의 두번째이자 마지막 단계로 해당 같이 높으면 컨슈머 그룹이 불안정하다는것을 나타낸다.
  • hearbeat-rate : 초당 hearbeat 요청을 보낸 횟수
  • commit-latency-avg : 커밋 요청에 소요된 평균 시간
  • commit-latency-max : 커밋 요청에 소요된 최대 시간
  • join-time-avg : 그룹에 rejoin 하는데 걸린 평균 시간
  • join-time-max : 그룹에 rejoin 하는데 걸린 최대 시간. 해당 값이 session timeout보다 크면 안된다.
  • heartbeat-response-time-max : heartbeat 요청에 대한 응답을 받는데까지 소요된 최대 시간
  • last-hearbeat-seconds-ago : 마지막 heartbeat 이후 지난 시간

consumer metrics

  • connection-count : active 커넥션 개수
  • connection-creation-total : 새롭게 생성된 커넥션 개수
  • connection-close-total : close된 커넥션 개수
  • io-ratio : I/O 스레드가 I/O 작업을 하는데 소요된 시간의 비율
  • io-wait-ratio : I/O 스레드가 wating 하는데 소요된 시간의 비율
  • select-total : I/O 계층에서 새로운 I/O를 수행하기 위해 체크한 횟수
  • io-time-ns-avg : The average length of time for I/O per select call
  • io-wait-time-ns-avg : The average length of time the I/O thread spent waiting for a socket to be ready for reads or writes
  • network-io-total : 받은 바이트 총 수
  • outgoing-byte-total : 전송된 바이트 총 수
  • request-total : 요청의 총 수
  • response-total : 응답의 총 수
  • io-waittime-total : Time spent on the I/O thread waiting for a socket to be ready for reads or writes.
  • iotime-total : Time spent in I/O during select calls.

자세한 사항은 confluent-new-consumer-metrics, KafkaConsumerMetrics 클래스를 참고