基本概念
Prometheus 所有采集的监控数据均以指标(metric)的形式保存在内置的时间序列数据库当中(TSDB):属于同一指标名称,同一标签集合的、有时间戳标记的数据流。除了存储的时间序列,Prometheus 还可以根据查询请求产生临时的、衍生的时间序列作为返回结果。
样本在时间序列中的每一个点称为一个样本(sample),样本由以下三部分组成:
指标(metric):指标名称和描述当前样本特征的 labelsets;
时间戳(timestamp):一个精确到毫秒的时间戳;
样本值(value): 一个 folat64 的浮点型数据表示当前样本的值。
1 | <metric name>{<label name>=<label value>, ...} |
Metric类型
Prometheus 客户端公开了在暴露服务指标时能够运用的四种指标类型。查看 Prometheus 的文档 以获得关于各种指标类型的深入信息。
Counter(计数器
一种累加的 metric,典型的应用如:请求的个数,结束的任务数,出现的错误数等。随着客户端不断请求,数值越来越大。例如api_http_requests_total{method="POST", handler="/messages"}
Gauge(计量器)
一种常规的 metric,典型的应用如:温度,运行的 goroutines 的个数。返回的数值会上下波动。
例如 go_goroutines{instance="172.17.0.2", job="Prometheus"}
Histogram(分布图)
可以理解为柱状图,典型的应用如:请求持续时间,响应大小。可以对观察结果采样,分组及统计。例如设置一个name为web_request_duration_seconds
的Histogram 的metrics,并设置区间值为[0.1,0.5,1]
会对区间点生成一条统计数据.
1 | # 响应时间小于0.1s的请求有5次 |
Summary(摘要)
跟 histogram 类似,summary 也对观测值(类似请求延迟或回复包大小)进行采样。同时它会给出一个总数以及所有观测值的总和,它在一个滑动的时间窗口上计算可配置的分位数。, 典型的应用如:请求持续时间,响应大小。主要做统计用,设置分位数的值,会实时返回该分位数上的值。
Golang中集成
Prometheus 程序库 提供了一个用 Golang 写成的健壮的插桩库,可以用来注册,收集和暴露服务的指标。在讲述如何在应用程序中暴露指标前,让我们先来探究一下 Prometheus 库提供的各种指标类型。
下载 Prometheus go 客户端
go get github.com/prometheus/client_golang/prometheus/promhttp
.Golang应用中集成 Prometheus HTTP 服务器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15package main
import (
"net/http"
"github.com/prometheus/client_golang/prometheus/promhttp"
)
func main() {
// expose prometheus metrics接口
server := http.NewServeMux() // create a new mux server
server.Handle("/metrics", promhttp.Handler()) // register a new handler for the /metrics endpoint
log.Fatal(http.ListenAndServe(":8080", server)) // start an http server using the mux server
}启动应用访问
http://localhost:8080/metrics
,会返回一些go应用中goroutine,thread、gc、堆栈的基本信息。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29# HELP go_gc_duration_seconds A summary of the GC invocation durations.
# TYPE go_gc_duration_seconds summary
go_gc_duration_seconds{quantile="0"} 0
go_gc_duration_seconds{quantile="0.25"} 0
go_gc_duration_seconds{quantile="0.5"} 0
go_gc_duration_seconds{quantile="0.75"} 0
go_gc_duration_seconds{quantile="1"} 0
go_gc_duration_seconds_sum 0
go_gc_duration_seconds_count 0
# HELP go_goroutines Number of goroutines that currently exist.
# TYPE go_goroutines gauge
go_goroutines 6
# HELP go_info Information about the Go environment.
# TYPE go_info gauge
go_info{version="go1.12"} 1
添加自定义指标
- 创建指标并注册到prometheus
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25// 初始化 web_reqeust_total, counter类型指标, 表示接收http请求总次数
var WebRequestTotal = prometheus.NewCounterVec(
prometheus.CounterOpts{
Name: "web_reqeust_total",
Help: "Number of hello requests in total",
},
// 设置两个标签 请求方法和 路径 对请求总次数在两个
[]string{"method", "endpoint"},
)
// web_request_duration_seconds,Histogram类型指标,bucket代表duration的分布区间
var WebRequestDuration = prometheus.NewHistogramVec(
prometheus.HistogramOpts{
Name: "web_request_duration_seconds",
Help: "web request duration distribution",
Buckets: []float64{0.1, 0.3, 0.5, 0.7, 0.9, 1},
},
[]string{"method", "endpoint"},
)
func init() {
// 注册监控指标
prometheus.MustRegister(WebRequestTotal)
prometheus.MustRegister(WebRequestDuration)
}- 在适当切入点对指标进行记录变更
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28// 包装 handler function,不侵入业务逻辑
func Monitor(h http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
start := time.Now()
h(w, r)
duration := time.Since(start)
// counter类型 metric的记录方式
WebRequestTotal.With(prometheus.Labels{"method": r.Method, "endpoint": r.URL.Path}).Inc()
// Histogram类型 meric的记录方式
WebRequestDuration.With(prometheus.Labels{"method": r.Method, "endpoint": r.URL.Path}).Observe(duration.Seconds())
}
}
···
func main() {
// expose prometheus metrics接口
http.Handle("/metrics", promhttp.Handler())
http.HandleFunc("/query", monitor.Monitor(Query))
log.Fatal(http.ListenAndServe(":8080", nil))
}
// query
func Query(w http.ResponseWriter, r *http.Request) {
//模拟业务查询耗时0~1s
time.Sleep(time.Duration(rand.Intn(1000)) * time.Millisecond)
_,_ = io.WriteString(w, "some results")
} - 启动并访问
http://localhost:8080/query
接口,并再次访问http://localhost:8080/metrics
接口,返回的指标数据中就有了刚加上的metric,如下所示1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28# HELP web_reqeust_total Number of hello requests in total
# TYPE web_reqeust_total counter
web_reqeust_total{endpoint="/hello",method="GET"} 1
web_reqeust_total{endpoint="/query",method="GET"} 7
# HELP web_request_duration_seconds web request duration distribution
# TYPE web_request_duration_seconds histogram
web_request_duration_seconds_bucket{endpoint="/query",method="GET",le="0.1"} 3
web_request_duration_seconds_bucket{endpoint="/query",method="GET",le="0.3"} 3
web_request_duration_seconds_bucket{endpoint="/query",method="GET",le="0.5"} 5
web_request_duration_seconds_bucket{endpoint="/query",method="GET",le="0.7"} 5
web_request_duration_seconds_bucket{endpoint="/query",method="GET",le="0.9"} 7
web_request_duration_seconds_bucket{endpoint="/query",method="GET",le="1"} 7
web_request_duration_seconds_bucket{endpoint="/query",method="GET",le="+Inf"} 7
web_request_duration_seconds_sum{endpoint="/query",method="GET"} 2.7190880529999997
web_request_duration_seconds_count{endpoint="/query",method="GET"} 7
- 在适当切入点对指标进行记录变更
代码地址
可以直接安装运行,详细说明可以参考官网
1 | go install github.com/crockitwood/go-prometheus-example |