티스토리 뷰

메트릭 (metric)


애플리케이션에서 발생한 메트릭을 그 순간만 확인하는 것이 아니라 과거 이력까지 함께 확인하려면 메트릭을 보관하는 DB가 필요하다. 이렇게 하려면 어디선가 메트릭을 지속해서 수집하고 DB에 저장해야 한다. 프로메테우스가 바로 이런 역할을 담당한다.

전체 구조

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

프로메테우스 아키텍처


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

프로메테우스는 메트릭을 수집하고 보관하는 DB이다.
이번에는 프로메테우스가 우리 애플리케이션의 메트릭을 수집하도록 연동해보겠다. 여기에는 2가지 작업이 필요하다.

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

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


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


build.gradle 추가

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

localhost:8080/actuator/prometheus 접속 결과

# HELP jvm_threads_states_threads The current number of threads
# TYPE jvm_threads_states_threads gauge
jvm_threads_states_threads{state="runnable",} 9.0
jvm_threads_states_threads{state="blocked",} 0.0
jvm_threads_states_threads{state="waiting",} 11.0
jvm_threads_states_threads{state="timed-waiting",} 7.0
jvm_threads_states_threads{state="new",} 0.0
jvm_threads_states_threads{state="terminated",} 0.0
# HELP tomcat_global_received_bytes_total  
# TYPE tomcat_global_received_bytes_total counter
tomcat_global_received_bytes_total{name="http-nio-8080",} 0.0
# HELP system_cpu_usage The "recent cpu usage" of the system the application is running in
# TYPE system_cpu_usage gauge
system_cpu_usage 0.0
# HELP hikaricp_connections_idle Idle connections
# TYPE hikaricp_connections_idle gauge
hikaricp_connections_idle{pool="HikariPool-1",} 10.0
# HELP application_started_time_seconds Time taken (ms) to start the application
# TYPE application_started_time_seconds gauge
application_started_time_seconds{main_application_class="hello.ActuatorApplication",} 6.228
# HELP tomcat_threads_config_max_threads  
# TYPE tomcat_threads_config_max_threads gauge
tomcat_threads_config_max_threads{name="http-nio-8080",} 200.0
# HELP executor_completed_tasks_total The approximate total number of tasks that have completed execution
# TYPE executor_completed_tasks_total counter
executor_completed_tasks_total{name="applicationTaskExecutor",} 0.0
# HELP jvm_buffer_memory_used_bytes An estimate of the memory that the Java virtual machine is using for this buffer pool
# TYPE jvm_buffer_memory_used_bytes gauge
jvm_buffer_memory_used_bytes{id="mapped - 'non-volatile memory'",} 0.0
jvm_buffer_memory_used_bytes{id="mapped",} 0.0
jvm_buffer_memory_used_bytes{id="direct",} 40960.0
# HELP jdbc_connections_min Minimum number of idle connections in the pool.
# TYPE jdbc_connections_min gauge
jdbc_connections_min{name="dataSource",} 10.0
...
  • 모든 메트릭이 프로메테우스 포멧으로 만들어 진 것을 확인할 수 있다.

포멧 차이

localhost:8080/actuator/metrics/jvm.info 접속 결과

{
  "name": "jvm.info",
  "description": "JVM version info",
  "measurements": [
    {
      "statistic": "VALUE",
      "value": 1.0
    }
  ],
  "availableTags": [
    {
      "tag": "vendor",
      "values": [
        "Eclipse Adoptium"
      ]
    },
    {
      "tag": "runtime",
      "values": [
        "OpenJDK Runtime Environment"
      ]
    },
    {
      "tag": "version",
      "values": [
        "17.0.5+8"
      ]
    }
  ]
}

localhost:8080/actuator/prometheus에서 살펴본 jvm.info 정보

jvm_info{runtime="OpenJDK Runtime Environment",vendor="Eclipse Adoptium",version="17.0.5+8",} 1.0
  • jvm.info -> jvm_info: 프로메테우스는 . 대신에 _ 포멧을 사용한다.

프로메테우스 - 수집 설정

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


프로메테우스 설치


prometheus.yml

  - job_name: "spring-actuator"
    metrics_path: '/actuator/prometheus'
    scrape_interval: 1s
    static_configs:
      - targets: ['localhost:8080']
  • 앞의 띄어쓰기 2칸에 유의하자
  • job_name: 수집하는 이름이다. 임의의 이름을 사용하면 된다.
  • metrics_path: 수집할 경로를 지정한다. /actuator/prometheus의 내용을 수집한다.
  • scrape_interval: 수집할 주기를 설정한다.
  • targets: 수집할 서버의 IP, PORT를 지정한다.

이렇게 설정하면 프로메테우스는 다음 경로를 1초에 한번씩 호출해서 애플리케이션의 메트릭들을 수집한다.


참고
scrape_interval의 값을 빠르게 확인하기 위해서 수집 주기를 1s로 했지만, 수집 주기의 기본 값은 1m이다. 수집 주기가 너무 짧으면 애플리케이션 성능에 영향을 줄 수 있으므로, 운영에서는 10s ~ 1m 정도를 권장한다. (물론 시스템 상황에 따라서 다르다.)


프로메테우스 연동 확인

터미널에서 프로메테우스 설치 폴더로 이동하여 ./prometheus 명령어로 프로메테우스를 실행한 뒤, http://localhost:9090/config에 접속해보면 prometheus.yml에 설정한 내용이 반영되어 있는 모습을 확인할 수 있다.


localhost:9090/config 접속 결과


프로메테우스 연동 확인 화면

http://localhost:9090/targets로 접속해보면, 방금 연동한 애플리케이션의 메트릭 정보가 연동된 모습을 확인할 수 있다.


localhost:9090/targets 접속 결과

  • prometheus: 프로메테우스 자체에서 제공하는 메트릭 정보이다. (프로메테우스가 프로메테우스 자신의 메트릭을 확인하는 것이다.)
  • spring-actuator: 우리가 연동한 애플리케이션의 메트릭 정보이다.
  • StateUP으로 되어 있으면 정상이고, DOWN으로 되어 있으면 연동이 안된 것이다.

프로메테우스를 통한 데이터 조회

프로메테우스 홈 화면으로 이동한 뒤, jvm_info를 검색창에 넣고 실행해보면 수집한 메트릭을 조회할 수 있다.


프로메테우스 - 기본 기능

프로메테우스를 사용하는데 필요한 간단한 기능들을 알아보자. 검색창에 http_server_requests_seconds_count를 입력하고 실행해보자


http_server_requests_seconds_count 검색 결과

  • 태그, 레이블: error, exception, instance, job, method, outcome, status, uri는 각각의 메트릭 정보를 구분해서 사용하기 위한 태그이다. 마이크로미터에서는 이것을 태그(Tag)라 하고, 프로메테우스에서는 레이블(Label)이라 한다. 둘을 구분하지 않고 사용할 것이다.
  • 숫자: 끝에 마지막에 보면 800, 1과 같은 숫자는 해당 uri로 요청한 횟수를 나타낸다.

Graph를 눌러 메트릭을 그래프로 조회할수도 있다.



필터

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


레이블 일치 연산자

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

예시

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

http_server_requests_seconds_count{uri="/log"} 실행 결과

  • uri의 정보가 /log인 내역만 조회 된다.

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

메트릭은 크게 보면 게이지와 카운터라는 2가지로 분류할 수 있다.


게이지(Gauge)

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

카운터(Counter)

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

게이지(Gauge)

게이지는 오르고 내리고 하는 값으로, 현재 상태를 그대로 출력한다.


  • 게이지는 가장 단순하고 사용하기 쉬운 메트릭이다
  • CPU 사용량의 현재 상태를 계속 측정하고 그 값을 그대로 그래프에 출력하면 과거부터 지금까지의 CPU 사용량을 확인할 수 있다.

카운터(Counter)

카운터는 단순하게 고객의 HTTP 요청수와 같이 증가하는 단일 누적 값이다.


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


increase()

increase()를 사용하면 지정한 시간 단위별로 증가를 확인할 수 있다. 마지막에 [시간]을 사용해서 범위 벡터를 선택해야 한다.
예) increase(http_server_requests_seconds_count{uri="/log"}[1m])


  • 09.28 ~ 09.30: 약 60건 요청
  • 09.28 ~ 09.33: 0건 요청
  • 09.28 ~ 09.35: 약 13건 요청

분당 얼마나 고객의 요청이 어느정도 증가했는지 한눈에 파악할 수 있다.


rate()

범위 백터에서 초당 평균 증가율을 계산한다. increase()가 숫자를 직접 카운트 한다면, rate()는 여기에 초당 평균을 나누어서 계산한다.

  • increase(data[1m])에서 [1m]이라고 하면 60초가 기준이 되므로 60을 나눈 수이다.
  • increase(data[2m])에서 [2m]이라고 하면 120초가 기준이 되므로 120을 나눈 수




Reference
김영한. 스프링 부트 - 핵심 원리와 활용. 인프런.

'Spring' 카테고리의 다른 글

[Spring Webflux] Cold Sequence & Hot Sequence  (0) 2024.01.07
[Spring] 메트릭(metric)을 직접 등록해보자  (0) 2023.04.17
[Spring] 메트릭 (metric)  (0) 2023.04.13
[Spring] actuator (액츄에이터)  (0) 2023.04.10
[Spring] YAML , @Profile  (0) 2023.04.09
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/01   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함