Spring Boot应用如何快速接入Prometheus监控

在使用Spring Boot应用过程中,为了对系统的状态进行持续地观测,您可以将Spring Boot应用接入Prometheus监控。本文介绍如何将Spring Boot应用快速接入Prometheus监控。

背景信息

对于开发者而言,大部分传统SSM结构的MVC应用背后的糟糕体验都是来自于搭建项目时的大量配置,稍有不慎就可能导致配置出错。为了解决这个问题,Spring Boot应运而生。Spring Boot的核心价值就是自动配置,只要存在相应Jar包,Spring Boot可以自动配置,如果默认配置不能满足需求,您还可以替换掉自动配置类,使用自定义配置快速构建企业级应用程序。

构建Spring Boot应用以及该应用上线之后,您需要对该应用进行监测。一般来说,搭建一套完整易用的监测系统主要包含以下几个关键部分。

收集监测数据

目前,行业常见的收集监测数据方式主要分为推送(Push)和抓取(Pull)两个模式。以越来越广泛应用的Prometheus监测体系举例,可观测监控 Prometheus 版就是以抓取(Pull)模式运行的典型系统。应用及基础设施的监测数据以OpenMetrics标准接口的形式暴露给可观测监控 Prometheus 版,然后由可观测监控 Prometheus 版进行定期抓取并长期存储。

OpenMetrics,是云原生、高度可扩展的指标协议。 OpenMetrics定义了大规模上报云原生指标的事实标准,并支持文本表示协议和Protocol Buffers协议,文本表示协议在其中更为常见,也是在可观测监控 Prometheus 版进行数据抓取时默认采用的协议。下图是一个基于OpenMetrics格式的指标表示格式样例。

ert

说明

指标的数据模型由指标(Metric)名,以及一组Key/Value标签(Label)定义的,具有相同的度量名称以及标签属于相同时序集合。例如acme_http_router_request_seconds_sum{path="/api/v1",method="GET"} 可以表示指标名为acme_http_router_request_seconds_sum,标签method值为GET的一次采样点数据。采样点内包含一个Float64值和一个毫秒级的UNIX时间戳。随着时间推移,这些收集起来的采样点数据将在图表上实时绘制动态变化的线条。

目前,对于云原生体系下的绝大多数基础组件能够支持OpenMetrics的文本协议格式暴露指标,对于暂不能支持自身暴露指标的组件, Prometheus社区也存在极其丰富的Prometheus Exporter供开发及运维人员使用。这些组件(或Exporter)通过响应来自可观测监控 Prometheus 版的定期抓取请求来及时地将自身的运行状况记录到可观测监控 Prometheus 版以便后续的处理及分析。对于应用开发者,您还可以通过可观测监控 Prometheus 版的多语言SDK,进行代码埋点,将自身的业务指标也接入到上述的Prometheus生态当中。

数据可视化及分析

在获取应用或基础设施运行状态、资源使用情况,以及服务运行状态等直观信息后,通过查询和分析多类型、多维度信息能够方便地对节点进行跟踪和比较。同时,通过标准易用的可视化大盘去获知当前系统的运行状态。比较常见的解决方案就是Grafana,作为开源社区中目前热度很高的数据可视化解决方案,Grafana提供了丰富的图表形式与模板。在可观测监控 Prometheus 版中,也为您提供了基于Grafana全托管版的监测数据查询、分析及可视化。

及时的告警和应急管理

当业务即将出现故障时,监测系统需要迅速反应并通知管理员,从而能够对问题进行快速的处理或者提前预防问题的发生,避免出现对业务的影响。当问题发生后,管理员需要对问题进行认领和处理。通过对不同监测指标以及历史数据的分析,能够找到并解决根源问题。

接入流程概述

针对Spring Boot应用,社区提供了开箱即用的Spring Boot Actuator框架,方便Java开发者进行代码埋点和监测数据收集、输出。从Spring Boot 2.0开始,Actuator将底层改为Micrometer,同时提供了更强、更灵活的监测能力。Micrometer是一个监测门面,可以类比成监测界的Slf4j ,借助Micrometer,应用则能够对接各种监测系统。例如,AppOptics、Datadog、Elastic、InfluxDB以及可观测监控 Prometheus 版等。

Micrometer在将可观测监控 Prometheus 版指标对接到Java应用的指标时,支持应用开发者用三个类型的语义来映射:

Micrometer指标类型

可观测监控 Prometheus 版监控的指标类型

典型用途

Counter

Counter

计数器,单调递增场景。例如,统计PVUV,接口调用次数等。

Gauge

Gauge

持续波动的变量。例如,资源使用率、系统负载、请求队列长度等。

Timer

Histogram

统计数据分布。例如,统计某接口调用延时的P50、P90、P99等。

DistributionSummary

Summary

统计数据分布,与Histogram用途类似。

  • Micrometer中的Counter指标类型对应于可观测监控 Prometheus 版中的Counter指标类型,用来描述一个单调递增的变量。如某个接口的访问次数、缓存命中或者访问总次数等。Timer在逻辑上蕴含了Counter,即如果使用Timer采集每个接口的响应时间,必然也会采集访问次数。因此无需为某个接口同时指定TimerCounter两个指标。

  • MicroMeter中的Gauge指标类型对应于可观测监控 Prometheus 版中的Gauge指标类型,用来描述在一个范围内持续波动的变量。如CPU使用率、线程池任务队列数等。

  • MicroMeter中的Timer指标类型对应于可观测监控 Prometheus 版中的Histogram,用来描述与时间相关的数据。如某个接口RT时间分布等。

  • Micrometer中的DistributionSummary指标类型对应可观测监控 Prometheus 版中的Summary指标类型 ,与Histogram类似,Summary也是用于统计数据分布的,但由于数据的分布情况是在客户端计算完成后再传入可观测监控 Prometheus 版进行存储,因此Summary的结果无法在多个机器之间进行数据聚合,无法统计全局视图的数据分布,使用起来有一定局限性。

接入流程

当您需要把部署在Kubernetes集群中的Spring Boot应用接入到可观测监控 Prometheus 版时,需要按照代码埋点>部署应用>服务发现这个流程来进行。

image

首先,您需要在代码中引入Spring Boot Actuator相关Maven依赖,并对您需要监测的数据进行注册,或对Controller内的方法打上相应的注解。

其次,您需要将埋点后的应用部署在Kubernetes中,并向可观测监控 Prometheus 版注册向应用拉取监测数据的端点(即可观测监控 Prometheus 版的服务发现)。阿里云Prometheus服务提供了使用ServiceMonitor CRD进行服务发现的方法。

最后,在目标应用的监测采集端点被可观测监控 Prometheus 版成功发现后,您就可以在Grafana上配置数据源及相应的大盘。同时您也可以根据某些关键指标进行对应的告警配置。

最终目标

通过将部署在Kubernetes集群中的Spring Boot应用接入到可观测监控 Prometheus 版,希望能够实现以下几点目标:

  • 监测系统的入口:Frontend服务是一个基于SpringMVC开发的入口应用,承接外部的客户流量,这里主要关注的是外部接口的关键RED指标。例如,调用率Rate、失败数Error、请求耗时Duration。

  • 监测系统的关键链路:对后端服务critical path上的对象进行监测。例如,线程池的队列情况、进程内Guava Cache缓存的命中情况。

  • 实现对业务强相关的自定义指标进行监测。例如,某个接口的UV等。

  • 实现对JVM GC及内存使用情况进行监测。

  • 实现对上述指标进行统一汇聚展示,以及配置关键指标的告警。

步骤一:引入Spring Boot Actuator依赖,进行初始配置

这里选取一个基于Spring BootSpring Cloud Alibaba构建的云原生微服务应用,为您介绍部署在Kubernetes集群上的Spring Boot微服务应用如何进行Prometheus接入的具体接入流程。

  1. 执行如下代码段,引入Spring Boot Actuator的相关依赖。

    <!-- spring-boot-actuator依赖 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>
    <!-- prometheus依赖 -->
    <dependency>
        <groupId>io.micrometer</groupId>
        <artifactId>micrometer-registry-prometheus</artifactId>
    </dependency>
  2. application.properties中添加相关配置暴露监测数据端口。例如,端口为8091。

    # application.properties添加以下配置用于暴露指标
    spring.application.name=frontend
    
    management.server.port=8091
    management.endpoints.web.exposure.include=*
    management.metrics.tags.application=${spring.application.name}

    配置成功后,即可访问该应用的8091端口,然后您可以在该端口的/actuator/prometheus路径中获取OpenMetrics标准的监测数据。

步骤二:代码埋点及改造

若要获取某个API接口的RED指标,您需要在对应的接口方法上打@Timed注解。这里以index页面接口为例打@Timed注解,如下代码段所示。

@Timed(value = "main_page_request_duration", description = "Time taken to return main page", histogram = true)
@ApiOperation(value = "首页", tags = {"首页操作页面"})
@GetMapping("/")
public String index(Model model) {
    model.addAttribute("products", productDAO.getProductList());

    model.addAttribute("FRONTEND_APP_NAME", Application.APP_NAME);
    model.addAttribute("FRONTEND_SERVICE_TAG", Application.SERVICE_TAG);
    model.addAttribute("FRONTEND_IP", registration.getHost());

    model.addAttribute("PRODUCT_APP_NAME", PRODUCT_APP_NAME);
    model.addAttribute("PRODUCT_SERVICE_TAG", PRODUCT_SERVICE_TAG);
    model.addAttribute("PRODUCT_IP", PRODUCT_IP);

    model.addAttribute("new_version", StringUtils.isBlank(env));
    return "index.html";
}
说明

其中value即为暴露到/actuator/prometheus中的指标名字,histogram=true表示暴露这个接口请求时长的histogram直方图类型指标,便于您后续计算P90、P99等请求时间分布情况。

若您的应用中使用了进程内缓存库(例如,最常见的Guava Cache库等)且需要追踪进程内缓存的运行状况,您可以按照Micrometer提供的修饰方法,对于待监测的关键对象进行封装。

Guava Cache改造

  1. 注入MeterRegistry,这里注入的具体实现是PrometheusMeterRegistry,由Spring Boot自行注入即可。

  2. 使用工具类API包装本地缓存,即如下图中的GuavaCacheMetrics.monitor。

  3. 开启缓存数据记录,即调用.recordStats()方法。

  4. Cache对象命名,用于生成对应的指标。

eru

线程池改造

  1. 注入MeterRegistry,这里注入的具体实现是PrometheusMeterRegistry。

  2. 使用工具类API包装线程池。

  3. 为线程池命名,用于生成对应的指标。

ert

在开发过程中还会涉及许多业务强相关的自定义指标,为了监测这些指标,在往Bean中注入MeterRegistry后,您还需要按照需求和对应场景构造Counter、GaugeTimer来进行数据统计,并将其注册到MeterRegistry进行指标暴露,示例如下。

@Service
public class DemoService {

    Counter visitCounter;

    public DemoService(MeterRegistry registry) {
        visitCounter = Counter.builder("visit_counter")
            .description("Number of visits to the site")
            .register(registry);
    }

    public String visit() {
        visitCounter.increment();
        return "Hello World!";
    }    
}

至此,您对应用的代码改造工作已全部完成。然后您需要将应用镜像重新构建并部署到已安装可观测监控 Prometheus 版Kubernetes集群中,并在可观测监控 Prometheus 版控制台中配置ServiceMonitor,进行服务发现。更多信息,请参见Prometheus实例 for 容器服务管理Kubernetes集群服务发现

ServiceMonitor配置完成后,您可以在Targets列表中查看到刚注册的Service应用。

erti

步骤三:看板配置

应用的监测数据已成功收集并存储到可观测监控 Prometheus 版,因此您可以配置相应的大盘及告警来查看监控到的数据。这里,为您提供以下两个Grafana社区中的开源大盘模板来构建您自己的业务监测模板。

借助以上模板以及可观测监控 Prometheus 版内置的Grafana服务,您可以根据自己的需求,将日常开发和运维过程中需要重点关注的指标展示在同一个Grafana Dashboard页面上,创建属于您的个性化大盘,便于日常监测。例如,这里基于上述模板和自身业务构建了一个真实的大盘,包含总览、组件运行时间,内存使用率、堆内堆外内存、分代GC情况等。

wsd