前提概要:假设你已经了解了Prometheus是做什么的,以及如何基于Prometheus搭建一个指标监控体系。 本章节将讲解如何基于Prometheus对SpringBoot进行指标采集
SpringBoot监控
添加prometheus依赖:
<!-- for monitor -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId>
</dependency>
使用actuator暴露prometheus端口:
# 供prometheus监控
management:
endpoints:
web:
exposure:
# 上报所有接口
include: "*"
metrics:
tags:
# 为上报数据添加applictoin的tag
application: ${spring.application.name}
export:
prometheus:
enabled: true
Prometheus会为自动的为SpringBoot应用产生生成非常多个监控指标,在正常情况下足够我们使用了:
业务埋点
spring-boot-actuator只能够帮助我们采集技术上的指标。如果我们想对业务指标进行监控,则可以对其进行拓展,Prometheus注解和API的方式,帮助我们快速的实现统计。
基于注解实现
@Gauge
- 用于度量可变值的当前状态,例如内存使用量、CPU负载、线程数等。适用于度量瞬态数据。- @Time - 用于记录方法的执行频率
- @Counted - 用于记录方法的调用次数,适合记录应用程序中重要事件的发送情况。例如用户请求的成功或失败计数
- @ExceptionMetered - 用于记录异常发生的次数和频率
注意: 这些注解只是将指标名称和度量值注册到Micrometer中,并没有为所监控的指标创建实际的计数器对象。因此,我们还需要显示的将指标注册到Micrometer中:
首先我们需要额外引入micrometer-core组件
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-core</artifactId>
</dependency>
比如说我们想要监控下单接口的执行时间,则可以这样做:
@RestController
public class OrderController{
public OrderController(MeterRegistry registry) {
registry.counter("demo.order.latency");
}
@PostMapping("/place")
@Timed("demo.order.latency")
public void place() {
// do business code.
}
}
基于API实现
除了注解,我们还可以通过API的方式处理代码块中更复杂一些的情况对其进行埋点,基本的使用方式如下:
@RestController
public class TestController {
Counter counter;
// 1. 通过自动注入MeterRegistry
public TestController(MeterRegistry registry) {
// 2. 通过对应的API接口构建采集器
counter = Counter.builder("charon_test_counts")
.register(registry);
}
@GetMapping("/test")
public String get() {
// 3. 执行采集任务
counter.increment();
return "true";
}
}
统计线程情况
通过ExecutorServiceMetrics.monitor()构造方法,我们可以对线程池进行监控以采集关键指标,以定时任务线程池为例,代码如下图所示:
@Autowired
private MeterRegistry meterRegistry;
private final ScheduledExecutorService EXECUTOR = ExecutorServiceMetrics.monitor(
meterRegistry,
Executors.newScheduledThreadPool(1, new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
Thread t = new Thread(r);
t.setName("schedule-thread-" + t.getId());
return t;
}
}), "Scheduled-Executor"
);