前沿

写这篇文章的目的是发现自己整天埋头写业务代码但忽略了主动发现问题的能力,这里指的是监控和报警。结合工作中发现Prometheus和Grafana还是主流一些。本文介绍如何使用自定义指标,并使用Prometheus进行监控并报警,同时在 Grafana 进行展现。

看完本文的收益:

  • 主动发现线上问题,而不用被动等客诉,线上问题的概率会变少。
  • 向上汇报,相比于你写的代码更喜欢能量化的东西比如UI中的数据。

项目搭建

目标:我的目标是监听服务的调用次数和接口的RT
技术栈:SpringBoot服务、Prometheus和Grafana
注意事项:整个过程都是通过Docker安装,高效

SpringBoot工程配置

首先新加一个SpringBoot项目,引入Prometheus的依赖

<!--增加依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>io.micrometer</groupId>
            <artifactId>micrometer-core</artifactId>
        </dependency>
        <dependency>
            <groupId>io.micrometer</groupId>
            <artifactId>micrometer-registry-prometheus</artifactId>
        </dependency>

需要配置properties开启监控

spring.application.name=springboot-demo
server.port=8082


#将所有Actuator端点暴露
management.endpoints.web.exposure.include=*
#启用Prometheus指标导出
management.metrics.export.prometheus.enabled=true
#springboot-demo
management.metrics.tags.application=${spring.application.name}
#启用Tomcat MBean注册表,以便于通过JMX进行监控和管理
server.tomcat.mbeanregistry.enabled=true

检查boot段监控是开启成功,在浏览器中输入http://ip:port/actuator/prometheus。出现下图所示,表示boot已经能配置成功。

prometheus如何清空Discovered labels指标 prometheus自定义指标_java


然后带着目标(监控方法的调用次数和RT)去编写代码

package com.example.springbootprometheusgrafanademo;

import io.micrometer.core.instrument.Counter;
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.Tags;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.Random;

/**
 * @author chaird
 * @create 2024-05-17 0:38
 */
@RestController
public class MethodCountController {


    /**
     * 引入micrometer的工具类
     */
    @Resource
    private MeterRegistry meterRegistry;


    @GetMapping("/deleteCount")
    public Object deleteCount() {
        System.out.println("deleteCount-----" + LocalDateTime.now().toString());
        incrementMonitorConut("com.example.springbootprometheusgrafanademo.HelloController.deleteCount");
        return "deleteCount-----" + LocalDateTime.now().toString();
    }

    @GetMapping("/addCount")
    public Object addCount() {
        System.out.println("add-----" + LocalDateTime.now().toString());
        incrementMonitorConut("com.example.springbootprometheusgrafanademo.HelloController.addCount");
        return "addCount-----" + LocalDateTime.now().toString();
    }


    /**
     * 记录接口调用次数
     *
     * @param method
     */
    public void incrementMonitorConut(String method) {
        //定义指标名称
        String mertricName = "method_count";
        Counter counter = meterRegistry.counter(mertricName, "methodName", method);
        counter.increment();
    }


    /*********************************************************************************************/
    /********************************上面是接口调用次数,下面是接口调用耗时******************************/
    /*********************************************************************************************/
    @GetMapping("/deleteRt")
    public Object deleteRt() {
        System.out.println("deleteRt-----" + LocalDateTime.now().toString());
        recordMethodRt("com.example.springbootprometheusgrafanademo.HelloController.deleteRt", 20L);
        return "deleteRt-----" + LocalDateTime.now().toString();
    }

    @GetMapping("/addRt")
    public Object addRt() {
        System.out.println("addRt-----" + LocalDateTime.now().toString());
        recordMethodRt("com.example.springbootprometheusgrafanademo.HelloController.addRt", 10L);
        return "addRt-----" + LocalDateTime.now().toString();
    }


   /**
     * 记录接口的RT
     *
     * @param method
     */
    public void recordMethodRt(String method, Long rt) {
        //定义指标名称
        String mertricName = "method_rt";
        meterRegistry.timer(mertricName, Tags.of("methodName", method)).record(rt, java.util.concurrent.TimeUnit.MILLISECONDS);
    }


}

启动boot应用程序。

搭建Prometheus

注意:下面使用Docker安装,简单省事

首先编写一个配置文件prometheus.yml,告诉Prometheus要监听哪些应用程序,当然本文要监听的是boot程序

scrape_configs:
  - job_name: 'spring_boot_app'   # job 名称
    metrics_path: '/actuator/prometheus'   # 监控路径
    static_configs:
      - targets: ['101.200.123.220:8082']  # 监控目标,即本文中的boot的端口和IP

然后通过docker启动应用程序

docker run -d -p 9090:9090 -v /root/cbeann/docker/prometheus.yml:/etc/prometheus/prometheus.yml --name prometheus prom/prometheus

访问**http://ip:port/**并选择下面标签,就可以看到下面这个标就表明boot已经被prometheus监听到了。

prometheus如何清空Discovered labels指标 prometheus自定义指标_spring_02


接下来触发几个请求保证有数据,此时我写了个脚本curl100.sh循环触发100次,简单操作

#!/bin/bash

# 循环执行 curl 命令 100 次
for ((i = 1; i <= 100; i++)); do

     # 执行 curl 命令
    curl -s -o /dev/null http://101.200.123.220:8082/addCount  # 替换 http://example.com 为你要请求的 URL

    # 输出当前循环次数
    echo "Curl request $i"

    # 休眠 1 秒
    sleep 1

        # 执行 curl 命令
    curl -s -o /dev/null http://101.200.123.220:8082/deleteCount  # 替换 http://example.com 为你要请求的 URL

    # 输出当前循环次数
    echo "Curl request $i"

    # 休眠 1 秒
    sleep 1

        # 执行 curl 命令
    curl -s -o /dev/null http://101.200.123.220:8082/deleteRt  # 替换 http://example.com 为你要请求的 URL

    # 输出当前循环次数
    echo "Curl request $i"

    # 休眠 1 秒
    sleep 1

            # 执行 curl 命令
    curl -s -o /dev/null http://101.200.123.220:8082/addRt  # 替换 http://example.com 为你要请求的 URL

    # 输出当前循环次数
    echo "Curl request $i"

    # 休眠 1 秒
    sleep 1



done

执行脚本

sh curl100.sh

此时prometheus已经有数据了,然后点操作一下就能看到数据了。

prometheus如何清空Discovered labels指标 prometheus自定义指标_spring_03

Grafana美化监控

docker安装Grafana,执行命令如下

docker run -d --name=grafana -p 3000:3000 grafana/grafana

执行完毕后输入**http://ip:port/**后, 首次访问时,默认的用户名和密码是 admin/admin

首先添加一个Prometheus的数据源

prometheus如何清空Discovered labels指标 prometheus自定义指标_prometheus_04


然后输入Prometheus的地址,然后选择最下面的Save,没问题后创建面板Dashboard

prometheus如何清空Discovered labels指标 prometheus自定义指标_java_05

在面板上选择自定义的指标,然后按照顺序点一下,整个图就简单绘制出来了。

prometheus如何清空Discovered labels指标 prometheus自定义指标_java_06

Grafana不美观怎办。官方有专门的主题面板库https://grafana.com/grafana/dashboards/ ,可以直接导入

prometheus如何清空Discovered labels指标 prometheus自定义指标_prometheus_07

总结

领导爱看大盘,Grafana就挺好
既要低头干活(CRUD),更要抬头看路
主动发现问题