엑츄에이터와 마이크로미터
스프링 엑츄에이터를 기반으로 한 많은 모니터링 툴들이 있다. 하지만 이러한 모니터링 툴들은 쌓인 엑츄에이터의 정보를 받아올 때 여러 다른 형식으로 데이터를 받아간다. 스프링은 이러한 환경에서 항상 추상화를 통하여 표준 방식을 개발자에게 제공한다.
이 경우에도 마이크로미터를 통한 추상화를 통하여 여러 다른 형식의 포맷을 표준화하였다.
마이크로미터와 액츄에이터가 제공하는 메트릭에는 매우 다양한 정보들이 있다. 전체적인 애플리케이션의 health 체크 및 시스템에 대한 메트릭은 기본적으로 제공해 준다.
하지만 애플리케이션의 비즈니스 로직에서의 의미 있는 지표를 뽑아내고 싶다면 어떻게 해야 할까??
사용자 메트릭일 정의하여 수집 설정을 할 수 있다.
카운트 예제 1)
- registry를 의존하여 로직 안에서 직접 생성
@Slf4j
@RequiredArgsConstructor
public class OrderServiceV1 implements OrderService {
private final MeterRegistry registry;
private AtomicInteger stock = new AtomicInteger(100);
@Override
public void order() {
log.info("주문");
stock.decrementAndGet();
Counter.builder("my.order")
.tag("class", this.getClass().getName())
.tag("method", "order")
.description("order")
.register(registry).increment();
}
@Override
public void cancel() {
log.info("취소");
stock.incrementAndGet();
Counter.builder("my.order")
.tag("class", this.getClass().getName())
.tag("method", "cancel")
.description("order")
.register(registry).increment();
}
}
카운터 예제 2)
- 위 방식은 서비스 로직과 다른 기능을 하는(모니터 로그를 수집하는) 기능이 로직안에 포함되어 있다.
- 마이크로미터의 AOP 방식으로 관점 분리할 수 있으며 Bean을 생성해주어야 한다.
@Configuration
public class OrderConfigV2 {
@Bean
public CountedAspect countedAspect(MeterRegistry registry) {
return new CountedAspect(registry);
}
@Bean
OrderService orderService() {
return new OrderServiceV2();
}
}
@Slf4j
@RequiredArgsConstructor
public class OrderServiceV2 implements OrderService {
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();
}
}
타이머 예제 1)
- registry를 의존하여 로직 안에서 직접 생성
@RequiredArgsConstructor
public class OrderServiceV3 implements OrderService {
private final MeterRegistry registry;
private AtomicInteger stock = new AtomicInteger(100);
@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);
});
}
}
타이머 예제 2)
- 카운터 예제와 동일
@Configuration
public class OrderConfigV4 {
@Bean
public TimedAspect countedAspect(MeterRegistry registry) {
return new TimedAspect(registry);
}
@Bean
OrderService orderService() {
return new OrderServiceV4();
}
}
@Timed(value = "my.order")
@RequiredArgsConstructor
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);
}
}
참고로 진행 중인 프로젝트에 적용하였을 때 정의한 이름의 메트릭이 생성되지 않아 진짜 몇 시간 동안 삽질을 했는데 혹시나 해서 api를 하나 찍어보니 메트릭이 생성되었다. config와 어노테이션으로 정의만 하는 것이 아니라 실제 호출 되었을 때 DB에 정보가 쌓여야 메트릭 정보도 확인이 가능하였다.... 자다가도 생각날 만큼 왜 안될까 고민을 너무 많이 함 ㅋㅋㅋ
마지막으로...
김영한 강사님의 로드맵을 끝 마치며 정말 항상 감사하고 마지막 말씀이 너무 감동이라 (T인데도 불구하고) 모든 로드맵 강의에 별점을 5점 박을수 밖에 없었다... 더욱 정진하겠습니다.
참고자료
김영한 : 스프링 부트 - 핵심 원리와 활용
스프링 부트 - 핵심 원리와 활용 | 김영한 - 인프런
김영한 | 실무에 필요한 스프링 부트는 이 강의 하나로 모두 정리해드립니다., 백엔드 개발자를 위한 스프링 부트 끝판왕! 실무에 필요한 내용을 모두 담았습니다. [임베딩 영상] 김영한의 스
www.inflearn.com
'Spring' 카테고리의 다른 글
@FeignClient 기본 세팅 (0) | 2024.05.21 |
---|---|
Spring 외부설정 2 (Profile 사용 예) (0) | 2024.05.06 |
배포 서버 ClassNotFoundException 트러블 슈팅 (0) | 2024.05.02 |
커스텀 익셉션 적용 (0) | 2024.04.28 |
Spring boot 의 외부 설정 (1) | 2024.04.27 |