애플리케이션에 비즈니스 메트릭 추가하여 모니터링하기

jjunhwan.kim·2023년 8월 13일
2

도커

목록 보기
6/6
post-thumbnail

개요

이전 포스트에서 스프링 액추에이터, 마이크로미터, 프로메테우스, 그라파나 등을 사용하여 컨테이너의 애플리케이션 모니터링 환경을 구축하였습니다. 스프링 액추에이터에서 기본으로 제공되는 메트릭을 프로메테우스에 연동하여 내부 데이터베이스에 저장하고, 그라파나의 대시보드에 프로메테우스에 저장된 데이터를 시각화하였습니다. 이번 포스트에서는 애플리케이션에 사용자 정의 메트릭을 추가하여 비즈니스에 특화된 부분을 모니터링 해보겠습니다.

사용자 정의 메트릭

스프링 액추에이터의 마이크로미터에서 제공되는 메트릭은 JVM(메모리 사용량 등), 시스템(CPU, 디스크 사용량 등), 톰캣, 데이터 소스, HTTP 요청 등 모든 애플리케이션에서 공통으로 사용할 수 있는 메트릭입니다. 사용자 정의 메트릭은 애플리케이션에서 제공하는 비즈니스 로직에 특화된 메트릭을 말합니다. 예를 들어 쇼핑 애플리케이션이라면 주문수, 주문 취소수, 재고 수량 같은 수치들을 모니터링하는 메트릭이 될 것 입니다.

프로메테우스 메트릭

기본적으로 프로메테우스의 메트릭은 게이지, 카운터로 분류할 수 있습니다. https://prometheus.io/docs/concepts/metric_types 를 참고하세요.

카운터

  • 카운터는 값이 증가하거나 0으로 초기화만 할 수 있는 메트릭입니다.
  • 따라서 값이 감소하는 측정 항목은 사용할 수 없습니다.
  • 예를 들면, HTTP 요청 수가 있습니다. 요청 수는 시간에 따라 증가 하기 때문에 카운터 메트릭을 사용합니다.

게이지

  • 게이지는 증가하거나 감소하는 값을 나타내는 메트릭입니다.
  • 주로 현재 상태 값을 보는데 사용합니다. 예를 들면 현재 재고 수량, 현재 메모리 사용량 등이 있습니다.

타이머

  • 타이머는 카운터와 유사한데, 실행 시간을 함께 측정할 수 있는 메트릭입니다.
  • 누적 실행 수(카운터), 실행 시간의 합, 최대 실행 시간(최근 1 ~ 3분 실행 중 가장 오래 걸린 실행 시간)을 측정할 수 있습니다.

예제 코드

본격적으로 애플리케이션에 사용자 정의 메트릭을 추가해보겠습니다. 먼저 예제 코드는 이전 포스트에서 프로메테우스, 그라파나를 연동한 커밋(https://github.com/nefertirii/docker-example/tree/f48f0c01d3ca52cec24b6666d818b37072b37cb2)에서 시작하겠습니다. 예제 프로젝트의 백엔드는 스프링 부트 애플리케이션입니다.

비즈니스 메트릭 정의

예제 프로젝트를 docker compose up -d 로 실행하고 http://localhost/posts 로 접속하면 간단한 게시판이 출력됩니다.

비즈니스 메트릭은 비즈니스마다 구현이 다를 수 밖에 없습니다. 여기서는 게시판에서 사용할 간단한 메트릭을 정의해보겠습니다.

  • 게시글 등록 요청 수, 게시글 삭제 요청 수
    • 게시글 등록 요청, 삭제 요청은 시간이 지남에 따라 계속 증가하므로 카운터를 사용합니다.
    • 게시글 등록은 카운터로 먼저 구현하고, 타이머로 수정해보겠습니다.
  • 현재 게시글 수
    • 현재 게시글은은 증가하거나 감소하므로 게이지를 사용합니다.

카운터 메트릭

기본적으로 메트릭 등록은 MeterRegistry 라고 하는 빈을 주입 받아서 사용합니다. MeterRegistry는 마이크로미터의 기능을 제공하는 컴포넌트입니다. MeterRegistry를 주입 받아 비즈니스 메서드에서 메트릭을 설정할 수 있습니다. 하지만 메트릭 로직 코드가 비즈니스 로직과 섞이기 때문에 스프링 AOP를 사용하여 분리합니다. 기본적으로 마이크로미터에서 어노테이션 기반으로 제공하므로 바로 사용해보겠습니다.

사용법은 간단합니다. @Counted 어노테이션을 측정을 원하는 메서드에 적용합니다. 아래 코드에서는 비즈니스 로직을 처리하는 PostService의 게시글 작성과 게시글 삭제 메서드에 적용하였습니다. 어노테이션의 파라미터는 메트릭 이름입니다. 아래에서는 my.posts 로 설정하였습니다.

그리고 아래와 같이 Config 클래스를 하나 만들어서 CountedAspect를 빈으로 등록합니다. @Counted 어노테이션을 인지하여 Counter를 사용하는 AOP를 적용합니다.

docker compose up -d --build backend 명령어를 통해 백엔드 서비스만 재빌드하여 실행합니다.

http://localhost:{백엔드 포트}/actuator/metrics 에서 메트릭을 조회합니다. 추가한 메트릭이 보이지 않습니다. 게시글을 하나 등록하고 나서 조회하면 아래와 같이 메트릭이 등록됩니다.

/actuator/metrics/my.posts 로 메트릭 값을 조회하면 아래와 같이 출력됩니다.

http://localhost:{백엔드 포트}/actuator/prometheus 에서 프로메테우스 포맷의 메트릭을 조회하면 아래와 같이 출력됩니다.

그라파나에서 대시보드에 아래와 같이 추가합니다. 카운터 메트릭은 값이 계속 증가하기 때문에 특정 시간에 얼마나 증가했는지 알 수 있는 increase() 또는 rate() 함수와 같이 사용합니다. Legend{{method}} 를 입력하면 실제 메서드 이름으로 등록됩니다.

아래와 같이 대시보드를 통해 최근 1분간 등록, 삭제 요청 수가 표시됩니다.

타이머 메트릭

타이머 메트릭은 카운터와 유사하면서 시간을 측정할 수 있는 기능을 제공합니다. 타이머는 누적 실행 수(카운터와 같음), 실행 시간의 합, 최대 실행 시간을 측정합니다. 최대 실행 시간은 약 1 ~ 3분간의 실행 중에 가장 오래 걸린 실행 시간을 표시해줍니다. 따라서 게이지라고 볼 수 있습니다.

타이머 메트릭은 @Timed 라는 어노테이션을 통해 AOP를 적용합니다.

이번에는 클래스 레벨에 @Timed 어노테이션을 적용해보겠습니다. 모든 메서드에 타이머가 적용됩니다.

카운터와 비슷하게 TimedAspect를 빈으로 등록하여 타이머 AOP를 활성화합니다.

/actuator/metrics/my.posts.time 으로 메트릭 값을 조회하면 아래와 같이 출력됩니다.

각 메서드의 실행된 누적 카운트 값, 전체 실행 시간의 합, 가장 오래 걸린 실행 시간 세 개의 값이 출력됩니다.

아래는 프로메테우스 포맷입니다. 아래와 같이 세 개의 값이 출력됩니다.

  • my_posts_time_seconds_max -> 가장 오래 걸린 실행 시간
  • my_posts_time_seconds_count -> 누적 실행 수
  • my_posts_time_seconds_sum -> 실행 시간 합

seconds_sum / seconds_count 를 통해 평균 실행 시간도 계산 가능합니다.

아래와 같이 my_posts_time_seconds_countincrease 함수를 사용하여 최근 1분의 실행 수를 표시합니다.

seconds_sum / seconds_countincrease 함수를 사용하여 최근 1분 평균 실행 시간도 구합니다. 마지막으로 seconds_max 는 그냥 출력해도 최근 1 ~ 3분간의 가장 오래 걸린 실행 시간을 출력해줍니다.

아래와 같이 대시보드가 구성됩니다.

게이지 메트릭

게이지 메트릭은 증가하거나 감소하는 값을 나타내는데 사용합니다. 현재 게시글 수를 게이지로 등록해보겠습니다. 먼저 비즈니스 로직에 현재 게시글 수를 리턴하는 메서드를 정의합니다.

MeterBinder 타입을 반환하는 빈을 등록하여 게이지를 등록합니다. 현재 게시글 수를 반환하는 메서드를 사용합니다.

/actuator/metrics/my.posts.size 로 메트릭 값을 조회하면 아래와 같이 출력됩니다.

아래는 프로메테우스 포맷입니다. my_posts_size 값이 현재 게시글 수 입니다.

그라파나에 아래와 같이 게이지 메트릭을 등록합니다.

구성된 대시보드입니다.

아래는 완성된 코드입니다.

https://github.com/nefertirii/docker-example/tree/fd6c86d8a69fd38a89bb748381ae39e91d610160

1개의 댓글

comment-user-thumbnail
2023년 8월 13일

좋은 정보 얻어갑니다, 감사합니다.

답글 달기