目录
基于SpringBoot写一个简单的exporter_demo
4种常用Metrics
Counter
连续增加不会减少的计数器,可以用于记录只增不减的类型,例如:网站访问人数,系统运行时间等。
对于Counter类型的指标,只包含一个inc()的方法,就是用于计数器+1.
一般而言,Counter类型的metric指标在冥冥中我们使用_total结束,如http_requests_total.
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去取的时候还是只取当前那一时间点的数据,并不会把历史的也拿过来,这让我很困惑,如果这样,他存的在意义是什么呢?不过也不确定是否因为我使用的不太对。