整合springboot,prometheus中guage的使用,统计一段时间中某个值的积累

1. 前言

    工作几个月了,但是工作的前3个月几乎没有工作内容,从国庆节后终于步入工作节奏,开始接一些需求了,老早就想督促自己去学习去记录,但是自制力太差了,希望自己可以慢慢的写博客、读书,取得一些进步,在半年后取得一些成果。
    之前看了半天的spring security ,本想写一篇博客,结果因为太懒,一直没动笔,都忘光了。。
    言归正传,前阵子leader给了我一个监控的需求,需要使用prometheus,因此我去调研了一下,然后在项目中使用。

2. prometheus简介

    关于prometheus的介绍,网上有很多,我就不在此班门弄斧了,里面主要有counter、gauge、timer、summary和histogram五种度量方式,前三种比较好理解,后两种我理解的是对某一个值分布的统计,即横坐标不是时间轴。

3. gauge的使用

    现在需求是这样的,将时间轴等距离均分,如间隔是一分钟,然后去监控每一分钟内发送到kafka中的消息数量。首先counter是不能使用的,因为counter的设定是只增不减,然后summary和histogram在我的理解中是对分布的统计和监控,所以也不能使用,因此我只好投机取巧的使用了gauge(投机取巧说的是:gauge的意义更在于是统计一个实时的值,反应一种动态变化)。
    因为项目使用的是springboot2.x,为了方便,就结合actuator使用了,引入如下依赖(项目使用的是gradle,目前感觉没有maven好用)

   compile group: 'org.springframework.boot', name: 'spring-boot-starter-actuator', version: '2.2.10.RELEASE'
   compile group: 'io.micrometer', name: 'micrometer-registry-prometheus', version: '1.1.3'

3.1 定义gauge变量

     要使用gauge,首先需要引入register,并在register中注册gauge,gauge的定义包括名字以及一个Number(当然还有其他的注册方式,如标签等,需要可以自行google),因为此处要统计某段时间内某个值的积累量,因此我做了如下定义

gaugeMap.put(gaugeName,registry.gauge(gaugeName,new AtomicLong(0));

     放入map中的目的是为了之后容易操作。
     然后我们可以使用该gauge对需要统计的量进行增量,如以下操作

send(){
	kafkaTemplate.send(topic, data);
	gaugeMap.get(gaugeName).incrementAndGet();
}

     当然,监控操作最好是使用aop来进行,这样可以和业务代码分离。

3.2 统计该gauge变量在某一段时间内的积累值

    首先我们要明白,prometheus收集监控信息时,不支持push操作,需要对配置的各个监控目标进行pull操作,因为我们要监控一分钟内的积累量,就需要将prometheus server端的拉取间隔配置为60s,接下来就遇到了另一个问题,在prometheus server拉取的时候,如何正好将这一刻的积累值给它,并进行清零操作呢?
    我的思路是这样的,prometheus server端拉取信息也是通过springboot项目暴露的http端点,因此可以通过拦截器,当拉取结束后就对gauge的积累值进行清零。结果发现拦截器并不起作用,后来想起来暴露的端口都可以通过配置替换,所以可能是springboot项目中,prometheus client自己起了一个springboot环境,因此导致拦截器无效。灵机一动,想到过滤器是在servlet层面进行过滤的,应该会生效吧,然后尝试了一下果然可以拦截到 ip:port/actuator/prometheus 端点,所以就选择使用过滤器进行这个操作。
    这里还有一个坑,在filter中自动注入为null。这是因为在spring项目中,在项目启动时,监听器listener最先初始化,然后是过滤器filter,最后是servlet。 Spring监听器在启动时会读取spring配置文件,进行spring容器的初始化。springMVC的dispatcherServlet初始化时会读取springMVC的配置文件,进行springMVC容器的初始化。Spring容器初始化时会实例化各个bean。过滤器是servlet规范中定义的,并不归spring容器管理,也无法直接注入spring中的bean,所以在filter中无法注入spring的实例。
    因此使用如下方法注入即可

public void init(FilterConfig config) throws ServletException {
        ServletContext sc = config.getServletContext();
        ApplicationContext ctx = WebApplicationContextUtils.getWebApplicationContext(sc);
        if (ctx != null && ctx.getBean("prometheusMonitor") != null) {
            monitor = (PrometheusCustomMonitor) ctx.getBean("prometheusMonitor");
            log.info("prometheusMonitor 注入");
        }
}

    之后就可以愉快的使用它了,然后我们配置好filter的拦截路径后,进行如下操作

public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain){
	filterChain.doFilter(servletRequest, servletResponse);
	gaugeMap.get(gaugeName).set(0L);
}

这样大体的使用就讲完了,希望之后可以每周或者每两周写一篇博客,加油。

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值