spring boot/actuator in spring boot

spring boot 3.x + actuator 파헤치기. 10. about metrics endpoint ( Gauge )

Hello World Study 2023. 4. 9. 18:34

https://youtu.be/oGJlKymgixc

 

metrics 중 Gauge 타입에 대해 알아보겠습니다.

 

이전에 다룬 Counter 타입의 경우 이름 그대로 횟수값을 다루는데 주로 사용합니다. queue 에 push 된 횟수, 상품 주문 횟수, 취소 횟수, http 요청 횟수, 에러 횟수 등등에 사용됩니다. 따라서 양수값만 사용되고 값이 작아지지 않습니다. ( Counter api 단에서 increment 메서드만 제공되지, decrement 메서드가 없습니다. )

 

Gauge 는 자동차 속도 계기판과 같이 커졌다 작아졌다 할 수 있는 값에 사용됩니다. 보통 cpu usage, mem usage , 사용중인 thread count, 사용중인 connection pool count 등에 사용됩니다. thread count 라고 해서 Counter 를 쓰는게 맞지 않냐? 라고 생각할 수 있으나 사용중인 thread count는 커졌다 작아졌다 할 수 있으므로 Gauge 가 맞습니다.

 

Counter 의 경우 해당 counter 값을 조회시도 하는지 여부와 무관하게, counter 값이 증가될때마다 내부값 갱신을 해줘야 합니다.  그래야 누락없이 횟수를 알 수 있으니까요. 

 

그러나 Gauge 의 경우, 조회시도 할때만 해당 값을 계산하면 됩니다. cpu usage 를 예로 들자면, cpu usage 를 actuator 를 통해 노출할 필요가 있을때 cpu usage 관련 클래스를 이용해서 값을 조회한 후 Gauge metric 타입으로 노출하면 됩니다. 따라서 일반적으로 아래처럼 특정 metric 를 관리하는 객체를 파라미터로 전달하는 형식으로 등록하게 됩니다.

Gauge gauge = Gauge
    .builder("mygauge", myObj, myObj::gaugeValue)  <-- 객체와 객체내의 메서드를 전달
    .register(registry);

즉 Counter 에서 다룬 FunctionCounter 와 동일한 형식입니다.

FunctionCounter counter = FunctionCounter
    .builder("mycounter", state, state -> state.count())    
    .register(registry);

 

테스트를 위해 임의로 특정 값을 리턴하는 service 를 아래와 같이 만들었습니다. 

kafka 와 같은 queue 에 대기중인 수를 리턴하는 service 라고 가정하겠습니다. 이 값은 커졌다 작아졌다 할 수 있으니 Counter 가 아닌 Gauge 가 적절합니다.

@Service
public class QueueManager {

    public long getQueueSize() {
        return System.currentTimeMillis();  // queue에 대기중인 데이터의 수를 리턴하는것으로 가정
    }
}

위 service 를 활용해서 gauge 로 등록하는 코드는 아래와 같습니다.

@Configuration
@RequiredArgsConstructor
public class GaugeConfig {

    private final QueueManager queueManager;

    private final MeterRegistry meterRegistry;

    @PostConstruct
    public void register() {
        Gauge gauge = Gauge
                .builder("my.queue.size", queueManager, queueManager -> {
                    return queueManager.getQueueSize();
                })
                .register(meterRegistry);

    }
}

생성한 gauge 변수는 사실 더 사용할 곳이 없으므로 굳이 변수를 만들 필요는 없습니다. 

my.queue.size 로 이름을 등록했으므로 아래처럼 url을 입력하면 값이 잘 나오는걸 알 수 있습니다.

기존 코드를 보면 QueueManager bean 와 MeterRegistry bean이 필요해서 생성자 주입을 받았습니다. 이렇게 다른 bean이 필요한 경우가 대부분이므로, 좀 더 편리하게 사용하라고 MeterBinder 라는 인터페이스가 제공되며, 아래처럼 MeterBinder 를 implement 한건 bean으로 등록하면 필요한 bean들은 자동으로 주입이 됩니다. 따라서 아래 방법이 좀 더 좋은 방법이라고 볼 수 있습니다.

@Configuration
public class GaugeConfigWithMeterBinder {

    @Bean
    public MeterBinder queueSize(QueueManager queueManager) {
        return new MeterBinder() {
            @Override
            public void bindTo(MeterRegistry registry) {
                Gauge.builder("my.queue2.size", queueManager, queueManager -> {
                    return queueManager.getQueueSize();
                }).register(registry);
            }
        };
    }
}

 

사용된 소스코드는 아래에서 확인할 수 있습니다.

https://github.com/ChunGeun-Yu/spring-actuator-study/tree/gaugeMetrics


이제 metric 에서는 timer 밖에 남지 않았습니다.