Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[spring] actuator와 모니터링 #47

Open
backtony opened this issue Mar 19, 2023 · 0 comments
Open

[spring] actuator와 모니터링 #47

backtony opened this issue Mar 19, 2023 · 0 comments

Comments

@backtony
Copy link
Owner

backtony commented Mar 19, 2023

actuator

implementation 'org.springframework.boot:spring-boot-starter-actuator' 

http://localhost:8080/actuator 를 실행해보면 현재 actuator가 지원하는 url을 제공해준다.
기본적으로는 제한된 url만 제공하는데 yml로 허용해줄 수 있다.

엔드포인트를 활성화 한다는 것은 해당 기능 자체를 사용할지 말지 on, off를 선택하는 것이다. 엔드포인트를 노출하는 것은 활성화된 엔드포인트를 HTTP에 노출할지 아니면 JMX에 노출할지 선택하는 것이다. 엔드포인트를 활성화하고 추가로 HTTP를 통해서 웹에 노출할지, 아니면 JMX를 통해서 노출할지 두 위치에 모두 노출할지 노출 위치를 지정해주어야 한다. 물론 활성화가 되어있지 않으면 노출도 되지 않는다.
그런데 엔드포인트는 대부분 기본으로 활성화 되어 있다.( shutdown 제외) 노출이 되어 있지 않을 뿐이다. 따라서 어떤 엔드포인트를 노출할지 선택하면 된다. 참고로 HTTP와 JMX를 선택할 수 있는데, 보통 JMX 는 잘 사용하지 않으므로 HTTP에 어떤 엔드포인트를 노출할지 선택하면 된다.

management:
  endpoints:
    web:
      exposure:
        include: "*"

* 옵션은 모든 엔드포인트를 웹에 노출하는 것이다. 참고로 shutdown 엔드포인트는 기본으로 활성화되지 않기 때문에 노출도 되지 않는다. 엔드포인트 활성화 + 엔드포인트 노출이 둘다 적용되어야 사용할 수 있다.

management:
    endpoint:
      shutdown:
        enabled: true
    endpoints:
      web:
        exposure:
          include: "*"

특정 엔드포인트를 활성화 하려면 management.endpoint.{엔드포인트명}.enabled=true 를 적용하면 된다.


management:
    endpoints:
      web:
        exposure:
          include: "*"
          exclude: "env,beans"

모두 포함시키고, exclude를 통해 제외시킬 수도 있다.

다양한 엔드포인트

각각의 엔드포인트를 통해서 개발자는 애플리케이션 내부의 수 많은 기능을 관리하고 모니터링 할 수 있다. 스프링 부트가 기본으로 제공하는 다양한 엔드포인트에 대해서 알아보자. 다음은 자주 사용하는 기능 위주로 정리했다.

  • beans : 스프링 컨테이너에 등록된 스프링 빈을 보여준다.
  • conditions : condition 을 통해서 빈을 등록할 때 평가 조건과 일치하거나 일치하지 않는 이유를 표시한다.
  • configprops : @ConfigurationProperties 를 보여준다.
  • env : Environment 정보를 보여준다.
  • health : 애플리케이션 헬스 정보를 보여준다.
  • httpexchanges : HTTP 호출 응답 정보를 보여준다. HttpExchangeRepository 를 구현한 빈을 별도로 등록해야 한다.
  • info : 애플리케이션 정보를 보여준다.
  • loggers : 애플리케이션 로거 설정을 보여주고 변경도 할 수 있다.
  • metrics : 애플리케이션의 메트릭 정보를 보여준다.
  • mappings : @RequestMapping 정보를 보여준다.
  • threaddump : 쓰레드 덤프를 실행해서 보여준다.
  • shutdown : 애플리케이션을 종료한다. 이 기능은 기본으로 비활성화 되어 있다.

https://docs.spring.io/spring-boot/docs/current/reference/html/actuator.html#actuator.endpoints

전체 엔드포인트는 공식 메뉴얼을 참고하자.

헬스 정보

헬스 정보를 사용하면 애플리케이션에 문제가 발생했을 때 문제를 빠르게 인지할 수 있다.
헬스 정보는 단순히 애플리케이션이 요청에 응답을 할 수 있는지 판단하는 것을 넘어서 애플리케이션이 사용하는 데이터베이스가 응답하는지, 디스크 사용량에는 문제가 없는지 같은 다양한 정보들을 포함해서 만들어진다.

 management:
    endpoint:
      health:
        show-details: always

위 옵션을 사용하면 health에 대한 매우 세세한 정보를 알려준다. 만약 상태정보만 간략하게 알고 싶다면 다음과 같이 사용한다.

management:
    endpoint:
      health:
        show-components: always

만약 표기된 내용중에 하나라도 down 이면 전체 status는 down이 된다.

애플리케이션 정보

  • info 엔드포인트는 애플리케이션의 기본 정보를 노출한다.
    • localhost:8080/actuator/info

기본으로 제공하는 기능들은 다음과 같다.

  • java : 자바 런타임 정보
  • os: OS 정보
  • env : Environment 에서 info. 로 시작하는 정보
  • build : 빌드 정보, META-INF/build-info.properties 파일이 필요하다.
  • git : git 정보, git.properties 파일이 필요하다.

env, java, os는 기본으로 비활성화 되어 있다.

management:
    info:
        java:
            enabled: true
        os:
            enabled: true
        env:
            enabled: true

info: 
    app:
        name: hello-actuator
        company: yh

env는 info에 하위에 적어두면 해당 내용을 보여준다.

빌드 정보는 직접 파일을 설정하는게 아니라 build.gradle에 아래 내용을 추가해주면 된다.

springBoot {
      buildInfo()
}

git 정보는 플러그인만 추가하면 된다.

plugins { 
    id "com.gorylenko.gradle-git-properties" version "2.4.1" //git info
    }

로거

loggers 엔드포인트를 사용하면 로깅과 관련된 정보를 확인하고, 또 실시간으로 변경할 수도 있다. 코드를 통해서 알아보자.

로그를 별도로 설정하지 않으면 스프링 부트는 기본으로 INFO 를 사용한다. 실행 결과를 보면 ROOT 의 configuredLevel 가 INFO 인 것을 확인할 수 있다. 따라서 그 하위도 모두 INFO 레벨이 적용된다.

실시간 로그 레벨 변경

개발 서버는 보통 DEBUG 로그를 사용하지만, 운영 서버는 보통 요청이 아주 많다. 따라서 로그도 너무 많이 남기 때문에 DEBUG 로그까지 모두 출력하게 되면 성능이나 디스크에 영향을 주게 된다. 그래서 운영 서버는 중요하다고 판단되는 INFO 로그 레벨을 사용한다.
그런데 서비스 운영중에 문제가 있어서 급하게 DEBUG 나 TRACE 로그를 남겨서 확인해야 확인하고 싶다면 어떻게 해야할까? 일반적으로는 로깅 설정을 변경하고, 서버를 다시 시작해야 한다.
loggers 엔드포인트를 사용하면 애플리케이션을 다시 시작하지 않고, 실시간으로 로그 레벨을 변경할 수 있다.

POST http://localhost:8080/actuator/loggers/{로그 레벨 바꾸고자 하는 로거 이름}
{
      "configuredLevel": "TRACE"
}

POST로 전달하는 내용 JSON , content/type 도 application/json 으로 전달해야 한다. 요청에 성공하면 204 응답이 온다.(별도의 응답 메시지는 없다.)

액츄에이터와 보안

보안 주의

액츄에이터가 제공하는 기능들은 우리 애플리케이션의 내부 정보를 너무 많이 노출한다. 그래서 외부 인터넷 망이 공개된 곳에 액츄에이터의 엔드포인트를 공개하는 것은 보안상 좋은 방안이 아니다. 액츄에이터의 엔드포인트들은 외부 인터넷에서 접근이 불가능하게 막고, 내부에서만 접근 가능한 내부망을 사용하는 것이 안전하다.

액츄에이터를 다른 포트에서 실행

예를 들어서 외부 인터넷 망을 통해서 8080 포트에만 접근할 수 있고, 다른 포트는 내부망에서만 접근할 수 있다면 액츄에이터에 다른 포트를 설정하면 된다.
액츄에이터의 기능을 애플리케이션 서버와는 다른 포트에서 실행하려면 다음과 같이 설정하면 된다. 이 경우 기존 8080 포트에서는 액츄에이터를 접근할 수 없다.

management.server.port=9292  

경로 변경

management:
    endpoints:
      web:
        base-path: "/manage"
  • /actuator/{엔드포인트} 대신에/manage/{엔드포인트}로 변경된다.

마이크로미터

1

예를 들어서 CPU, JVM, 커넥션 정보 등을 JMX 툴에 전달한다고 가정해보자. 그러면 각각의 정보를 JMX 모니터링 툴이 정한 포멧에 맞추어 측정하고 전달해야 한다.

2

그런데 중간에 사용하는 모니터링 툴을 변경하면 어떻게 될까? 기존에 측정했던 코드를 모두 변경한 툴에 맞도록 다시 변경해야 한다. 개발자 입장에서는 단순히 툴 하나를 변경했을 뿐인데, 측정하는 코드까지 모두 변경해야 하는 문제가 발생한다. 이런 문제를 해결하는 것이 바로 마이크로미터라(Micrometer)는 라이브러리이다.

마이크로미터 구조

3

  • 마이크로미터는 애플리케이션 메트릭 파사드라고 불리는데, 애플리케이션의 메트릭(측정 지표)을 마이크로미터가 정한 표준 방법으로 모아서 제공해준다.
  • 쉽게 이야기해서 마이크로미터가 추상화를 통해서 구현체를 쉽게 갈아끼울 수 있도록 해두었다.
  • 보통은 스프링이 이런 추상화를 직접 만들어서 제공하지만, 마이크로미터라는 이미 잘 만들어진 추상화가 있기 때문에 스프링은 이것을 활용한다. 스프링 부트 액츄에이터는 마이크로미터를 기본으로 내장해서 사용한다.

메트릭 확인하기

CPU, JVM, 커넥션 사용 등등 수 많은 지표들을 어떻게 수집해야 할까?
개발자가 각각의 지표를 직접 수집해서 그것을 마이크로미터가 제공하는 표준 방법에 따라 등록하면 된다. 다행히도 마이크로미터는 다양한 지표 수집 기능을 이미 만들어서 제공한다. 그리고 스프링 부트 액츄에이터는 마이크로미터가 제공하는 지표 수집을 @autoConfiguration 을 통해 자동으로 등록해준다.
쉽게 이야기해서 스프링 부트 액츄에이터를 사용하면 수 많은 메트릭(지표)를 편리하게 사용할 수 있다.

metrics 엔드포인트

http://localhost:8080/actuator/metrics

metrics 엔드포인트를 사용하면 기본으로 제공되는 메트릭들을 확인할 수 있다.

http://localhost:8080/actuator/metrics/{name}
metrics 엔드포인트는 다음과 같은 패턴을 사용해서 더 자세히 확인할 수 있다.

http://localhost:8080/actuator/metrics/jvm.memory.used 에 접속해보면 jvm 메모리 사용량을 확인할 수 있는데 화면을 보면 availableTags가 보인다.
availableTags는 Tag 필터라고 부른다.

jvm 메모리를 확인하면 아래와 같은 태그가 보인다.

  • tag:area , values[heap, nonheap]
  • tag:id , values[G1 Survivor Space, ...]

해당 Tag를 기반으로 정보를 필터링해서 확인할 수 있다. tag=key:value와 같은 형식을 사용한다.

http://localhost:8080/actuator/metrics/jvm.memory.used?tag=area:heap 로 검색하면 이는 jvm 메모리중에 heap메모리만 필터링해서 알려주는 것이라고 보면 된다.

다양한 메트릭

마이크로미터와 액츄에이터가 기본으로 제공하는 다양한 메트릭을 확인해보자.

  • JVM 메트릭
  • 시스템 메트릭
  • 애플리케이션 시작 메트릭
  • 스프링 MVC 메트릭
  • 톰캣 메트릭
  • 데이터 소스 메트릭
  • 로그 메트릭
  • 기타 수 많은 메트릭이 있다.

사용자가 메트릭을 직접 정의하는 것도 가능하다.

JVM 메트릭

JVM 관련 메트릭을 제공한다. jvm. 으로 시작한다.

  • 메모리 및 버퍼 풀 세부 정보
  • 가비지 수집 관련 통계
  • 스레드 활용
  • 로드 및 언로드된 클래스 수
  • JVM 버전 정보
  • JIT 컴파일 시간

시스템 메트릭

시스템 메트릭을 제공한다.
system. , process. , disk. 으로 시작한다.

  • CPU 지표
  • 파일 디스크립터 메트릭
  • 가동 시간 메트릭
  • 사용 가능한 디스크 공간

애플리케이션 시작 메트릭

  • application.started.time : 애플리케이션을 시작하는데 걸리는 시간 ( ApplicationStartedEvent 로 측정)
  • application.ready.time : 애플리케이션이 요청을 처리할 준비가 되는데 걸리는 시간 ( ApplicationReadyEvent 로 측정)

스프링은 내부에 여러 초기화 단계가 있고 각 단계별로 내부에서 애플리케이션 이벤트를 발행한다.

  • ApplicationStartedEvent : 스프링 컨테이너가 완전히 실행된 상태이다. 이후에 커맨드 라인 러너가 호출된다.(순수하게 스프링 뜨는 시간)
  • ApplicationReadyEvent : 커맨드 라인 러너가 실행된 이후에 호출된다.(스프링 뜬다음에 부가 작업한 뒤에 찍히는 시간)

스프링 MVC 메트릭

  • 스프링 MVC 컨트롤러가 처리하는 모든 요청을 다룬다.
  • 메트릭 이름: http.server.requests
    • localhost:8080/actuator/metrics/http.server.requests

TAG 를 사용해서 다음 정보를 분류해서 확인할 수 있다.

  • uri : 요청 URI
  • method : GET , POST 같은 HTTP 메서드
  • status : 200 , 400 , 500 같은 HTTP Status 코드 exception : 예외
  • outcome : 상태코드를 그룹으로 모아서 확인 1xx:INFORMATIONAL , 2xx:SUCCESS , 3xx:REDIRECTION , 4xx:CLIENT_ERROR , 5xx:SERVER_ERROR

데이터소스 메트릭

  • DataSource , 커넥션 풀에 관한 메트릭을 확인할 수 있다.
  • jdbc.connections. 으로 시작한다.
  • 최대 커넥션, 최소 커넥션, 활성 커넥션, 대기 커넥션 수 등을 확인할 수 있다.
  • 히카리 커넥션 풀을 사용하면 hikaricp. 를 통해 히카리 커넥션 풀의 자세한 메트릭을 확인할 수 있다.

로그 메트릭

  • logback.events : logback 로그에 대한 메트릭을 확인할 수 있다.
  • trace, debug, info, warn, error 각각의 로그 레벨에 따른 로그 수를 확인할 수 있다.
  • 예를 들어서 error 로그 수가 급격히 높아진다면 위험한 신호로 받아드릴 수 있다.

톰캣 메트릭

  • 톰캣 메트릭은 tomcat. 으로 시작한다.
  • 톰캣 메트릭을 모두 사용하려면 다음 옵션을 켜야한다. (옵션을 켜지 않으면 tomcat.session. 관련 정보만 노출된다.)
server:
    tomcat:
      mbeanregistry:
        enabled: true

톰캣의 최대 쓰레드, 사용 쓰레드 수를 포함한 다양한 메트릭을 확인할 수 있다.


프로메테우스와 그라파나

  • 프로메테우스
    • 애플리케이션에서 발생한 메트릭을 그 순간만 확인하는 것이 아니라 과거 이력까지 함께 확인하려면 메트릭을 보관하는 DB가 필요하다. 이렇게 하려면 어디선가 메트릭을 지속해서 수집하고 DB에 저장해야 한다. 프로메테우스가 바로 이런 역할을 담당한다.
  • 그라파나
    • 프로메테우스가 DB라고 하면, 이 DB에 있는 데이터를 불러서 사용자가 보기 편하게 보여주는 대시보드가 필요하다. 그라파나는 매우 유연하고, 데이터를 그래프로 보여주는 툴이다. 수 많은 그래프를 제공하고, 프로메테우스를 포함한 다양한 데이터소스를 지원한다.

4

  1. 스프링 부트 액츄에이터와 마이크로미터를 사용하면 수 많은 메트릭을 자동으로 생성한다.
    • 마이크로미터 프로메테우스 구현체는 프로메테우스가 읽을 수 있는 포멧으로 메트릭을 생성한다.
  2. 프로메테우스는 이렇게 만들어진 메트릭을 지속해서 수집한다.
  3. 프로메테우스는 수집한 메트릭을 내부 DB에 저장한다.
  4. 사용자는 그라파나 대시보드 툴을 통해 그래프로 편리하게 메트릭을 조회한다. 이때 필요한 데이터는 프로메테우스를 통해서 조회한다.

프로메테우스 - 애플리케이션 설정

https://prometheus.io/download/

프로메테우스는 메트릭을 수집하고 보관하는 DB이다.
프로메테우스가 애플리케이션의 메트릭을 수집하도록 하려면 2가지 작업이 필요하다.

  1. 애플리케이션 설정: 프로메테우스가 애플리케이션의 메트릭을 가져갈 수 있도록 애플리케이션에서 프로메테우스 포멧에 맞추어 메트릭 만들기
  2. 프로메테우스 설정: 프로메테우스가 우리 애플리케이션의 메트릭을 주기적으로 수집하도록 설정

프로메테우스가 애플리케이션의 메트릭을 가져가려면 프로메테우스가 사용하는 포멧에 맞추어 메트릭을 만들어야 한다.
참고로 프로메테우스는 /actuator/metrics 에서 보았던 포멧(JSON)은 이해하지 못한다. 마이크로미터가 이런 부분은 모두 해결해준다.

5

각각의 메트릭들은 내부에서 마이크로미터 표준 방식으로 측정되고 있다. 따라서 어떤 구현체를 사용할지 지정만 해주면 된다.

implementation 'io.micrometer:micrometer-registry-prometheus' //추가
  • 마이크로미터 프로메테우스 구현 라이브러리를 추가한다.
  • 이렇게 하면 스프링 부트와 액츄에이터가 자동으로 마이크로미터 프로메테우스 구현체를 등록해서 동작하도록 설정해준다.
  • 액츄에이터에 프로메테우스 메트릭 수집 엔드포인트가 자동으로 추가된다.

프로메테우스 - 수집 설정

프로메테우스가 애플리케이션의 /actuator/prometheus 를 호출해서 메트릭을 주기적으로 수집하도록 설정해보자.
프로메테우스 폴더에 있는 prometheus.yml 파일을 수정하자.

# prometheus.yml
- job_name: "spring-actuator"
  metrics_path: '/actuator/prometheus'
  scrape_interval: 1m
  static_configs:
    - targets: ['localhost:8080']

수집 주기는 성능에 영향을 줄 수 있으므로 운영에서는 10초에서 1m를 권장하며 기본값은 1m이다.

프로메테우스 - 기본 기능

검색창에 http_server_requests_seconds_count 를 입력하고 실행해보자.
6

  • 태그, 레이블: error , exception , instance , job , method , outcome , status , uri 는 각각의 메트릭 정보를 구분해서 사용하기 위한 태그이다. 마이크로미터에서는 이것을 태그(Tag)라 하고, 프로메테우스에서는 레이블(Label)이라 한다. 여기서는 둘을 구분하지 않고 사용하겠다.
  • 숫자: 끝에 마지막에 보면 132 , 4 와 같은 숫자가 보인다. 이 숫자가 바로 해당 메트릭의 값이다.
  • Table Evaluation time 을 수정해서 과거 시간 조회 가능
  • Graph 메트릭을 그래프로 조회 가능

필터

레이블을 기준으로 필터를 사용할 수 있다. 필터는 중괄호( {} ) 문법을 사용한다.

  • = 제공된 문자열과 정확히 동일한 레이블 선택
  • != 제공된 문자열과 같지 않은 레이블 선택
  • =~ 제공된 문자열과 정규식 일치하는 레이블 선택
  • !~ 제공된 문자열과 정규식 일치하지 않는 레이블 선택

예시

  • uri=/log , method=GET 조건으로 필터
    • http_server_requests_seconds_count{uri="/log", method="GET"}
  • /actuator/prometheus 는 제외한 조건으로 필터
    • http_server_requests_seconds_count{uri!="/actuator/prometheus"}
  • method 가 GET , POST 인 경우를 포함해서 필터
    • http_server_requests_seconds_count{method=~"GET|POST"}
  • /actuator 로 시작하는 uri 는 제외한 조건으로 필터
    • http_server_requests_seconds_count{uri!~"/actuator.*"}

sum

  • sum : 값의 합계를 구한다.
    • 예) sum(http_server_requests_seconds_count)
  • sum by
    • sum by(method, status)(http_server_requests_seconds_count)
    • SQL의 group by 기능과 유사하다.

count

  • count(http_server_requests_seconds_count)
  • 메트릭 자체의 수 카운트

topk

  • topk(3, http_server_requests_seconds_count)
  • 상위 3개 메트릭 조회

오프셋 수정자

  • http_server_requests_seconds_count offset 10m
  • offset 10m 과 같이 나타낸다. 현재를 기준으로 특정 과거 시점의 데이터를 반환한다.

범위 벡터 선택기

  • http_server_requests_seconds_count[1m]
  • 마지막에 [1m] , [60s] 와 같이 표현한다. 지난 1분간의 모든 기록값을 선택한다.

참고로 범위 벡터 선택기는 차트에 바로 표현할 수 없다. 데이터로는 확인할 수 있다. 범위 벡터 선택의 결과를 차트에 표현하기 위해서는 약간의 가공이 필요하다.

프로메테우스 - 게이지와 카운터

7

  • 게이지(Gauge)
    • 임의로 오르내일 수 있는 값
    • 예) CPU 사용량, 메모리 사용량, 사용중인 커넥션

8

  • 카운터(Counter)
    • 단순하게 증가하는 단일 누적 값
    • 예) HTTP 요청 수, 로그 발생 수

쉽게 이야기해서 게이지는 오르락 내리락 하는 값이고, 카운터는 특정 이벤트가 발생할 때 마다 그 수를 계속 누적하는 값이다.

HTTP 요청 메트릭을 그래프로 표현해보자. 카운터는 계속 누적해서 증가하는 값이다. 따라서 계속 증가하는 그래프만 보게 될 것이다. 이렇게 증가만 하는 그래프에서는 특정 시간에 얼마나 고객의 요청이 들어왔는지 한눈에 확인하기 매우 어렵다. 이런 문제를 해결하기 위해 increase() , rate() 같은 함수를 지원한다.

increate와 rate 예시 : https://blog.voidmainvoid.net/449

  • increase()

    • increase() 를 사용하면 이런 문제를 해결할 수 있다.
    • 지정한 시간 단위별로 증가를 확인할 수 있다. 마지막에 [시간] 을 사용해서 범위 벡터를 선택해야 한다.
    • 예) increase(http_server_requests_seconds_count{uri="/log"}[1m])
      • 분당 얼마나 고객의 요청이 어느정도 증가했는지 한눈에 파악할 수 있다.
    • 예) increate(node_network_transmit_bytes_total[1m])
      • 1분동안 전송된 총 바이트
      • 예를 들어 1분전 메트릭이 1000바이트이고 현재가 2000바이트면 1000이 되는 것이다.
  • rate()

    • 범위 백터에서 초당 평균 증가율을 계산한다.
    • increase() 가 숫자를 직접 카운트 한다면, rate() 는 여기에 초당 평균을 나누어서 계산한다.
    • rate(data[1m]) 에서 [1m] 이라고 하면 60초가 기준이 되므로 60을 나눈 수이다.
    • 예를 들어 1분동안 1000바이트에서 2000바이트로 증가했다면 rate는 초당 16.67바이트의 변화율을 반환한다.
    • rate(data[2m]) 에서 [2m] 이라고 하면 120초가 기준이 되므로 120을 나눈 수이다.
    • 너무 복잡하게 생각하기 보다는 초당 얼마나 증가하는지 나타내는 지표로 보면 된다.
  • irate()

    • rate 와 유사한데, 범위 벡터에서 초당 순간 증가율을 계산한다. 급격하게 증가한 내용을 확인하기 좋다.

정리

  • 게이지: 값이 계속 변하는 게이지는 현재 값을 그대로 그래프로 표현하면 된다.
  • 카운터: 값이 단조롭게 증가하는 카운터는 increase() , rate() 등을 사용해서 표현하면 된다.

참고
더 자세한 내용은 다음 프로메테우스 공식 메뉴얼을 참고하자
기본기능: https://prometheus.io/docs/prometheus/latest/querying/basics/
연산자: https://prometheus.io/docs/prometheus/latest/querying/operators/
함수: https://prometheus.io/docs/prometheus/latest/querying/functions/

프로메테우스의 단점은 한눈에 들어오는 대시보드를 만들어보기 어렵다는 점이다. 이 부분은 그라파나를 사용하면 된다.

그라파나

https://grafana.com/grafana/download

그라파나는 프로메테우스를 통해서 데이터를 조회하고 보여주는 역할을 한다. 쉽게 이야기해서 그라파나는 대시보드의 껍데기 역할을 한다.

9

data sources에 프로메테우스를 등록해서 연동한다.
실제 메트릭 정보를 promQL로 작성할 수도 있지만 매우 번거롭기 때문에 다른 사람들이 만들어 놓은 대시보드를 사용한다.

https://grafana.com/grafana/dashboards/

마음에 드는 대시보드를 클릭하고 id를 기억하고 그라파나로 다시 돌아온다.

  1. 왼쪽 Dashboards 메뉴 선택
  2. New 버튼 선택 Import 선택
  3. 불러올 대시보드 숫자( 11378 )를 입력하고 Load 버튼 선택
  4. Prometheus 데이터소스를 선택하고 Import 버튼 선택

만들어진 대시보드를 수정하고 싶다면 우측 상단에 톱니바퀴를 선택하고 make editable을 선택하고 save하면 수정이 가능해진다.

메트릭 등록

CPU 사용량, 메모리 사용량, 톰캣 쓰레드, DB 커넥션 풀과 같이 공통으로 사용되는 기술 메트릭은 이미 등록되어 있다. 이런 이미 등록된 메트릭을 사용해서 대시보드를 구성하고 모니터링 하면 된다.

여기서 더 나아가서 비즈니스에 특화된 부분을 메트릭으로 만들어둔다면 메트릭들도 시스템을 운영하는데 상당히 도움이 된다. 예를 들어서 취소수가 갑자기 급증하거나 재고 수량이 임계치 이상으로 쌓이는 부분들은 기술적인 메트릭으로 확인할 수 없는 시스템의 비즈니스 문제를 빠르게 파악하는데 도움을 준다.

마이크로미터를 사용해서 메트릭을 직접 등록하는 방법을 알아보자. 마이크로미터로 메트릭을 등록해두면 구현체들이 알아서 그에 맞게 변환해준다.

MeterRegistry

  • 마이크로미터 기능을 제공하는 핵심 컴포넌트
  • 스프링을 통해서 주입 받아서 사용하고, 이곳을 통해서 카운터, 게이지 등을 등록한다.

카운터

  • 단조롭게 증가하는 단일 누적 측정항목
    • 단일 값
    • 보통 하나씩 증가
    • 누적이므로 전체 값을 포함(total)
    • 프로메테우스에서는 일반적으로 카운터의 이름 마지막에 _total 을 붙여서 my_order_total 과 같이 표현함
  • 값을 증가하거나 0으로 초기화 하는 것만 가능
  • 마이크로미터에서 값을 감소하는 기능도 지원하지만, 목적에 맞지 않음 예) HTTP 요청수
@Configuration
public class OrderConfigV2 {

    @Bean
    public CountedAspect countedAspect(MeterRegistry registry) {
        return new CountedAspect(registry);
    }
}
  • annotation으로 동작하는 @counted의 경우에는 aop로 동작하기 때문에 관련해서 제공되는 CountedAspect를 빈으로 등록해줘야 한다.
@Slf4j
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();
    }

    @Override
    public AtomicInteger getStock() {
        return stock;
    }
}
  • @counted 애노테이션을 측정을 원하는 메서드에 적용한다. 주문과 취소 메서드에 적용했다. 그리고 메트릭 이름을 지정하면 된다.
  • 이렇게 사용하면 tag 에 method명과 클래스 명으로 분류가 가능해진다.
  • 실제로 찍히는 것을 보면 메트릭 이름이 my.order my_order_total 로 변경된 것을 확인할 수 있다.
  • 프로메테우스는 . _ 로 변경한다.
  • 카운터는 마지막에 _total 을 붙인다. 프로메테우스는 관례상 카운터 이름의 끝에 _total 을 붙인다.

Timer

Timer는 좀 특별한 메트릭 측정 도구인데, 시간을 측정하는데 사용된다. 카운터와 유사한데, Timer 를 사용하면 실행 시간도 함께 측정할 수 있다.
Timer 는 다음과 같은 내용을 한번에 측정해준다.

  • seconds_count : 누적 실행 수(카운터)
  • seconds_sum : 실행 시간의 합 (sum)
  • seconds_max : 최대 실행 시간(가장 오래걸린 실행 시간)(게이지)
    • 내부에 타임 윈도우라는 개념이 있어서 1~3분 마다 최대 실행 시간이 다시 계산된다.

이를 활용하여 평균 실행 시간도 계산할 수 있다. seconds_sum / seconds_count = 평균 실행시간

@Configuration
public class OrderConfigV4 {

    @Bean
    public TimedAspect timedAspect(MeterRegistry registry) {
        return new TimedAspect(registry);
    }
}
  • 마찬가지로 timedAspect도 등록해준다.
// 메서드에 해도 되고 클래스에 해도 된다.
@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;
    }
}

게이지

https://prometheus.io/docs/concepts/metric_types/#gauge

  • 게이지는 임의로 오르내릴 수 있는 단일 숫자 값을 나타내는 메트릭 값의 현재 상태를 보는데 사용
  • 값이 증가하거나 감소할 수 있음
  • 예) 차량의 속도, CPU 사용량, 메모리 사용량
  • 참고: 카운터와 게이지를 구분할 때는 값이 감소할 수 있는가를 고민해보면 도움이 된다.
@Slf4j
@Configuration
public class StockConfigV2 {

    @Bean
    public MeterBinder stockSize(OrderService orderService) {
        return registry -> Gauge.builder("my.stock", orderService, service -> {
            log.info("stock gauge call");
            // 리턴값을 프로메테우스에서 가져가는 주기마다 이것을 호출해서 가져간다.
            return service.getStock().get();
        }).register(registry);
    }
}
@backtony backtony changed the title [spring] actuator와 모니터 [spring] actuator와 모니터링 Mar 19, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant