Prometheus 第一篇:快速上手
metrics 类型
Prometheus 总共提供了四种类型的 metrics 类型,分别为下面四种类型
Counter
Counter 类型的指标其工作方式和计数器一样,只增不减(除非系统发生重置)
常见的监控指标,如 http_requests_total,node_cpu 都是 Counter 类型的监控指标
一般在定义 Counter 类型指标的名称时推荐使用 _total 作为后缀
Gauge
与Counter不同,Gauge类型的指标侧重于反应系统的当前状态。因此这类指标的样本数据可增可减。
常见指标如:
node_memory_MemFree(主机当前空闲的内容大小)
node_memory_MemAvailable(可用内存大小)都是Gauge类型的监控指标
Histogram & Summary
Q:为什么需要这两个指标?
A:在大多数情况下人们都倾向于使用某些量化指标的平均值,例如CPU的平均使用率、页面的平均响应时间。这种方式的问题很明显,以系统API调用的平均响应时间为例:如果大多数API请求都维持在100ms的响应时间范围内,而个别请求的响应时间需要5s,那么就会导致某些WEB页面的响应时间落到中位数的情况,而这种现象被称为****长尾问题
为了区分是平均的慢还是长尾的慢,最简单的方式就是按照请求延迟的范围进行分组。例如,统计延迟在0-10ms之间的请求数有多少而10-20ms之间的请求数又有多少。通过这种方式可以快速分析系统慢的原因。Histogram和Summary都是为了能够解决这样问题的存在,通过Histogram和Summary类型的监控指标,我们可以快速了解监控样本的分布情况
那么这两个指标的区别是什么?
我们针对下面这个指标来看一个具体的例子
summary 类型
# HELP prometheus_tsdb_wal_fsync_duration_seconds Duration of WAL fsync.
# TYPE prometheus_tsdb_wal_fsync_duration_seconds summary
prometheus_tsdb_wal_fsync_duration_seconds{quantile="0.5"} 0.012352463
prometheus_tsdb_wal_fsync_duration_seconds{quantile="0.9"} 0.014458005
prometheus_tsdb_wal_fsync_duration_seconds{quantile="0.99"} 0.017316173
prometheus_tsdb_wal_fsync_duration_seconds_sum 2.888716127000002
prometheus_tsdb_wal_fsync_duration_seconds_count 216
从上面的样本中可以得知当前Prometheus Server进行wal_fsync操作的总次数为216次,耗时2.888716127000002s。其中中位数(quantile=0.5)的耗时为0.012352463,9分位数(quantile=0.9)的耗时为0.014458005s
histogram 类型
# HELP prometheus_tsdb_compaction_chunk_range Final time range of chunks on their first compaction
# TYPE prometheus_tsdb_compaction_chunk_range histogram
prometheus_tsdb_compaction_chunk_range_bucket{le="100"} 0
prometheus_tsdb_compaction_chunk_range_bucket{le="400"} 0
prometheus_tsdb_compaction_chunk_range_bucket{le="1600"} 0
prometheus_tsdb_compaction_chunk_range_bucket{le="6400"} 0
prometheus_tsdb_compaction_chunk_range_bucket{le="25600"} 0
prometheus_tsdb_compaction_chunk_range_bucket{le="102400"} 0
prometheus_tsdb_compaction_chunk_range_bucket{le="409600"} 0
prometheus_tsdb_compaction_chunk_range_bucket{le="1.6384e+06"} 260
prometheus_tsdb_compaction_chunk_range_bucket{le="6.5536e+06"} 780
prometheus_tsdb_compaction_chunk_range_bucket{le="2.62144e+07"} 780
prometheus_tsdb_compaction_chunk_range_bucket{le="+Inf"} 780
prometheus_tsdb_compaction_chunk_range_sum 1.1540798e+09
prometheus_tsdb_compaction_chunk_range_count 780
可以看到这两个指标的区别如下:
- Summary 指标统计的是区间范围内的某个范围的数值,比如常见的请求的 P99,P90 等延迟
- Histogram 指标直接反应了在不同区间内样本的个数,区间通过标签len进行定义
快速入门
wget https://github.com/prometheus/prometheus/releases/download/v2.54.1/prometheus-2.54.1.linux-amd64.tar.gz解压后完成后直接启动即可
./prometheus --config.file=prometheus.yml
查看 metrics 路由和 graph 路由
配置文件 prometheus.yml 解析
# my global config
global:# 全局默认的数据拉取间隔scrape_interval: 15s # Set the scrape interval to every 15 seconds. Default is every 1 minute.# 全局默认的报警规则拉取间隔evaluation_interval: 15s # Evaluate rules every 15 seconds. The default is every 1 minute.# scrape_timeout is set to the global default (10s).# Alertmanager configuration
alerting:alertmanagers:- static_configs:- targets:# - alertmanager:9093# Load rules once and periodically evaluate them according to the global 'evaluation_interval'.
rule_files:# 规则相关的配置文件# - "first_rules.yml"# - "second_rules.yml"# A scrape configuration containing exactly one endpoint to scrape:
# Here it's Prometheus itself.# prometheus 配置规则相关的参数
scrape_configs:# The job name is added as a label `job=<job_name>` to any timeseries scraped from this config.# 任务名称- job_name: "prometheus"# metrics_path defaults to '/metrics'# scheme defaults to 'http'.# 配置 server 的暴露访问端口static_configs:- targets: ["localhost:9090"]
整体架构
参考上面这个图我们可以发现,prometheus 其实就是一个时序数据的中转站
输入源是配置有metrics 时序数据的各种 exporter
输出源就是将时序数据进行展示的终端组件 Grafana 以及可配置的报警组件 AlertManager
快速入门
下面我们结合 node_export 来演示如何接入 prometheus 以及如何配置相关的报警 AlertManager
下载 node_exporter 和 grafana 以及报警配置 alertmanager 并进行解压
wget https://github.com/prometheus/node_exporter/releases/download/v1.8.2/node_exporter-1.8.2.linux-amd64.tar.gzwget https://dl.grafana.com/enterprise/release/grafana-enterprise-11.2.2.linux-amd64.tar.gzwget https://github.com/prometheus/alertmanager/releases/download/v0.27.0/alertmanager-0.27.0.linux-amd64.tar.gz
配置对应的 metrics 新增一个 node_exporter 相关的 job
# A scrape configuration containing exactly one endpoint to scrape:
# Here it's Prometheus itself.
scrape_configs:# The job name is added as a label `job=<job_name>` to any timeseries scraped from this config.- job_name: "prometheus"# metrics_path defaults to '/metrics'# scheme defaults to 'http'.static_configs:- targets: ["localhost:9090"]# 新增的 node_exporter 的 job- job_name: "node_exporter"static_configs:- targets: ["localhost:9100"]
启动完成之后会发现对应的 node_exporter 的 metrics 已经能够被 prometheus 捕获到
任意选取一个指标进行观察可看到对应的时序曲线图
我们配置 grafana 来进行更加人性化的可视化展示
启动上面下载好的 grafana-server 之后,导入 node_exporter 的 dashboard 配置,即可获取如下所以的 dashboard 图形化展示
便可以看到所有的可视化时序数据的变化
我们以右上角的 CPU 核数来看看具体的查询语句是什么样子的
其实就是将从 node_exporter 里面暴露出去的指标进行了适当的聚合得出了 CPU 的总数
instance 就代表当前的实例的名称,宿主机的 ip:port 组成
job 就代表了当前运行的一个任务
Exporter 详解
记住下面这几个相关的端口
prometheus 9090
node_exporter 9100
grafana 3000
node_exporter
我们知道喂给 prometheus 的数据源必须都暴露一个相关的 /metrics 接口来吐出对应的 metrics 时序数据,node_exporter 自然也不例外
查看机器的 9100/metrics 端口会发现暴露出很多的指标
仔细观察 metrics 指标的数据格式,指标构成规则如下
指标名称 + label + 数值
代码解析
// 存储所有的 Collector
initiatedCollectors = make(map[string]Collector)// NewNodeCollector creates a new NodeCollector.
func NewNodeCollector(logger *slog.Logger, filters ...string) (*NodeCollector, error) {f := make(map[string]bool)// 判断是否 filters 中的 collector 是否存在for _, filter := range filters {enabled, exist := collectorState[filter]if !exist {return nil, fmt.Errorf("missing collector: %s", filter)}if !*enabled {return nil, fmt.Errorf("disabled collector: %s", filter)}f[filter] = true}collectors := make(map[string]Collector)initiatedCollectorsMtx.Lock()defer initiatedCollectorsMtx.Unlock()for key, enabled := range collectorState {if !*enabled || (len(f) > 0 && !f[key]) {continue}// 这里会按照State注册对应的collectorsif collector, ok := initiatedCollectors[key]; ok {collectors[key] = collector} else {collector, err := factories[key](logger.With("collector", key))if err != nil {return nil, err}collectors[key] = collectorinitiatedCollectors[key] = collector}}return &NodeCollector{Collectors: collectors, logger: logger}, nil
}
各种各样的 Collector 通过 init 函数注册到上面的 initiatedCollectors 里面
func init() {registerCollector("meminfo", defaultEnabled, NewMeminfoCollector)
}func init() {registerCollector("os", defaultEnabled, NewOSCollector)
}
我们以一个内存采集的具体例子溯源 node_export 是怎么采集到这个指标的
func NewMeminfoCollector(logger *slog.Logger) (Collector, error) {// 构建一个fs函数,procPath 的默认路径值是 /procfs, err := procfs.NewFS(*procPath)...
}func (c *meminfoCollector) getMemInfo() (map[string]float64, error) {// 这里构建一个Meminfo的结构体meminfo, err := c.fs.Meminfo()metrics := make(map[string]float64)if meminfo.ActiveBytes != nil {metrics["Active_bytes"] = float64(*meminfo.ActiveBytes)}if meminfo.ActiveAnonBytes != nil {metrics["Active_anon_bytes"] = float64(*meminfo.ActiveAnonBytes)}....
}func (fs FS) Meminfo() (Meminfo, error) {// 看这个函数名就是读取一个路径下面的 meminfo 的文件b, err := util.ReadFileNoStat(fs.proc.Path("meminfo"))....m, err := parseMemInfo(bytes.NewReader(b))
}
所以总结起来就是获取 /porc/meminfo 里面的信息再转化成 metrics 这个map里面的数据即可
自定义 exporter
理解了 prometheus 之后,我们可以编写一个最简单的 exporter 服务,服务必须暴露对应的 /metrics 接口供 prometheus 采集指标
// 定义一个 counter 类型的指标用来记录接口被请求的次数
var pingCounter = prometheus.NewCounter(prometheus.CounterOpts{Name: "ping_request_counter",Help: "No of request handled by Ping handler",
})func ping(w http.ResponseWriter, req *http.Request) {// 每当这个接口被请求时就将对应的metri指标递增一个值pingCounter.Inc()fmt.Fprintf(w, "pong")
}func main() {prometheus.MustRegister(pingCounter)http.HandleFunc("/ping", ping)// 这里必须暴露 /metrics 接口供 prometheus 进行监控接入http.Handle("/metrics", promhttp.Handler())http.ListenAndServe(":8090", nil)
}
启动上述服务之后,我们访问对应的 /ping 接口就能在看到对应的 metrics 的指标
配置prometheus文件,在 scrape_configs 参数底下新增如下的配置
scrape_configs:.....- job_name: simple_serverstatic_configs:- targets: ["localhost:8090"]
在 prometheus 的 web-ui 里面就能看到对应的配置信息以及指标的变化情况
配置报警
目前 prometheus 支持配置的告警目标方有 email, webhook, pagerduty, slack 这四种,我们这里实用 webhook 来进行告警配置
参考这里获取 webhook 相关的地址 Webhook.site - Test, transform and automate Web requests and emails
配置报警相关参数
global:resolve_timeout: 5m
route:receiver: webhook_receiver
receivers:- name: webhook_receiverwebhook_configs:- url: '<INSERT-YOUR-WEBHOOK>' # 这里替换成上面的webhook-urlsend_resolved: false
启动 alertmanager
alertmanager --config.file=alertmanager.yml
访问 9093 端口如果能看到下述相关信息则代表配置成功
修改 prometheus 配置文件来对接 alertmanager
# Alertmanager configuration
alerting:alertmanagers:- static_configs:- targets:- localhost:9093
rule_files:- rules.yml
新增 rules.yaml 文件
groups:
# 代表当指标 ping_request_count 超过 8 时便触发报警- name: Count greater than 8rules:- alert: CountGreaterThan8expr: ping_request_counter > 8for: 10s
重新启动 prometheus,查看 rules 如下即代表配置成功
尝试触发报警,不断尝试访问 /ping 接口,查看报警页面已经是 pending 状态
AlertManager 也收到了报警
查看配置的 web-hook 报警页面,可看到也收到了相关的报警信息
集群部署
参考:GitHub - prometheus-operator/kube-prometheus: Use Prometheus to monitor Kubernetes and applications running on Kubernetes
安装之前需要先确认集群的版本
➜ ~ k version
Client Version: version.Info{Major:"1", Minor:"23", GitVersion:"v1.23.8", GitCommit:"a12b886b1da059e0190c54d09c5eab5219dd7acf", GitTreeState:"clean", BuildDate:"2022-06-16T05:57:43Z", GoVersion:"go1.17.11", Compiler:"gc", Platform:"linux/amd64"}
Server Version: version.Info{Major:"1", Minor:"23", GitVersion:"v1.23.17", GitCommit:"953be8927218ec8067e1af2641e540238ffd7576", GitTreeState:"clean", BuildDate:"2023-02-22T13:27:46Z", GoVersion:"go1.19.6", Compiler:"gc", Platform:"linux/amd64"}
比如我安装的k8s的版本是1.23,需要下载 release-0.11 的版本
查看 monitoring 空间的 deployment,如果全部能够全部 Ready 即代表部署成功
➜ ~ k get deployments.apps -n monitoring
NAME READY UP-TO-DATE AVAILABLE AGE
blackbox-exporter 1/1 1 1 2m45s
grafana 1/1 1 1 2m44s
kube-state-metrics 1/1 1 1 2m44s
prometheus-adapter 2/2 2 2 2m44s
prometheus-operator 1/1 1 1 2m44s
部署完成之后我们将 prometheus-k8s 的 service 暴露到主机上的一个特定端口
➜ ~ k port-forward --address 0.0.0.0 service/prometheus-k8s 39090:9090 -n monitoring
Forwarding from 0.0.0.0:39090 -> 9090
直接访问对应的 39090 端口便能看到对应的 prometheus 的 UI 界面
同样我们查看暴露 Grafana 对应的 service 也能查看到具体的 web-UI 界面
➜ ~ k port-forward --address 0.0.0.0 service/grafana 33000:3000 -n monitoring
Forwarding from 0.0.0.0:33000 -> 3000
内置了很多的 Dashboard
我们查看一个具体的 kubelet 相关的监控看板
由于我 k8s 是部署的单个节点,所以只会有一个 kubelet 节点
查看总的pod的数量,确实只有24个,指标采集符合预期
参考资料
10分钟教你在k8s中部署Prometheus全家桶前言 K8s本身不包含内置的监控工具,所以市场上有不少这样监控工具来 - 掘金https://chronosphere.io/learn/an-introduction-to-the-four-primary-types-of-prometheus-metrics/
Prometheus - Monitoring system & time series database