-
메트릭 등록 - 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