본문 바로가기
Lecture/김영한 - 스프링 부트 - 핵심 원리와 활용

스프링 부트 - 핵심 원리와 활용 - 모니터링 메트릭 활용

by Soono991 2023. 3. 12.

💡이 포스팅은 김영한 님의 인프런 강의인 스프링 부트 - 핵심 원리와 활용을 수강하고 학습한 내용을 정리한 포스팅입니다.

 

김영한 님의 강의를 수강하며 정리한 GitHub Repository입니다.

 

 

GitHub - kiekk/inflearn-kyh-spring-boot

Contribute to kiekk/inflearn-kyh-spring-boot development by creating an account on GitHub.

github.com

 

이번 챕터에 대해 정리할 내용은 다음과 같습니다.

  • 메트릭(Metric)

 

이전 포스팅에서도 메트릭이라는 단어를 사용하면서 따로 설명을 하지는 않았었는데, 이번 챕터가 메트릭을 다루기 때문에 이 포스팅에서 정리해 보도록 하겠습니다.

 

메트릭(Metric)이란?

저의 기준에서는 메트릭이란 용어를 자주 사용하거나 들어본 용어는 아니기 때문에 어떤 뜻인지를 먼저 알고 넘어가면 좋을 것 같습니다.

 

영한님 강의 학습 후 저는 메트릭을 측정 지표라고 이해했습니다.

 

따라서 CPU, JVM, Connection 메트릭이라고 한다면 CPU 메트릭에서는 CPU 사용량, CPU 개수와 같이 CPU에 관련된 정보(지표)를 확인할 수 있고, JVM 메트릭에서는 JVM 힙 사용량 등등 그리고 Connection 메트릭에서는 Connection 총 개수와 Connection 사용량 등등의 정보를 확인할 수 있습니다.

 

🔔 추가로 이번 강의는 아니지만 인프런의 다른 강의에서도 이와 같은 질문을 하신 분이 있어 참고용으로 링크를 남겨놓겠습니다.

 

 

액추에이터의 metrics 엔드포인트를 통해 액추에이터에서 제공하는 다양한 메트릭 정보들을 확인할 수도 있습니다.

http://localhost:8080/actuator/metrics

 

Actuator Metrics 확인하기

metrics 엔드포인트를 통해 메트릭 목록을 확인할 수 있으며 /actuator/metrics/{name}을 통해 메트릭의 상세 정보를 확인할 수도 있습니다.

http://localhost:8080/actuator/metrics/{name}

 

 

위와 같이 /actuator/metrics/jvm.memory.used 엔드 포인트를 통해 jvm 메모리 사용량을 확인해 봤습니다.

이렇게 특정 메트릭의 상세 정보를 확인할 수 있는데 한 가지 특이한 점은 메트릭 상세 정보에는 avilableTags라는 항목이 있습니다.

 

이 항목에는 객체 형태로 다시 tag, values 항목이 존재하는데 tag 항목을 통해 해당 메트릭의 정보를 필터링해서 확인할 수 있습니다.

사용법
tag=KEY:VALUE

ex) tag=area:heap

 

 

area 태그를 사용해서 jvm 메모리 중 힙 메모리와 힙이 아닌 메모리로 분류해서 데이터를 확인할 수 있습니다.

 

Actuator가 제공하는 기본 Metrics

액추에이터는 기본적으로 다음과 같은 메트릭 정보들을 제공합니다.

 

  • JVM 메트릭 : JVM 관련 메트릭을 제공하며 jvm. 으로 시작합니다.
    • 메모리 및 버퍼 풀 세부 정보
    • 가비지 수집 관련 통계
    • 스레드 활용
    • 로드 및 언로드 된 클래스 수
    • JVM 버전 정보
    • JIT 컴파일 시간
  • 시스템 메트릭: 시스템 메트릭을 제공하며 system. , process. , disk. 으로 시작합니다.
    • CPU 지표
    • 파일 디스크립터 메트릭
    • 가동 시간 메트릭
    • 사용 가능한 디스크 공간
  • 애플리케이션 시작 메트릭: 애플리케이션 시작 메트릭을 제공하며 application.started., application.ready. 으로 시작합니다.
  • 스프링 MVC 메트릭: 스프링 MVC 컨트롤러가 처리하는 모든 요청을 다룹니다. 아래 tag를 활용해 정보를 분류할 수 있습니다.
    • uri: 요청 URI
    • method: GET, POST 같은 HTTP 메서드
    • status: 200, 400, 500 같은 HTTP Status 코드
    • exception: 예외
    • outcome: 상태코드를 그룹으로 모아서 확인
  • 데이터소스 메트릭: DataSource, 커넥션 풀에 관한 메트릭을 확인할 수 있으며 jdbc.connections. 으로 시작합니다.
    • 최대 커넥션
    • 최소 커넥션
    • 할당 커넥션
    • 대기 커넥션
  • 로그 메트릭: logback 로그에 대한 메트릭을 확인할 수 있으며 logback.events 로 시작합니다.
  • 톰캣 메트릭: tomcat. 으로 시작합니다.

 

이 외에도 여러 메트릭들이 제공되는데 더 자세한 내용은 공식 문서를 참고하시면 좋을 것 같습니다.

 

Custom Metrics 등록

액추에이터에서 제공하는 Metric 외에 비즈니스에 의해 발생되는 정보들을 관리하고 싶은 경우에는 이를 직접 메트릭으로 만들어야 합니다.

 

이전 포스팅에서도 설명했듯이 액추에이터는 표준 측정 방법을 위해 마이크로미터를 사용하기 때문에 직접 메트릭을 등록할 경우에도 마이크로미터를 사용하여 메트릭을 등록해야 합니다.

 

액추에이터는 마이크로미터 기능을 제공하는 MeterRegistry를 제공합니다.

 

@Slf4j
public class OrderServiceV1 implements OrderService {

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

    public OrderServiceV1(MeterRegistry registry) {
        this.registry = registry;
    }

    @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();
    }

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

 

이제 api end point를 만들어서 작성한 order(), cancel()을 호출하면 이후 메트릭 목록을 조회할 때 작성한 메트릭이 추가되어 있는 것을 확인할 수 있습니다.

 

 

하지만 위 방식은 비즈니스 로직에 메트릭 등록/수집 로직이 추가되어 있습니다.

이를 해결하기 위해서는 AOP 이용하면 되는데 마이크로미터는 이런 방식을 지원하는 annotation을 제공하고 있습니다.

 

@Slf4j
public class OrderServiceV2 implements OrderService {

    private final 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 annotation을 사용할 때 주의할 점은 CountedAspect를 빈으로 등록해야 합니다.

 

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

    @Bean
    public CountedAspect countedAspect(MeterRegistry registry) {
        return new CountedAspect(registry);
    }
}

 

🔔 @CountedCountedAspect, @TimedTimedAspect를 각각 빈으로 등록해야 합니다.

 

Metric Type

메트릭은 크게 3가지로 분류할 수 있습니다.

  • Counter
  • Gauge
  • Timer

 

Counter

카운터는 단순히 증가하는 단일 누적 측정 항목입니다.

카운터 메트릭은 값을 증가하거나 또는 0으로 초기화하는 것만 가능합니다.

 

Gauge

게이지는 임의로 오르내릴 수 있는 단일 숫자 값을 나타내는 메트릭입니다.

값의 현재 상태를 보는 데 사용하며 값이 증가하거나 감소할 수 있습니다.

 

Timer

타이머의 경우 시간을 측정하는 데 사용합니다.

카운터와 유사하지만 Timer를 사용하면 실행 시간도 함께 측정할 수 있습니다.

Timer는 다음 내용을 한 번에 측정해 줍니다.

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

댓글