1.简介
Prometheus是开源的监控,告警系统,从2012开始被很多公司开始使用,并且有非常活跃的开发人员和社区。目前作为独立的开源项目维护,不依赖任何公司。并且已加入CNCF阵营。
Prometheus主要的特性:
- 数据模型:通过标签名称和键值对定的多维时序
- PromQL:可根据不同维度查询的引擎
- 不依赖分布式存储,支持本地存储
- 通过HTTP方式拉去时间序列集合
- 通过gateway可以支持推送
- 通过服务发现或静态配置确定收集目标
- 支持多种模式图形和仪表盘
Prometheus架构和生态
![](https://img.haomeiwen.com/i12039474/6aa5087233835a58.png)
组件说明
- Prometheus server : 用于抓取和存储时间序列数据
- 用于检测应用程序代码的客户端库
- push gateway:支持短时任务
- 针对特定服务的Exporter,如HAProxy, StatsD, Graphite等
- 一个处理告警的告警管理器
- 各种工具
Prometheus 直接或者间接通过gateway拉去指标度量值,并将拉去的样本存储在本地。从拉去的样本数据中按照规则聚合并产生新的时序数据,或者告警数据。通过Grafana将收集的数据可视化。
Prometheus 使用的场景
Prometheus 对数字型的时间序列有很好的支持。既适用于以机器为维度的的监控,也适用于动态变化的服务架构的监控,对于微服务中的数据收集和查询也很有优势。
Prometheus 是为可靠性而设计的,在出现宕机的时候能够帮助你快速诊断问题。每个Prometheus 服务器都是独立的,不依赖于网络存储或其他远程服务。
Prometheus 主要是为了保证系统本身的可用性,出现问题是可以通过它定位分析。但是对于业务系统中的数据不要依赖Prometheus 。因为Prometheus 里面的数据毕竟不是全量的,而是采样数据。
Prometheus 中metric的格式
格式:<metric name>{<label name>=<label value>, ...}
例如:api_http_requests_total{method="POST", handler="/messages"}
metric name :唯一标识,命名遵循[a-zA-Z_:][a-zA-Z0-9_:]*.
Prometheus 中metric的类型
-
Counter
一个Counter表示一个累计度量,只增不减,重启后恢复为0。适用于访问次数统计,异常次数统计等场景。 -
Gauge
Gauge表示可变化的度量值,适用于CPU,内存使用率等 -
Histogram
Histogram对指标的范围性(区间)统计。比如内存在0%-30%,30%-70%之间的采样次数。
Histogram包含三个指标:
<basename>:度量值名称
<basename>_count: 样本反正总次数
<basename>_sum:样本发生次数中值得综合
<basename>_bucket{le="+Inf"}: 每个区间的样本数 -
Summary
和histogram类似,提供次数和总和,同时提供每个滑动窗口中的分位数。
histogram 和Summary的对比
序号 | histogram | Summary |
---|---|---|
配置 | 区间配置 | 分位数和滑动窗口 |
客户端性能 | 只需增加counters代价小 | 需要流式计算代价高 |
服务端性能 | 计算分位数消耗大,可能会耗时 | 无需计算,代价小 |
时序数量 | _sum、_count、bucket | _sum、_count、quantile |
分位数误差 | bucket的大小有关 | φ的配置有关 |
φ和滑动窗口 | Prometheus 表达式设置 | 客户端设置 |
聚合 | 根据表达式聚合 | 一般不可聚合 |
Prometheus 中的JOBS 和INSTANCES
- INSTANCES:供采集的API endpoint
- JOBS:相同目的的INSTANCES
例如,四个节点上的api-server
job: api-server
instance 1: 1.2.3.4:5670
instance 2: 1.2.3.4:5671
instance 3: 5.6.7.8:5670
instance 4: 5.6.7.8:5671
Prometheus 拉去目标数据时,会自动给目标的时序上增加一些标签,用于唯一标识,如果时序中本省已经包含,那么取决于honor_labels。
- JOB:会增加JOB名称
- instance增加host:port
2.如何为中间件开发Exporter
Prometheus 为开发这提供了客户端工具,用于为自己的中间件开发Exporter,对接Prometheus 。
目前支持的客户端
以go为例开发自己的Exporter
2.1依赖包的引入
工程结构
[root@node1 data]# tree exporter/
exporter/
├── collector
│ └── node.go
├── go.mod
└── main.go
1 directory, 3 files
引入依赖包
require (
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.1 // indirect
github.com/prometheus/client_golang v1.1.0
//借助gopsutil 采集主机指标
github.com/shirou/gopsutil v0.0.0-20190731134726-d80c43f9c984
)
main.go
package main
import (
"cloud.io/exporter/collector"
"fmt"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
"net/http"
)
func init() {
//注册自身采集器
prometheus.MustRegister(collector.NewNodeCollector())
}
func main() {
http.Handle("/metrics", promhttp.Handler())
if err := http.ListenAndServe(":8080", nil); err != nil {
fmt.Printf("Error occur when start server %v", err)
}
}
为了能看清结果我将默认采集器注释,位置registry.go
func init() {
//MustRegister(NewProcessCollector(ProcessCollectorOpts{}))
//MustRegister(NewGoCollector())
}
/collector/node.go
代码中涵盖了Counter、Gauge、Histogram、Summary四种情况,一起混合使用的情况,具体的说明见一下代码中。
package collector
import (
"github.com/prometheus/client_golang/prometheus"
"github.com/shirou/gopsutil/host"
"github.com/shirou/gopsutil/mem"
"runtime"
"sync"
)
var reqCount int32
var hostname string
type NodeCollector struct {
requestDesc *prometheus.Desc //Counter
nodeMetrics nodeStatsMetrics //混合方式
goroutinesDesc *prometheus.Desc //Gauge
threadsDesc *prometheus.Desc //Gauge
summaryDesc *prometheus.Desc //summary
histogramDesc *prometheus.Desc //histogram
mutex sync.Mutex
}
//混合方式数据结构
type nodeStatsMetrics []struct {
desc *prometheus.Desc
eval func(*mem.VirtualMemoryStat) float64
valType prometheus.ValueType
}
//初始化采集器
func NewNodeCollector() prometheus.Collector {
host,_:= host.Info()
hostname = host.Hostname
return &NodeCollector{
requestDesc: prometheus.NewDesc(
"total_request_count",
"请求数",
[]string{"DYNAMIC_HOST_NAME"}, //动态标签名称
prometheus.Labels{"STATIC_LABEL1":"静态值可以放在这里","HOST_NAME":hostname}),
nodeMetrics: nodeStatsMetrics{
{
desc: prometheus.NewDesc(
"total_mem",
"内存总量",
nil, nil),
valType: prometheus.GaugeValue,
eval: func(ms *mem.VirtualMemoryStat) float64 { return float64(ms.Total) / 1e9 },
},
{
desc: prometheus.NewDesc(
"free_mem",
"内存空闲",
nil, nil),
valType: prometheus.GaugeValue,
eval: func(ms *mem.VirtualMemoryStat) float64 { return float64(ms.Free) / 1e9 },
},
},
goroutinesDesc:prometheus.NewDesc(
"goroutines_num",
"协程数.",
nil, nil),
threadsDesc: prometheus.NewDesc(
"threads_num",
"线程数",
nil, nil),
summaryDesc: prometheus.NewDesc(
"summary_http_request_duration_seconds",
"summary类型",
[]string{"code", "method"},
prometheus.Labels{"owner": "example"},
),
histogramDesc: prometheus.NewDesc(
"histogram_http_request_duration_seconds",
"histogram类型",
[]string{"code", "method"},
prometheus.Labels{"owner": "example"},
),
}
}
// Describe returns all descriptions of the collector.
//实现采集器Describe接口
func (n *NodeCollector) Describe(ch chan<- *prometheus.Desc) {
ch <- n.requestDesc
for _, metric := range n.nodeMetrics {
ch <- metric.desc
}
ch <- n.goroutinesDesc
ch <- n.threadsDesc
ch <- n.summaryDesc
ch <- n.histogramDesc
}
// Collect returns the current state of all metrics of the collector.
//实现采集器Collect接口,真正采集动作
func (n *NodeCollector) Collect(ch chan<- prometheus.Metric) {
n.mutex.Lock()
ch <- prometheus.MustNewConstMetric(n.requestDesc,prometheus.CounterValue,0,hostname)
vm, _ := mem.VirtualMemory()
for _, metric := range n.nodeMetrics {
ch <- prometheus.MustNewConstMetric(metric.desc, metric.valType, metric.eval(vm))
}
ch <- prometheus.MustNewConstMetric(n.goroutinesDesc, prometheus.GaugeValue, float64(runtime.NumGoroutine()))
num, _ := runtime.ThreadCreateProfile(nil)
ch <- prometheus.MustNewConstMetric(n.threadsDesc, prometheus.GaugeValue, float64(num))
//模拟数据
ch <- prometheus.MustNewConstSummary(
n.summaryDesc,
4711, 403.34,
map[float64]float64{0.5: 42.3, 0.9: 323.3},
"200", "get",
)
//模拟数据
ch <- prometheus.MustNewConstHistogram(
n.histogramDesc,
4711, 403.34,
map[float64]uint64{25: 121, 50: 2403, 100: 3221, 200: 4233},
"200", "get",
)
n.mutex.Unlock()
}
![](https://img.haomeiwen.com/i12039474/3553c003df0f336b.png)
网友评论