ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 메트릭 등록 - Timer
    스프링/스프링부트 2023. 10. 3. 21:55

    Timer는 카운터와 유사한데 실행 시간도 함께 측정해주는 기능이다.

     

     

    Timer 는 다음과 같은 내용을 한번에 측정해준다.

    • seconds_count : 누적 실행 수 - 카운터
    • seconds_sum : 실행 시간의 합 - sum
    • seconds_max : 최대 실행 시간(가장 오래걸린 실행 시간) - 게이지

    최대 실행 시간은 평생 유지되는게 아니라 내부에 타임 윈도우라는 개념이 있어서 1~3분 마다 최대 실행 시간이 다시 갱신된다.

     

     

    수동 등록

     

    Timer도 자동으로 등록하는 @Timed 어노테이션이 존재하지만 일단 수동 등록부터 정리하겠다.

     

    @Slf4j
    public class OrderServiceV3 implements OrderService {
    
        private final MeterRegistry registry;
    
        private AtomicInteger stock = new AtomicInteger(100);
    
        public OrderServiceV3(MeterRegistry registry) {
            this.registry = registry;
        }
    
        @Override
        public void order() {
            Timer timer = Timer.builder("my.order")
                    .tag("class", this.getClass().getName())
                    .tag("method", "order")
                    .description("order")
                    .register(registry);
    
            timer.record(() -> {
                log.info("주문");
                stock.decrementAndGet(); // 내부 로직 실행 시간을 측정
                sleep(500); // 로직이 너무 빨리 끝나는 것을 방지
            });
        }
    
        @Override
        public void cancel() {
            Timer timer = Timer.builder("my.order")
                    .tag("class", this.getClass().getName()) .tag("method", "cancel")
                    .description("order")
                    .register(registry);
            
            timer.record(() -> {
                log.info("취소");
                stock.incrementAndGet();
                sleep(200);
            });
        }
    
        private static void sleep(int l) {
            try {
                Thread.sleep(l + new Random().nextInt(200));
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    
        @Override
        public AtomicInteger getStock() {
            return stock;
        }
    }

    Timer.builder를 사용하고 메트릭 name, tag, description, register는 이전과 동일하다.

     

    timer.recored() 안에 측정하고 싶은 비즈니스 로직을 넣어주면 된다.

    이때, 너무 빨리 끝나는 것을 방지하기 위해 sleep()을 넣어줘서 500~700ms의 실행 시간을 임의로 넣어줬다.

    (취소는 0.2~0.4초 사이)

     

     

    OrderConfigV3.class

    @Configuration
    public class OrderConfigV3 {
    
        @Bean
        OrderService orderService(MeterRegistry registry) {
            return new OrderServiceV3(registry);
        }
    }

     

     

    localhost:8080/actuator/metrics/my.order로 접근하면 count, total_time, max의 정보가 나오게 된다. 여기서 count와 total_time의 값은 계속 증가하며 max는 실행을 하면서 최댓값이 되면 갱신된다.

     

     

    주문수는 카운터 - increase() 함수 사용, 최대 실행 시간은 게이지로 나타냈다.

     

     

     

    @Timed

    @Timed 어노테이션을 통해 AOP를 적용시킬 수 있다.

    @Timed("my.order")
    @Slf4j
    public class OrderServiceV4 implements OrderService {
    
        private AtomicInteger stock = new AtomicInteger(100);
    
    
        @Override
        public void order() {
                log.info("주문");
                stock.decrementAndGet(); // 내부 로직 실행 시간을 측정
                sleep(500); // 로직이 너무 빨리 끝나는 것을 방지
        }
    
        @Override
        public void cancel() {
                log.info("취소");
                stock.incrementAndGet();
                sleep(200);
        }
    
        private static void sleep(int l) {
            try {
                Thread.sleep(l + new Random().nextInt(200));
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    
        @Override
        public AtomicInteger getStock() {
            return stock;
        }
    }

    @Timed 어노테이션은 각각의 메서드가 아니라 클래스 선언부에 어노테이션을 선언한다. 물론 메서드 단위로 해도 된다.

     

    괄호 안에 메트릭 이름을 적어주면 된다. 타입에 적용하면 해당 타입의 모든 public 메서드에 타이머가 적용된다.

     

    이 경우는 getStock()도 public이기 때문에 타이머가 적용이 된다.

     

     

    @Configuration
    public class OrderConfigV4 {
    
        @Bean
        OrderService orderService() {
            return new OrderServiceV4();
        }
        
        @Bean
        public TimedAspect timedAspect(MeterRegistry registry) {
            return new TimedAspect(registry);
        }
    }

    Configuration에 TimedAspect를 스프링 빈으로 무조건 등록해줘야지 AOP를 사용할 수 있다.

     

     

    결과는 위와 동일한데, @Timed 어노테이션을 사용하면 훨씬 편리하다.

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

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