SPRING/Spring Boot

[SpringBoot] 커스텀 메트릭(Metric) 등록하기 - 카운터(Counter)

IT록흐 2023. 5. 16. 00:46
반응형
 

[SpringBoot] 커스텀 메트릭(Metric) 등록하기

[SpringBoot] 메트릭(Metric) 이란? [SpringBoot] 모니터링 - 엑츄에이터(Actuator)(1) 개발이 완료되면 App을 모니터링해야 한다. ( Production-Ready ) App상태정보, 트래픽, DB상태정보 등등 다양한 모니터링 데이터

lordofkangs.tistory.com

 

 

이전 포스팅에서 커스텀 메트릭 등록을 위한 간단한 예제프로그램을 만들어 보았다.

이번 포스팅에서는 예제 프로그램을 활용하여 커스텀 메트릭을 만들어 보겠다.

 

 

 

 

 

 

1) 카운터 ( Counter )

시간에 따라 '증가'만하는 데이터이다. 주문수는 항상 증가한다. 중간에 감소하지 않는다.

2) 게이지 ( Gauage )

시간에 따라 '증가' '감소'를 반복하는 데이터이다. 재고량은 쌓였다가 줄었다가 반복한다. 

3) 타이머 ( Timer )

시간과 관련된 데이터이다. 실행횟수,실행시간의 합, 최장실행시간 등 시간과 관련된 정보를 제공한다. 

 

 

카운터(Counter)

 

MeterResistry는 데이터를 메트릭으로 등록하는 마이크로미터 모듈이다. MeterResistry는 스프링이 자동으로 IOC컨테이너에 Bean으로 등록하므로 의존관계 주입만 하면 사용할 수 있다.

 

OrderConfig 클래스

@Configuration
public class OrderConfig {
    @Bean // MeterRegistry Bean 객체 주입
    public OrderService orderService(MeterRegistry meterRegistry){  
        return new OrderServiceV0(meterRegistry);
    }
}

 

설정클래스에서 Bean등록할 때 MeterRegistry 객체를 주입해준다.

 

OrderServiceV0 클래스

package com.example.demo.orderservice;

import io.micrometer.core.instrument.Counter;
import io.micrometer.core.instrument.MeterRegistry;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.atomic.AtomicInteger;

@Slf4j
@RequiredArgsConstructor
public class OrderServiceV0 implements OrderService{

    private final MeterRegistry meterRegistry; 
    private AtomicInteger stock = new AtomicInteger(100);

    @Override
    public void order() {
        log.info("주문...");
        stock.decrementAndGet();

        //카운터 등록 ( 주문수 )
        Counter.builder("my.order") // 이름
                .tag("class",this.getClass().getName()) // 태그1 ( class )
                .tag("method","order") // 태그2 (method)
                .description("order") // 설명
                .register(meterRegistry).increment(); // register : 등록,  increment()_: 메트릭 measurments 속성의 value + 1
    }

    @Override
    public void cancel() {
        log.info("주문취소...");
        stock.incrementAndGet();
        //카운터 등록 ( 취소수 )
        Counter.builder("my.order") // 이름 
                .tag("class",this.getClass().getName()) // 태그1 ( class )
                .tag("method","cancel") // 태그2 ( method )
                .description("order") // 설명 
                .register(meterRegistry).increment();  // register : 등록,  increment()_: 메트릭 measurments 속성의 value + 1
    }

    @Override
    public AtomicInteger getStock() {
        return stock;
    }
}

 

 

두 클래스를 제외하고는 나머지 코드는 이전과 동일하다.

그럼 실행시켜보겠다.

 

▹ 주문수행 : http://localhost:8080/order

 취소수행 : http://localhost:8080/cancel 

 

주문과 실행을 수행한 후, 메트릭값이 잘 나오는지 확인해보자.

 

메트릭 정보 확인 : http://localhost:8080/actuator/metrics/my.order

 

JSON 방식으로 메트릭이 생성되었음을 확인할 수 있다. 나는 주문과 취소를 총 3회 수행해서 호출횟수의 VALUE가 3이다.  availableTags 는 해당 메트릭에 등록된 태그를 보여준다. 우리는 method 태그와 class 태그를 추가해서 위와 같다.

 

 

AOP로 코드 리팩토링하기

 

Counter로 커스텀 메트릭을 생성하는 과정의 코드가 반복된다. 이는 AOP를 사용하면 코드를 줄여줄 수 있다. 

 

 

이전 코드는 개발자가 직접 MeterRegistry를 조작했다. 이번에는 MeterRegistry를 주입받은 CountedAspect에게 메트릭 생성을 일임할 것이다. CountedAspect 객체가 Bean으로 등록하면 @Counted 어노테이션이 달린 메소드들을 읽고 메트릭으로 자동등록한다. 이렇게 되면 개발자가 굳이 메트릭 등록 코드를 짤 필요가 사라진다.

 

build.gradle에 AOP 의존관계를 하나 추가한다. 

implementation 'org.springframework.boot:spring-boot-starter-aop'

 

OrderConfig 클래스

@Configuration
public class OrderConfig {
    @Bean // CountedAspect Bean으로 등록하기 ( MeterRegistry 주입 )
    public CountedAspect countedAspect(MeterRegistry meterRegistry){
        return new CountedAspect(meterRegistry);
    }
    @Bean // OrderService 버전업 Bean등록
    public OrderService orderService(){
        return new OrderServiceV1();
    }
}

 

CountedAspect 객체를 Bean으로 등록하였다. 그리고 OrderService는 리팩토링 된 OrderServiceV1으로 버전 업그레이드 하였다.

 

OrderServiceV1 클래스 

@Slf4j
public class OrderServiceV1 implements OrderService{
    private AtomicInteger stock = new AtomicInteger(100);

    @Override
    @Counted("my.order") // 어노테이션 하나로 메트릭 생성
    public void order() {
        log.info("주문...");
        stock.decrementAndGet();
    }

    @Override
    @Counted("my.order") // 어노테이션 하나로 메트릭 생성
    public void cancel() {
        log.info("주문취소...");
        stock.incrementAndGet();
    }

    @Override
    public AtomicInteger getStock() {
        return stock;
    }
}

 

코드가 확실히 단순해졌다. 

어노테이션에 이름만 정해주면 알아서 여러 태그와 정보를 넣어서 메트릭을 생성한다. 

그럼 프로젝트를 재실행하여 메트릭데이터를 확인해보자. 

 

URL : http://localhost:8080/actuator/metrics/my.order

// 20230516003356
// http://localhost:8080/actuator/metrics/my.order

{
  "name": "my.order",
  "measurements": [
    {
      "statistic": "COUNT",
      "value": 2.0
    }
  ],
  "availableTags": [
    {
      "tag": "result",
      "values": [
        "success"
      ]
    },
    {
      "tag": "exception",
      "values": [
        "none"
      ]
    },
    {
      "tag": "method",
      "values": [
        "cancel",
        "order"
      ]
    },
    {
      "tag": "class",
      "values": [
        "com.example.demo.orderservice.OrderServiceV1"
      ]
    }
  ]
}

 

 

이전과 달리 result, exception 태그가 추가되었다. AOP로 리팩토링된 코드도 잘 출력됨을 확인하였다. 

 

 

 URL : http://localhost:8080/actuator/prometheus

마이크로미터는 JSON메트릭을 프로메테우스용 메트릭 변형본도 제공한다. 프로메테우스는 해당 URL로 일정주기로 접근하여 메트릭을 수집한다. my.order는 my_order_total로 이름이 바뀌었다. 카운테 메트릭은 끝에 _total로 바뀐다. 

 

 

 

프로메테우스, 그라파나 연동하기 

 

프로메테우스 서버를 실행하고 SpringBoot 프로젝트와 연동하였다.

 

 

[Prometheus] 프로메테우스 연동하기 ( With SpringBoot )

프로메테우스(Prometheus)란? Application을 모니터링하려면 다양한 데이터를 수집해야 한다. 시간이 지남에 따라 추이가 변하는 데이터를 메트릭(Metric)이라고 하는데, CPU사용량, 메모리 사용량 등이

lordofkangs.tistory.com

 

위 그림과 같이,

spring-actuator Endpoint의 status가 up이면 정상적으로 연동이 완료된 것이다.

 

그라파나 서버를 실행하고 Prometheus와 연동하였다.

 

 

[Grafana] 그라파나 연동하기 ( With SpringBoot, Prometheus )

그라파나(Grafana)란? 시간이 지남에 따라 추이가 변하는 데이터를 메트릭(Metric)이라 부른다. CPU 사용률, 메모리 사용률, 트래픽 등이 메트릭(Metric)에 해당된다. 메트릭은 시간별로 데이터가 수집

lordofkangs.tistory.com

 

 

그라파나는 프로메테우스에 쿼리를 보내 데이터를 가져온다. 

 

 주문메트릭쿼리 : increase(my_order_total{method="order"}[1m])

 취소메트릭쿼리 : increase(my_order_total{method="cancel"}[1m])

 

그럼 대시보드를 만들고 주문과 취소를 연속으로 수행하여 주문수와 취소수의 카운트의 추이가 시각화 되는지 보자.

 

▹ 주문수행 : http://localhost:8080/order

 취소수행 : http://localhost:8080/cancel 

 

 

 

주문수와 취소수는 카운터로 항상 '증가'만 한다. 우리가 원하는 데이터는 시간대별 증가'추이'이다.

 

주문수는 증가하지만 주문추이는 감소할 수 있다. 

취소수는 증가하지만 취소추이는 감소할 수 있다.

 

위 차트처럼 증가했다가 잠시감소했다가 다시 증가하는 이유는 increase()를 사용해서이다. increase를 사용하면 증가추이를 확인할 수 있다. 이렇게 커스텀 메트릭도 데이터가 시각화를 완료하였다. 마이크로미터가 제공하는 기본 메트릭이 아닌 커스텀 메트릭도 마이크로미터에 등록할 수 있다.

 

 


 

 

참고자료

 

스프링 부트 - 핵심 원리와 활용 - 인프런 | 강의

실무에 필요한 스프링 부트는 이 강의 하나로 모두 정리해드립니다., - 강의 소개 | 인프런

www.inflearn.com

 

 

 

 

 

 

반응형