您的当前位置:首页正文

Prometheus基于java开发exporter样例以及pushgateway的应用

2024-11-29 来源:个人技术集锦

 


4种常用Metrics

Counter

Gauge

可增可减的仪表盘,曲线图

对于这类可增可减的指标,用于反应应用的当前状态。

例如在监控主机时,主机当前空闲的内存大小,可用内存大小等等。

对于Gauge指标的对象则包含两个主要的方法inc()和dec(),用于增加和减少计数。

Histogram

主要用来统计数据的分布情况,这是一种特殊的metrics数据类型,代表的是一种近似的百分比估算数值,统计所有离散的指标数据在各个取值区段内的次数。例如:我们想统计一段时间内http请求响应小于0.005秒、小于0.01秒、小于0.025秒的数据分布情况。那么使用Histogram采集每一次http请求的时间,同时设置bucket。

Histogram会自动创建3个指标,分别为:
一、事件发生总次数: basename_count:
#实际含义: 当前一共发生了2次http请求
io_namespace_http_requests_latency_seconds_histogram_count{path="/",method="GET",code="200",} 2.0
二、所有事件产生值的大小的总和: basename_sum
#实际含义: 发生的2次http请求总的响应时间为13.107670803000001 秒
io_namespace_http_requests_latency_seconds_histogram_sum{path="/",method="GET",code="200",} 13.107670803000001
三、事件产生的值分布在bucket中的次数: basename_bucket{le="上包含"}
# 在总共2次请求当中。http请求响应时间 <=0.005 秒 的请求次数为0
io_namespace_http_requests_latency_seconds_histogram_bucket{path="/",method="GET",code="200",le="0.005",} 0.0
在总共2次请求当中。http请求响应时间 <=0.01 秒 的请求次数为0
io_namespace_http_requests_latency_seconds_histogram_bucket{path="/",method="GET",code="200",le="0.01",} 0.0
在总共2次请求当中。http请求响应时间 <=0.025 秒 的请求次数为0
io_namespace_http_requests_latency_seconds_histogram_bucket{path="/",method="GET",code="200",le="0.025",} 0.0

Summary

Summary和Histogram非常相似,都可以统计事件发生的次数或者大小,以及其分布情况,他们都提供了对时间的计数_count以及值的汇总_sum,也都提供了可以计算统计样本分布情况的功能,不同之处在于Histogram可以通过histogram_quantile函数在服务器计算分位数。而Sumamry的分位数则是直接在客户端进行定义的。因此对于分位数的计算,Summary在通过PromQL进行查询的时候有更好的性能表现,而Histogram则会消耗更多的资源,但是相对于客户端而言Histogram消耗的资源就更少。用哪个都行,根据实际场景自由调整即可。

基于SpringBoot写一个简单的exporter_demo

1.pom.xml配置如下

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>com.unicom</groupId>
	<artifactId>exporter-demo</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>jar</packaging>

	<name>exporter-demo</name>
	<description>Demo project for Spring Boot</description>

	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>1.5.11.RELEASE</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>

	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
		<java.version>1.8</java.version>
	</properties>

	<dependencies>

        <!--普罗米修斯依赖-->
        <dependency>
            <groupId>io.prometheus</groupId>
            <artifactId>simpleclient_spring_boot</artifactId>
            <version>0.4.0</version>
        </dependency>
        <dependency>
            <groupId>io.prometheus</groupId>
            <artifactId>simpleclient_hotspot</artifactId>
            <version>0.4.0</version>
        </dependency>
        <dependency>
            <groupId>io.prometheus</groupId>
            <artifactId>simpleclient_servlet</artifactId>
            <version>0.4.0</version>
        </dependency>
		<dependency>
			<groupId>io.prometheus</groupId>
			<artifactId>simpleclient_pushgateway</artifactId>
			<version>0.4.0</version>
		</dependency>
        <!--springboot-->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>
</project>

4个prometheus的依赖包和两个pushgateway的依赖包。

2.Application类注解

@SpringBootApplication
@EnableScheduling
@EnablePrometheusEndpoint
@EnableSpringBootMetricsCollector
public class ExporterDemoApplication{

	public static void main(String[] args) {
		SpringApplication.run(ExporterDemoApplication.class, args);
	}
}

添加@EnableScheduling注解主要是添加了定时任务,用于动态模拟数据的变化,后面会看到应用的地方。

3.CounterDemo

定义一个Counter类型的metrics,一般而言,Counter类型的metrics指标在命名中我们使用_total结束。

@RestController
public class CounterDemo {
    /*
     *  使用Counter.build()创建Counter类型的监控指标,并且通过name()方法定义监控指标的名称network_traffic_input
     * ,通过labelNames()定义该指标包含的标签。最后通过register()将该指标注册到Collector的defaultRegistry中
     */
    static final Counter counterDemo = Counter.build()
            .name("counterChanger2").labelNames("wy","zxjr","ocs","xxjf","unit")
            .help("Counter 实例").register();
    //指标埋点,定时器会造成普罗米修斯与本地的数据时间戳不同步,尽量不要使用这种方式,实例中的定时器是为了数据演示
    @Scheduled(cron="0/5 * * * * ?")
    @RequestMapping("/changeCounter")
    public  void changeCounter(){
      counterDemo.labels("网元","在线接入","OCS","消息计费","seconds").inc();//指标值增加
  }
}

这里每5秒会自动执行changeCounter用于模拟数据的变化。

4.GaugeDemo

@RestController
public class GaugeDemo {
    /**指标注册
     * name设置指标名
     * labelNames设置各项指标名称
     * help设置指标描述
     */
    static final Gauge gaugeDemo = Gauge.build()
            .name("gaugeDemo")
            .labelNames("label1","label2","label3","label4","label5")
            .help("gauge 实例").register();

    //指标埋点
    @Scheduled(cron="0/5 * * * * ?")
    @RequestMapping("/changeGauge")
    public  void  changeGauge() {
        gaugeDemo.labels("1","2","3","4","5").inc(); //指标值加1
        gaugeDemo.labels("1","2","3","4","5").dec(); //指标值减一
        gaugeDemo.labels("1","2","3","4","5").set(19.00); //指标值直接赋值
    }
}

可以看到Gauge类型的metrics可以对数据进行增加、减小和直接赋值。这种类型在实际应用中比较多。

5.HistogramDemo

@RestController
public class HistogramDemo
{
    /**
     * 注册
     * 注册时buckets()设置区间值,如下设置了100、200、300三个区间值
     */
    static final Histogram histogramDemo = Histogram.build()
                                                    .labelNames("label1", "label2", "label3", "label4", "label5")
                                                    .name("histogramDemo")
                                                    .buckets(100, 200, 300)
                                                    .help("Histogram 实例")
                                                    .register();
    //指标埋点
    @Scheduled(cron = "0/5 * * * * ?") 
    public void changeHistogram()
    {
        /**
         * 本次执行的指标值
         * 如下设置为150,则每次执行,小于200区间以及小于300区间加1,小于100区间不变
         */
        histogramDemo.labels("1", "2", "3", "4", "5").observe(150);
    }
}

定义了三个区间,小于100,小于200,小于300,而changeHistogram中每次我们设置数据为150,所以最后画出来的曲线只有两条。

6.SummaryDemo

@RestController
public class SummaryDemo {
    //注册
    static final Summary summaryDemo = Summary.build()
            .quantile(0.5, 0.01)   // 添加50%分位数,允许有5%的误差,相当于求中位数
            .quantile(0.9, 0.01)   // 添加90%分位数,允许有1%的误差
            .name("summaryDemo").labelNames("label1","label2","label3","label4","label5")
            .help("Summary 实例").register();
    //指标埋点
    @Scheduled(cron="0/5 * * * * ?")
    public  void  changeSummary(){
        summaryDemo.labels("1","2","3","4","5").observe(1);
    }
}

在prometheus的Graph中通过查看summaryDemo、summaryDemo_count、summaryDemo_sum查看对应结果。

7.关于pushgateway

@Component
public class PrometheusConfig
{
    public static final Counter counterDemo = Counter.build()
                                                        .name("push_way_counter")
                                                        .labelNames("wy","zxjr","ocs","xxjf","unit","instance")
                                                        .help("Counter 实例")
                                                        .register();
    //测试发送
    public static void main(String[] args)
    {
        PushGateway prometheusPush = new PushGateway("localhost:9091");
        try
        {
            for(int i=0;i<50;i++){
                counterDemo.labels("网元","在线接入","OCS","消息计费","byte","localhsot:9091").inc();
                prometheusPush.push(counterDemo,"sp-getway");
                Thread.sleep(5000);
            }
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
    }
}

这里拿counter举一个简单的例子,其他三种度量也是一样的处理方式。

关于pushgateway中转数据,根据我自己实际的验证,我发现索然说数据每次都会先发送到pushgateway,但是prometheus去取的时候还是只取当前那一时间点的数据,并不会把历史的也拿过来,这让我很困惑,如果这样,他存的在意义是什么呢?不过也不确定是否因为我使用的不太对。

参考文献

显示全文