自定义Metrics|让Prometheus监控你的应用程序

6,744 阅读3分钟

这是我参与更文挑战的第12天,活动详情查看: 更文挑战

前言:

本文将以Spring Boot/Spring Cloud为例,介绍如果使用Prometheus SDK实现自定义监控指标的定义以及暴露,并且会介绍Prometheus中四种不同指标类型(Counter, Gauge, Histogram, Summary)的实际使用场景;

需求背景:

最近在做的一个新的项目,上线后要实现Prometheus监控,以及对项目里自己比较在意的指标进行自定义监控,用的是公司已有的Grafana,并没有自己搭建Grafana+Prometheus的仪表盘,下一篇文章会更新一些如何使用Grafana+Prometheus搭建项目仪表盘,这里就不多做赘述啦!下面看正文👇👇👇;

对于后端的一些应用以及环境架构。一般而言,我们通常会从几个层面进行监控指标的采集:

  • 入口网关:这里可以是Nginx/HaProxy这一类的负载均衡器,也可以是注入Spring Cloud Zuul这一类框架提供的微服务入口。一般来说我们需要对所有Http Request相关的指标数据进行采集。如请求地址,Http Method,返回状态码,响应时长等。从而可以通过这些指标历史数据去分析业务压力,服务状态等信息。
  • 应用服务:对于应用服务而言,基本的如应用本身的资源使用率,比如如果是Java类程序可以直接通过JVM信息来进行统计,如果是部署到容器中,则可以通过Container的资源使用情况来统计。除了资源用量外,某些特殊情况下,我们可能还会对应用中的某些业务指标进行采集。
  • 基础设施:虚拟机或者物理机的资源使用情况等。
  • 其它:集群环境中所使用到的数据库,缓存,消息队列等中间件状态等。

对于以上的集中场景中,除了直接使用Prometheus社区提供的Exporter外,不同的项目可能还需要实现一些自定义的Exporter用于实现对于特定目的的指标的采集和监控需求。

对于监控系统主要由以下几个结构组成:

  • 目标服务:该服务即为各个组上线的服务,通过接入架构组提供的公共监控服务包后,会在服务启动之后暴露出一个数据监控接口 /actuator/prometheus,我们的一些监控数据指标也暴露在这里,直接请求http://localhost:8080/actuator/prometheus 即可
  • 数据搜集服务:即prometheus服务,该服务主要负责将定时各个目标服务接口暴露的数据搜集起来,并将接口中的数据根据【Metric】数据格式整合起来,供监控展示服务使用
  • 数据展示服务:即grafana,该服务为单纯的数据展示服务,可支持包括prometheus等多种数据搜集服务的数据展示,同时提供一些特性函数以应对多种复合的展示场景

接入方法

pom依赖:

<!--监控点开始-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
    <version>${starter-actuator.version}</version>
</dependency>
<dependency>
    <groupId>io.micrometer</groupId>
    <artifactId>micrometer-registry-prometheus</artifactId>
</dependency>
<dependency>
    <groupId>io.prometheus</groupId>
    <artifactId>simpleclient</artifactId>
    <version>${prometheus-simpleclient.version}</version>
</dependency>
<dependency>
    <groupId>io.prometheus</groupId>
    <artifactId>simpleclient_spring_boot</artifactId>
    <version>${prometheus-simpleclient.version}</version>
</dependency>
<dependency>
    <groupId>io.prometheus</groupId>
    <artifactId>simpleclient_hotspot</artifactId>
    <version>${prometheus-simpleclient.version}</version>
</dependency>
<!--监控点结束-->

application.properties配置文件:

management.metrics.export.prometheus.enabled=true
management.metrics.export.prometheus.step=1m
management.metrics.export.prometheus.descriptions=true
management.web.server.auto-time-requests=true
management.endpoints.prometheus.id=produce-server
management.endpoints.web.exposure.include=health,info,env,prometheus,metrics,httptrace,threaddump,heapdump,springmetrics,git
management.health.rabbit.enabled=false

不同项目对于暴露出去的接口要求不同,可针对各值环境对上述management.endpoints.web.exposure.include 参数进行相应调整

项目内新增prometheus数据收集组件:

import io.micrometer.core.instrument.ImmutableTag;
import io.micrometer.core.instrument.Metrics;
import io.micrometer.core.instrument.Tag;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;

import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicLong;

/**
 * levelDb自定义监控指标
 *
 * @author taoze
 * @version 1.0
 * @date 4/27/21 10:42 AM
 */
@Component
@Slf4j
public class LevelDbMetrics {

    /**
     * levelDB监控项
     */
    private AtomicLong levelDBHead = Metrics.gauge("a.levelDb.head", init(), new AtomicLong(0));
    private AtomicLong levelDBTail = Metrics.gauge("a.levelDb.tail", init(), new AtomicLong(0));

    /**
     * 初始化tag
     *
     * @return
     */
    List<Tag> init() {
        List<Tag> list = new ArrayList<>();
        String ip = null;
        try {
            ip = InetAddress.getLocalHost().getHostAddress();
        } catch (UnknownHostException e) {
            e.printStackTrace();
        }
        list.add(new ImmutableTag("host", StringUtils.isBlank(ip) ? "127.0.0.1" : ip));
        return list;
    }

    public void setLevelDBHead(Long head) {
        levelDBHead.set(head);
        log.info("levelDB head = [{}]", levelDBHead.get());
    }

    public void setLevelDBTail(Long tail) {
        levelDBTail.set(tail);
        log.info("levelDB tail = [{}]", levelDBTail.get());
    }
}
  • 想要将自定义数据暴露在/actuator/prometheus 中,就需要在项目中建立对一个Metrics对象,然后对这个对象进行数据更新,最终在调用接口时就会从这个Metrics对象存储的数据中获取到指定的数据
  • 更新值的时候调用 setLevelDBHead或setLevelDBTail方法即可或使用定时任务定时修改值

Metrics指标类型以及使用场景:

  • Counter,只增不减的计数器
  • Gauge,可增可减的仪表盘
  • Histogram,自带buckets区间用于统计分布统计图
  • Summary, 客户端定义的数据分布统计图 除了上述方法我们也可以通过拦截器/过滤器:用于统计所有应用请求的情况等

WebMvcConfigurerAdapter方式手机监控指标:

@SpringBootApplication
@EnablePrometheusEndpoint
public class SpringApplication extends WebMvcConfigurerAdapter implements CommandLineRunner {

    @Autowired
    private CustomExporter customExporter;

    ...省略的代码

    @Override
    public void run(String... args) throws Exception {
        ...省略的代码
        customExporter.register();
    }
}

ok!今日分享到此结束,搜集指标代码还是比较简单的,有类似需求的小伙伴可以试试哦,希望可以对大家有帮助,有不对的地方希望大家可以提出来的,共同成长;

整洁成就卓越代码,细节之中只有天地