본문 바로가기
모티터링도구

Springboot Prometheus , micrometer architecture

by 아이티.파머 2024. 5. 26.
반응형
  • micromether
    • java 애플리리케이션에서 메트릭을 수집하는 라이브러리
  • micromether core
    • 핵심라이브러리로 메트릭 수집하고 관리함
    • 사용자 정의 MeterBinder 및 Exporter 개발 기능 지원
  • micromether prometheus exporter
    • micromether 의 확장 기능 이다.
    • micromether core 가 수집한 메트릭 데이터를 Prometheus 포멧으로 변환한다.
    • prometheus 엔드포엔트를 자동으로 생성
    • prometheus 스크랩을 자동으로 생성

**설명** 

Springboot 에서  prometheus를 사용할때, Actuator 와 micromether 를 함께 사용한다. 

위에  나열 했듯이 micromether 는  jvm 의 데이터를 수집하여 prometheus  format 으로 변환하고 actuator 를 통해 외부 엔트포인트로 자동 생성해준다. 

이를 사용하여 `promethous server` 는  spring boot 의 `/actuator/prometheus` endpoint 를 호출 하여 matric 정보를 수집한다. 

또한 micromether 의 core 라이브러리를 사용하여 원하는 metric data 를 생성 할 수 있다. 다음 예제를 통해 관련 내역을 살펴 보자 .

예제 코드

docker-compose file

version: "3.8"
services:
  zipkin:
    image: 'openzipkin/zipkin:latest'
    ports:
      - '9411:9411'
  grafana:
    image: "grafana/grafana:latest"
    container_name: grafana
    restart: unless-stopped
    ports:
      - "3000:3000"
    volumes:
      - ./grafana-data/grafana:/var/lib/grafana
    environment:
      - TZ=Asia/Seoul

  prometheus:
    image: prom/prometheus:latest
    container_name: prometheus
    restart: always
    ports:
      - "9090:9090"
    #user: "root"  #-> log 접근에 대한 권한 오류 발생시, docker 실행 user 를 root 로 사용한다.
    #user: "${UID}:${GID}"
    volumes:
      - ./prometheus/config:/etc/prometheus/
      - ./prometheus-data:/prometheus
    command:
      - '--config.file=/etc/prometheus/prometheus.yml'
      - '--storage.tsdb.path=/prometheus'
      - '--storage.tsdb.retention.time=30d'
      - '--storage.tsdb.retention.size=30GB'

#volumes:
#  grafana-data:
#  prometheus-data:
#    driver_opts:
#      type: 'none'
#      device: './prometheus-data'
#      o: 'bind'

gradle , 라이브러리 정보

plugins {
    id 'java'
    id 'org.springframework.boot' version '3.2.2'
    id 'io.spring.dependency-management' version '1.1.4'
    id 'org.graalvm.buildtools.native' version '0.9.28'
}

group = 'com.example'
version = '0.0.1-SNAPSHOT'

java {
    sourceCompatibility = '21'
}

configurations {
    compileOnly {
        extendsFrom annotationProcessor
    }
}

repositories {
    mavenCentral()
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-web'
    implementation 'org.springframework.boot:spring-boot-starter-actuator'
    implementation 'io.micrometer:micrometer-tracing-bridge-brave'
    implementation 'io.zipkin.reporter2:zipkin-reporter-brave'
    compileOnly 'org.projectlombok:lombok'
    developmentOnly 'org.springframework.boot:spring-boot-devtools'
    //developmentOnly 'org.springframework.boot:spring-boot-docker-compose'
    runtimeOnly 'io.micrometer:micrometer-registry-prometheus'
    annotationProcessor 'org.projectlombok:lombok'
    implementation 'org.springframework.boot:spring-boot-starter-webflux'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
    testImplementation 'io.projectreactor:reactor-test'
}

tasks.named('test') {
    useJUnitPlatform()
}

application yml 설정 값

spring:
  application:
    name: "elk application spring server name"

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

  metrics:
    tags:
      application: ${spring.application.name}

Controller 코드

package com.example.elkproject;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

/**
 * Description
 *
 * @author yohan.an
 * @version Copyright (C) 2024 by KakaoHealthcare. All right reserved.
 * @since 1/31/24
 */

@RestController
public class ElkController {

    final OrderServicePrometheus OrderServicePrometheus;

    public ElkController(com.example.elkproject.OrderServicePrometheus orderServicePrometheus) {
        OrderServicePrometheus = orderServicePrometheus;
    }

    @RequestMapping(value = "order", method = RequestMethod.GET)
    public void order() {
        OrderServicePrometheus.order();;
    }

    @RequestMapping(value = "cancel", method = RequestMethod.PATCH)
    public void cancel() {
        OrderServicePrometheus.cancel();;
    }

}

Service 코드

package com.example.elkproject;

import io.micrometer.core.instrument.Counter;
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.Tags;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 * Description
 *
 * @author yohan.an
 * @version Copyright (C) 2024 by KakaoHealthcare. All right reserved.
 * @since 2024. 5. 26.
 */
@Service
public class OrderServicePrometheus {

    @Autowired
    private MeterRegistry meterRegistry;

    public void order() {

        Counter.builder("product-count")
                .description("custom metric product order count")
                .tag("product-counter", "order")
                .register(meterRegistry)
                .increment();

    }

    public void cancel() {

        Counter.builder("product-count")
                .description("custom metric product cancel count")
                .tag("product-counter", "cancel")
                .register(meterRegistry)
                .increment();

    }

}

실행 파일

package com.example.elkproject;

import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.Tag;
import io.micrometer.core.instrument.Tags;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.stereotype.Component;

@SpringBootApplication
public class ElkProjectApplication {

    public static void main(String[] args) {
        SpringApplication.run(ElkProjectApplication.class, args);
    }

}

서비스를 실행하여,

[http://127.0.0.1:8080/actuator](http://127.0.0.1:8080/actuator/metrics) 에 접속해서 제공중인 endpoint 를 확인한다.

매트릭 지표를 확인 할 수있는 엔드포인트를 제공하는것을 확인 할 수있다. “actuator/metrics” 에 접근해서 새로 생성한 메트릭도 수집중인지 확인하자.

    "prometheus": {
      "href": "http://127.0.0.1:8080/actuator/prometheus",
      "templated": false
    },
    "metrics": {
      "href": "http://127.0.0.1:8080/actuator/metrics",
      "templated": false
    },
    "metrics-requiredMetricName": {
      "href": "http://127.0.0.1:8080/actuator/metrics/{requiredMetricName}",
      "templated": true
    },

Custom 하게 새로 만든 매트릭 지표를 확인 할 수 있다. “product-count” ( 구분을 콤마(.) 로하는걸 보니, 다음엔 콤마(.)로 변경하여 사용하자. )

 

requiredMetricName 으로 접근하여 product-count 동작 확인

커스텀하게 만든 엔드포인트가 정상 동작 하는지 확인해보자.

###
GET http://localhost:8080/order

###
PATCH http://localhost:8080/cancel

url 을 호출하여 counter 가 증가 되는 것을 확인 한다.

증감전 카운트 value
증감후 카운트 value

actuator/prometheus 에 접근하여 테그명 확인

http://127.0.0.1:8080/actuator/prometheus

프로메테우스용 마이크로미터 메트릭도 확인 한다. 정의된 해당 테그명으로 통계를 낼 수 있다.

  • order count 실시간으로 주문되는 카운트수 (누적 증감)
  • cancel count 실시간으로 취소되는 카운트수 (누적)

promethous 에서 데이터 확인 하기

[http://127.0.0.1:9090/targets?search](http://127.0.0.1:9090/targets?search) 에 접속하여 서비스가 정상 동작 하는지 확인한다.

쿼리에 product_count_total 을 입력한 뒤 execute 하고 request count(order, cancel)을 늘려가며 모니터링 해보면 다음과 같이 실시간으로 그래프를 확인 할 수있다.

참고

tomcat의 메트릭을 모두 보고 싶으면 활성화 시켜야 한다. 활성화 하지 않으면 session 만 활성화 된다.

server:
  tomcat:
    mbeanregistry:
      enabled: true
반응형