ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 메트릭 등록 - 카운터
    스프링/스프링부트 2023. 10. 3. 21:19

    공통으로 사용되는 메트릭인 공용 메트릭을 사용한다. 하지만, 우리 개인만의 메트릭을 만들어야할 수도 있다. 우리만의 기술이나 사용자의 요구사항에 따라 비즈니스 메트릭이 필요할 때가 있다.

     

     

    비즈니스의 실시간 주문, 취소, 실시간 재고 수량을 메트릭으로 등록하고 확인해볼 것이다.

     

     

     

    주문수, 취소수 - 카운터 사용(계속 증가)

    • 상품을 주문하면 주문수가 증가한다.
    • 상품을 취소해도 주문수는 유지한다. 대신에 취소수를 증가한다.

    재고 수량 - 게이지 사용(증가하거나 감소)

    • 상품을 주문하면 재고 수량이 감소한다.
    • 상품을 취소하면 재고 수량이 증가한다.
    • 재고 물량이 들어오면 재고 수량이 증가한다.

     

     

     

    MeterRegistry - 마이크로미터 기능을 제공하는 핵심 component

    기본적으로 다 스프링으로 등록되어 있으며 이 곳에서 카운터, 게이지를 등록해서 사용하면 된다.

     

     

    수동 등록

     

    OrderService interface

    public interface OrderService {
        void order();
        void cancel();
        AtomicInteger getStock(); // 멀티 쓰레드에서 값을 안전하게 증가시키는 타입
    }

     

     

     

    OrderServiceV1.class

    @Slf4j
    public class OrderServiceV1 implements OrderService {
    
        private final MeterRegistry registry;
    
        private AtomicInteger stock = new AtomicInteger(100);
    
        public OrderServiceV1(MeterRegistry registry) {
            this.registry = registry;
        }
    
        @Override
        public void order() {
            log.info("주문");
            stock.decrementAndGet();
    
            Counter counter = Counter.builder("my.order")
                    .tag("class", this.getClass().getName())
                    .tag("method", "order")
                    .description("order")
                    .register(registry);
    
            counter.increment(); // 메트릭 값이 1 증가됨
        }
    
        @Override
        public void cancel() {
            log.info("취소");
            stock.incrementAndGet();
    
            Counter.builder("my.order") // 메트릭 name
                    .tag("class", this.getClass().getName())
                    .tag("method", "cancel") // 위의 2개는 tag인데, 메트릭 이름은 같고 tag로 구분짓기
                    .description("order") // 카운터를 MeterRegistry에 등록
                    .register(registry).increment(); // 카운터의 값을 하나 증가시킴
        }
    
        @Override
        public AtomicInteger getStock() {
            return stock;
        }
    }

    MeteryRegistry를 이용해서 메트릭을 만드는 것이다. Counter.builder에서 첫번째 파라미터는 메트릭의 name이다. 그 뒤로는 tag, description, register가 있는데 tag는 메트릭이 무슨 메트릭인지 구분짓는 것이며, description은 메트릭의 설명, register는 registry를 넣어주는 것이다. 최종적으로 increment()를 통해 호출될 때마다 카운터의 값을 하나씩 증가시킨다.

     

     

    OrderController.class

    @RestController
    @Slf4j
    public class OrderController {
    
        private final OrderService orderService;
    
        public OrderController(OrderService orderService) {
            this.orderService = orderService;
        }
    
        @GetMapping("/order")
        public String order() {
            log.info("order");
            orderService.order();
            return "order";
        }
    
        @GetMapping("/cancel")
        public String cancel() {
            log.info("cancel");
            orderService.cancel();
            return "cancel";
        }
    
        @GetMapping("/stock")
        public int stock() {
            log.info("stock = {}", orderService.getStock().get());
            return orderService.getStock().get();
        }
    }

    코드를 실행시키면 localhost:8080/actuator/metrics에 my.order가 포함된다.

     

     

    이렇게 엔드포인트를 잡으면 특정 메서드에 대한 정보를 얻을 수도 있다.

     

     

    그라파나에 접근해서 my_order_total{method="order"}를 통해 메트릭을 지표화할 수 있다.

    이전 포스팅에서도 봤듯이 카운터는 한눈에 파악하기 힘들기 때문에 increase()를 사용했다.

     

     

     

     

    하지만 비즈니스 로직에 카운터가 들어가서 좋은 설계가 아니다. 이럴 때에 사용하려고 스프링 AOP가 존재하는 것이다.

     

    마이크로미터는 이런 상황에 맞춰진 AOP 구성이 이미 있다.

     

     

    @Counted

    @Slf4j
    public class OrderServiceV2 implements OrderService {
    
        // private final MeterRegistry registry; 사용하지 않음
    
        private AtomicInteger stock = new AtomicInteger(100);
    
        @Counted("my.order")
        @Override
        public void order() {
            log.info("주문");
            stock.decrementAndGet();
        }
    
        @Counted("my.order")
        @Override
        public void cancel() {
            log.info("취소");
            stock.incrementAndGet();
        }
    
        @Override
        public AtomicInteger getStock() {
            return stock;
        }
    }

    그냥 측정을 원하는 메서드에 @Counted("my.order")라 적어주기만 하면 된다. 괄호 안의 my.order는 메트릭 이름이 되며 tag는 method의 이름이 자동으로 들어간다.

     

     

     

    OrderConfigV2 - 중요!!!

    @Configuration
    public class OrderConfigV2 {
        
        @Bean
        public OrderService orderService() {
            return new OrderServiceV2();
        }
        
        @Bean
        public CountedAspect countedAspect(MeterRegistry registry) {
            return new CountedAspect(registry);
        }
    }

    여기서 단순히 Service만 스프링 빈으로 등록하는 것이 아니라 CountedAspect도 빈으로 등록해줘야 한다.

    여기서 MeterRegistry를 넣어주며 이렇게 해야지만 @Counted가 인지되어 Counter를 사용하는 AOP가 적용되는 것이다.

     

     

    method와 class가 자동으로 tag로 들어간다. 또한, result와 exception까지 추가해준다.

     

    그라파나 대시보드에도 똑같은 패널에 이미 들어가있다. 프로메테우스 쿼리가 동일하기 때문에 같은 이름의 그래프가 만들어진 것인데, 노란색과 주황색이 잘 만들어진 것을 확인할 수 있다.

     

     

     

    @Counted 메서드를 사용하면 카운터를 쉽게 적용할 수 있다.

    '스프링 > 스프링부트' 카테고리의 다른 글

    메트릭 등록 - 게이지  (0) 2023.10.03
    메트릭 등록 - Timer  (0) 2023.10.03
    그라파나 - 공유 대시보드 활용  (0) 2023.10.02
    그라파나 - 대시보드 만들기  (0) 2023.10.02
    그라파나 - 설치 및 연동  (0) 2023.10.02
Designed by Tistory.