SpringBoot2中的度量框架

  |   0 评论   |   0 浏览

背景

当一个 Spring Boot 项目运行时,我们可能需要对这个项目进行实时监控,获取项目运行情况,在项目出错时能够自动报警等。

Spring Boot提供了actuator,来帮助开发者获取应用程序的实时运行数据。开发者可以选择使用 HTTP 端点或者 JMX 来管理和监控应用程序,获取应用程序的运行数据,包括健康状况、应用信息、内存使用等情况。

初体验

pom依赖

<dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>

默认端点介绍

见[2]

健康检查

http://localhost:8080/actuator/health

结果

{
  status: "UP"
}

默认只开启了health接口。可以访问 /actuator来查看开放的接口。

metric

开启web显示,方便调试。

management:
  endpoints:
    web:
      exposure:
        include: metrics
  endpoint:
    metrics:
      enabled: true

访问 http://localhost:8080/actuator/metrics,可见默认的指标有:

{
	"names": [
		"http.server.requests",
		"jvm.buffer.count",
		"jvm.buffer.memory.used",
		"jvm.buffer.total.capacity",
		"jvm.classes.loaded",
		"jvm.classes.unloaded",
		"jvm.gc.live.data.size",
		"jvm.gc.max.data.size",
		"jvm.gc.memory.allocated",
		"jvm.gc.memory.promoted",
		"jvm.gc.pause",
		"jvm.memory.committed",
		"jvm.memory.max",
		"jvm.memory.used",
		"jvm.threads.daemon",
		"jvm.threads.live",
		"jvm.threads.peak",
		"jvm.threads.states",
		"logback.events",
		"process.cpu.usage",
		"process.files.max",
		"process.files.open",
		"process.start.time",
		"process.uptime",
		"system.cpu.count",
		"system.cpu.usage",
		"system.load.average.1m",
		"tomcat.sessions.active.current",
		"tomcat.sessions.active.max",
		"tomcat.sessions.alive.max",
		"tomcat.sessions.created",
		"tomcat.sessions.expired",
		"tomcat.sessions.rejected"
	]
}

自定义统计指标

除了使用 metrics 端点默认的这些统计指标外,我们还可以实现自定义统计指标。Metrics 提供 4 种基本的度量类型:Gauge、Counter、Timer、Summary。下面分别进行介绍。

Gauge(计量器)

Gauge(计量器)是最简单的度量类型,只有一个简单的返回值,他用来记录一些对象或者事物的瞬时值。

Metrics.gauge("user.test.gauge", 3);

如果要统计Map类型的话,可以使用

Metrics.gaugeMapSize("global.concurrency", Tags.of("ip", NetworkUtil.SERVER_IP), stateMap);

Counter(计数器)

Counter(计数器)简单理解就是一种只增不减的计数器。它通常用于记录服务的请求数量、完成的任务数量、错误的发生数量等等。

static final Counter userCounter = Metrics.counter("user.counter.total", "services", "demo");
 
    public void processCollectResult() {
        userCounter.increment(1D);
    }

Timer(计时器)

Timer(计时器)可以同时测量一个特定的代码逻辑块的调用(执行)速度和它的时间分布。简单来说,就是在调用结束的时间点记录整个调用块执行的总时间,适用于测量短时间执行的事件的耗时分布,例如消息队列消息的消费速率。

private Timer timer = Metrics.timer("user.test.timer","timer", "timersample");
 
    @GetMapping("/hello")
    public void hello() {
 
        // 执行createOrder方法并记录执行时间
        timer.record(() -> createOrder());
    }
 
    //模拟方法耗时
    private void createOrder() {
        try {
            TimeUnit.SECONDS.sleep(3);
        } catch (InterruptedException e) {
        }
    }

默认的timer结果中,只有sum, max和count指标。可以使用Config的方式,增加位点指标。[3]

import io.micrometer.core.instrument.Meter;
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.config.MeterFilter;
import io.micrometer.core.instrument.distribution.DistributionStatisticConfig;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.actuate.autoconfigure.metrics.MeterRegistryCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
@Slf4j
public class MicrometerConfig {

    @Bean
    MeterRegistryCustomizer<MeterRegistry> metricsCommonTags() {
        return registry -> {
            registry.config().meterFilter(
                    new MeterFilter() {
                        @Override
                        public DistributionStatisticConfig configure(Meter.Id id, DistributionStatisticConfig config) {
                            // 显示P50, P90, P95, P99信息
                            if (id.getType() == Meter.Type.TIMER && id.getName().contains("timer")) {
                                return DistributionStatisticConfig.builder()
                                        .percentilesHistogram(true)
                                        .percentiles(0.5, 0.90, 0.95, 0.99)
//                                        .sla(Duration.ofMillis(50).toNanos(),
//                                                Duration.ofMillis(100).toNanos(),
//                                                Duration.ofMillis(200).toNanos(),
//                                                Duration.ofSeconds(1).toNanos(),
//                                                Duration.ofSeconds(5).toNanos())
//                                        .minimumExpectedValue(Duration.ofMillis(1).toNanos())
//                                        .maximumExpectedValue(Duration.ofSeconds(5).toNanos())
                                        .build()
                                        .merge(config);
                            } else {
                                return config;
                            }
                        }
                    });
        };
    }
}k

Summary(摘要)

Summary(摘要)用于跟踪事件的分布。它类似于一个计时器,但更一般的情况是,它的大小并不一定是一段时间的测量值。在 micrometer 中,对应的类是 DistributionSummary,它的用法有点像 Timer,但是记录的值是需要直接指定,而不是通过测量一个任务的执行时间。

private DistributionSummary summary = Metrics.summary("user.test.summary","summary", "summarysample");
 
    @GetMapping("/hello")
    public void hello() {
        summary.record(2D);
        summary.record(3D);
        summary.record(4D);
    }

通过web访问promethous

引入依赖:

<dependency>
          <groupId>io.micrometer</groupId>
          <artifactId>micrometer-registry-prometheus</artifactId>
          <version>1.8.4</version>
    </dependency>

修改配置文件:

management:
  endpoints:
    web:
      exposure:
        include: '*'
  endpoint:
    metrics:
      enabled: true
    prometheus:
      enabled: true

查看:http://localhost:8080/actuator/prometheus

其它

Prometheus语法

详见prometheus内置函数,或者Prometheus中文文档

increase

平均增长率:获取区间向量中的第一个后最后一个样本并返回其增长量

increase(node_cpu[2m]) / 120

或者用rate函数可以直接计算区间向量v在时间窗口内平均增长速率

rate(node_cpu[2m])

irate

瞬间增长率:通过区间向量中最后两个样本数据来计算区间向量的增长速率。这种方式可以避免在时间窗口范围内的“长尾问题”,并且体现出更好的灵敏度

irate(node_cpu[2m])

参考

  1. Spring Boot Actuator: Production-ready Features
  2. SpringBoot - Actuator应用监控使用详解1(开启、暴露端点,获取监控信息)
  3. springboot如何集成Prometheus如何暴露Histogram来获取P99等监控指标