마이크로미터 소개
앱의 데이터를 측정한 데이터를 API 스펙에 맞게 넘겨줘야할 때 툴을 바꾸게 되면 호환이 맞지 않아서 문제가 된다.
마이크로미터를 통해 하나의 표준방식으로 여러 모니터링툴 구현체를 사용할 수 있게 도와준다. 마이크로미터가 지원하는 툴을 사용해야하긴 하지만 지원하는것들이 엄청 많다.
메트릭 확인하기
미이크로미터에 이미 다양한 지표 수집기능이 만들어져있고 스프링에서는 @AutoConfiguration에서 해당 기능들을 사용할 수 있도록 빈으로 등록한다.
actuator/metrics 를 확인하면 jvm.memory.used 처럼 여러 메트릭들이 이미 존재한다.
actuator/metrics/jvm.memory.used?tag=area:heap
처럼 tag를 이용하여 한번더 필터링을 할 수 있다.
uri중에 /log에 대한 정보중에 200만 확인하고싶으면
http.server.request?tag=uri:/log&tag=status:200 와 같이 tag 를 키 값으로 하고 해당되는 value를 추가적으로 적어주면 필터링 된다.
프로메테우스와 그라파나
프로메테우스 = 앱에서 발생한 메트릭을 그 순간만 확인하는 것이 아니라 과거 이력까지 함께 확인하려면 메트릭을 보관하는 DB역할을 한다.
그라파나 = 프로메테우스를 포함한 다양한 데이터소스를 지원하는 대시보드 툴이다.
- 스프링 부트 엑츄에이터와 마이크로미터를 사용하면 수 많은 메트릭들이 자동으로 생성이 된다.
- 프로메테우스에서 주기적으로 메트릭 데이터를 수집하고 db에 저장을 한다.
- 그라파나도 주기적으로 프로메테우스 db에서 데이터를 수집해서 대시보드에 뿌려준다.
앱단에서 build.gradle에 다음 dependency를 추가해주면
implementation 'io.micrometer:micrometer-registry-prometheus'
/actuator/prometheus로 엑츄에이터에 프로메테우스 메트릭 엔드포인트가 자동으로 추가된다.
http.server.request 의 actuatordml metric 은 json format으로 요청수 , 시간 합, 최대 시간 정보를 가지고 있다. 이것을 프로메테우스에서는
- http_server_request_seconds_count
- http_server_request_seconds_sum
- http_server_request_seconds_max
이런식으로 포맷들이 변경된다.
scrape_configs:
- job_name: "prometheus"
static_configs:
- targets: ["192.168.31.32:19090"]
- job_name: "spring-actuator"
metrics_path: '/actuator/prometheus'
scrape_interval: 1s
static_configs:
- targets: ['192.168.31.32:8080']
docker로 띄우는데 -p 19090:9090 으로 띄웠기 때문에 static_configs에 19090 포트를 적어줘야한다.
docker run --name prometheus -p 19090:9090 -v /home/tony/vscode/boot-source-20230228/start/prometheus-grafana/prometheus.yml:/etc/prometheus/prometheus.yml prom/prometheus
프로메테우스 - 게이지와 카운터
Gauge = 게이지는 오르고 내리는 값, 현재 상태값을 출력하게 된다. = CPU 사용량
Counter = 단일 누적값 = HTTP 요청수 (http_server_requests_seconds_count{uri="/log"})
increase(http_server_requests_seconds_count{uri="/log"}[1m]) = 함수로 지정한 시간 단위별로 증가를 확인 할 수 있다.
rate(http_server_requests_seconds_count{uri="/log"}[1m]) = increase 는 숫자이지만 rate는 초당 평균을 나누어 계산한 값인 비율을 y축에 보여주게 된다.
rate는 1m로 하면 (지금 값 - 1분전 값) / 1분 으로 계산하여 1분동안 60개의 요청이 왔으면 값이 1 이된다.
increase는 rate * 1m = 60 으로 실제 분당 요청이 얼마 들어왔는지 나타내게 된다.
계속증가되는값은 특정시간에 얼마나 고객의 요청이 들어왔는지 한 눈에 확인하기 어려우니 increase, rate를 쓴다.
그라파나
grafana를 docker로 띄울시 좀 기다려야한다
logger=http.server t=2023-05-19T02:08:35.841231555Z level=info msg="HTTP Server Listen" address=[::]:3000 protocol=http subUrl= socket=
요 로그가 나올 때까지
https://grafana.com/grafana/dashboards/?search=spring
여기서 이미 완성된 dashboard들을 가져다 쓰는것이 좋다.
메트릭 등록
공통적인것들은 이미 모니터링을 잘 할 수 있게 마련되어있다. 필요한것 각 비즈니스의 특화된 부분의 메트릭이 필요하다.
예를 들어서 취소수가 갑자기 급증하거나 재고 수량이 임계치 이상으로 쌓이는 부분들은 기술적인 메트릭으로 확인 할 수 없는 우리 시스템 비즈니스 문제를 빠르게 파악하는데 도움을 준다.
등록할 메트릭
주문수, 취소수 (카운터, 계속증가함으로)
- 상품을 주문하면 주문수가 증가한다.
- 상품을 취소해도 주문수는 유지한다. 대신에 취소수를 증가시킨다.
재고 수량 (게이지 , 증감이 있음으로)
- 상품을 주문하면 재고 수량이 감소한다.
- 상품을 취소하면 재고 수량이 증가한다.
- 재고 물량이 들어오면 재고 수량이 증가한다.
메트릭 등록1 - 카운터
@RequiredArgsConstructor
public class OrderServiceV1 implements OrderService {
private final MeterRegistry registry;
private AtomicInteger stock = new AtomicInteger(100);
@Override
public void order() {
System.out.println("주문");
stock.decrementAndGet();
Counter counter = Counter.builder("my.order")
.tag("class", this.getClass().getName())
.tag("method", "order")
.description("order")
.register(registry);
counter.increment();
}
나만의 비지니스 메트릭을 actuator에 추가할 수 있다.
# HELP my_order_total order
# TYPE my_order_total counter
my_order_total{class="hello.order.V1.OrderServiceV1",method="order",} 1.0
my_order_total{class="hello.order.V1.OrderServiceV1",method="cancel",} 1.0
actuator/prometheus 에서 my_order_total 로 변경된것을 확인할 수 있다. counter이기 때문에 끝에 total이 자동으로 붙는다.
grafana에도 custom한 것을 쉽게 등록할 수 있다.
메트릭 등록2 - @Counted
위에서는 service메소드를 호출해야하만 Counter가 등록되게 되었다. 비지니스 로직에 모니터링 기능이 침투하게 된것이다.
AOP를 사용해서 분리하자
@Configuration
public class OrderConfigV2 {
@Bean
OrderService orderService() {
return new OrderServiceV2();
}
@Bean
public CountedAspect countedAspect(MeterRegistry registry) {
return new CountedAspect(registry);
}
}
@RequiredArgsConstructor
public class OrderServiceV2 implements OrderService {
private AtomicInteger stock = new AtomicInteger(100);
@Counted("my.order")
@Override
public void order() {
System.out.println("주문");
stock.decrementAndGet();
}
@Counted 를 사용하려면 CountedAspect를 빈으로 등록을 해줘야 동작하게 된다.
메트릭 등록3 - Timer
카운터와 유사함, 실행시간도 함께 측정해준다.
- seconds_count = 누적 실행수 == 카운터
- seconds_sum = 실행시간의 합
- seconds_max = 최대 실행시간( 가장 오래 걸린 시간 )
@RequiredArgsConstructor
public class OrderServiceV3 implements OrderService {
private final MeterRegistry registry;
private AtomicInteger stock = new AtomicInteger(100);
@Override
public void order() {
Timer timer = Timer.builder("my.order")
.tag("class", this.getClass().getName())
.tag("method", "order")
.description("order")
.register(registry);
timer.record(() -> {
System.out.println("주문");
stock.decrementAndGet();
});
}
특정 로직이 시간이 걸리는지 측정하게 도와준다.
@Timed(value = "my.order")
public class OrderServiceV4 implements OrderService {
private AtomicInteger stock = new AtomicInteger(100);
@Override
public void order() {
System.out.println("주문");
stock.decrementAndGet();
}
@Configuration
public class OrderConfigV4 {
@Bean
OrderService orderService() {
return new OrderServiceV2();
}
@Bean
public TimedAspect timedAspect(MeterRegistry registry) {
return new TimedAspect(registry);
}
}
@Counted와 동일하게 @Timed, TimedAspect를 사용하면 위와 동일하게 동작을 하게 된다.
메트릭 등록5 - 게이지
임의로 오르내릴수 있는 단일 숫자 값을 나타내는 메트릭
@PostConstruct
public void init() {
Gauge.builder("my.stock",orderService, service -> {
System.out.println("stock gauge call");
int stock = service.getStock().get();
return stock;
}).register(registry);
}
my.stock metric을 확인할 때마다 전달한 람다가 호출된다.
actuator/prometheus 를 프로메테우스가 1초에 한번씩 호출하기 떄문에 1초마다 위 람다가 호출이 되게된다.
@Configuration
public class StockConfigV2 {
@Bean
public MeterBinder stockSize(OrderService orderService) {
return registry -> Gauge.builder("my.stock",orderService, service -> {
System.out.println("stock gauge call");
return service.getStock().get();
}).register(registry);
}
}
좀 더 간편하게 등록하는 방법
'WEB > Spring Boot' 카테고리의 다른 글
액츄에이터 (0) | 2023.05.16 |
---|---|
외부설정과 프로필 (0) | 2023.05.14 |
자동 구성(Auto Configuration) (0) | 2023.05.13 |
스프링 부트 스타터와 라이브러리 관리 (0) | 2023.05.11 |
스프링 부트와 내장 톰캣 (0) | 2023.05.10 |