3、Prometheus入门:架构、数据模型、指标类型(Counter、Gauge、Histogram、Summary)、Pull模型
Prometheus 是云原生可观测性领域的基石系统,其设计哲学与传统的“推模型”监控系统(如 Zabbix、Nagios)截然不同。理解 Prometheus 的架构、数据模型与指标类型,是构建可靠监控体系的前提。本章将从核心组件入手,剖析其 Pull 模型的优势,并通过实战案例演示如何设计高效的指标采集任务。
上图展示了 Prometheus 的核心架构。与直觉相反,Prometheus 并不主动接收数据,而是通过 HTTP 周期性拉取(Pull)暴露了 /metrics 端点的目标。这种设计使得监控系统的健康状态不依赖于被监控对象的推送能力,且便于在本地进行故障诊断。接下来,我们将深入拆解其数据模型与四种核心指标类型。
3.1 核心原理:Pull 模型与组件协作
Prometheus 的 Pull 模型是其架构的灵魂。Prometheus Server 根据配置的 scrape_configs,定期(默认 15s)向目标地址发起 HTTP GET 请求,路径通常为 /metrics。目标端返回的文本格式数据会被解析并存储至内置的 TSDB(时间序列数据库)。
该模型带来三个关键优势:
- 健康检查简单:只要 Prometheus 能成功拉取,说明目标进程存活且 HTTP 服务正常;拉取失败则立即触发告警。
- 易于本地调试:使用
curl http://localhost:9100/metrics即可查看原始指标,无需额外工具。 - 避免推送风暴:在微服务规模较大时,推送模型容易因网络抖动导致数据堆积,而 Pull 模型由服务端控制节奏。
组件协作流程如下:服务发现(如 Kubernetes SD)动态维护待拉取的目标列表;Prometheus Server 的 Retrieval 模块根据该列表执行拉取;拉取到的样本经过有效性校验后写入 TSDB;PromQL 引擎负责查询与聚合;Alerting 模块基于规则生成告警并推送至 Alertmanager。
3.2 数据模型:时间序列与标签
Prometheus 的数据模型可以概括为:时间序列 = 指标名 + 标签集合 + 时间戳样本值。每个唯一组合(指标名+标签键值对)定义了一条时间序列。
| 组成部分 | 示例 | 说明 |
|---|---|---|
| 指标名 | http_requests_total |
必须符合 [a-zA-Z_:][a-zA-Z0-9_:]*,通常包含单位(_total、_seconds) |
| 标签 | method="GET", code="200" |
用于维度过滤与聚合,是 PromQL 查询的核心 |
| 样本 | timestamp value |
毫秒级时间戳 + float64 数值 |
标签设计是监控建模的关键。例如,http_requests_total{method="POST", code="500"} 与 http_requests_total{method="GET", code="200"} 是两条不同的序列。高基数标签(如用户 ID、请求 URL)会导致序列数量爆炸,必须避免。
3.3 指标类型:Counter、Gauge、Histogram、Summary
Prometheus 客户端库提供四种核心指标类型,每种类型服务于不同的观测场景。
3.3.1 Counter(计数器)
Counter 只增不减(除非系统重启)。它适用于累计型指标,如请求总数、错误次数、任务完成数。在 PromQL 中,通常使用 rate() 或 increase() 函数计算每秒速率或增量。
# 定义示例
http_requests_total{method="GET", code="200"} 1027
# 查询每秒速率
rate(http_requests_total[5m])
3.3.2 Gauge(仪表盘)
Gauge 表示可增可减的瞬时值,如当前内存使用量、CPU 温度、在线用户数。它直接反映当前状态,无需额外计算。
# 当前内存使用字节数
node_memory_MemAvailable_bytes 838860800
3.3.3 Histogram(直方图)
Histogram 用于观测值的分布情况,例如请求延迟或响应体大小。它通过 累积桶(cumulative bucket) 记录样本落在每个桶中的计数,同时提供总和与总计数。
# HELP http_request_duration_seconds 请求延迟
# TYPE http_request_duration_seconds histogram
http_request_duration_seconds_bucket{le="0.1"} 120
http_request_duration_seconds_bucket{le="0.5"} 450
http_request_duration_seconds_bucket{le="1"} 700
http_request_duration_seconds_bucket{le="+Inf"} 800
http_request_duration_seconds_sum 320.5
http_request_duration_seconds_count 800
通过 histogram_quantile() 函数可以计算分位数(如 P99),但需注意桶边界的选择会影响精度。
3.3.4 Summary(摘要)
Summary 在客户端直接计算分位数(如 0.5、0.9、0.99),并暴露为独立的指标。它不依赖服务端计算,但无法跨实例聚合。
# TYPE http_request_duration_seconds summary
http_request_duration_seconds{quantile="0.5"} 0.23
http_request_duration_seconds{quantile="0.9"} 0.87
http_request_duration_seconds_sum 320.5
http_request_duration_seconds_count 800
| 类型 | 适用场景 | 聚合能力 | 分位数计算 |
|---|---|---|---|
| Counter | 累计计数(请求数、错误数) | 支持 Sum | 不适用 |
| Gauge | 瞬时值(温度、内存) | 支持 Avg/Max/Min | 不适用 |
| Histogram | 延迟、大小分布 | 支持 Sum/Count | 服务端计算(近似) |
| Summary | 延迟分布(客户端预计算) | 不支持跨实例聚合 | 客户端计算(精确) |
3.4 案例拆解:为订单服务设计监控指标
假设我们有一个订单服务,需要监控其健康状态与性能。以下是具体的实施过程。
背景与目标:该服务部署在 Kubernetes 集群中,日订单量约 50 万。我们需要回答三个问题:QPS 是多少?P99 延迟是否达标?错误率是否上升?
关键输入数据:服务使用 Go 语言编写,已集成 Prometheus 客户端库。
操作步骤:
- 定义指标:在代码中创建 Counter 与 Histogram。
var (
ordersTotal = prometheus.NewCounterVec(
prometheus.CounterOpts{
Name: "orders_created_total",
Help: "Total number of created orders.",
},
[]string{"status"}, // status: "success", "failed"
)
orderDuration = prometheus.NewHistogramVec(
prometheus.HistogramOpts{
Name: "order_create_duration_seconds",
Help: "Time taken to create an order.",
Buckets: prometheus.DefBuckets, // 默认桶
},
[]string{},
)
)
- 埋点:在创建订单的函数中记录耗时与结果。
start := time.Now()
err := createOrder()
duration := time.Since(start).Seconds()
orderDuration.WithLabelValues().Observe(duration)
if err != nil {
ordersTotal.WithLabelValues("failed").Inc()
} else {
ordersTotal.WithLabelValues("success").Inc()
}
- 配置抓取:在 Prometheus 配置中增加 Job。
scrape_configs:
- job_name: 'order-service'
kubernetes_sd_configs:
- role: pod
relabel_configs:
- source_labels: [__meta_kubernetes_pod_label_app]
regex: 'order-service'
action: keep
metrics_path: /metrics
scrape_interval: 15s
- 验证与查询:在 Grafana 中创建面板,使用 PromQL 查询。
# QPS
sum(rate(orders_created_total[5m]))
# P99 延迟
histogram_quantile(0.99, sum(rate(order_create_duration_seconds_bucket[5m])) by (le))
# 错误率
sum(rate(orders_created_total{status="failed"}[5m])) / sum(rate(orders_created_total[5m]))
结果对比:监控上线后,发现 P99 延迟在高峰期从 0.8s 飙升至 2.1s。通过 Histogram 桶分布定位到是数据库连接池瓶颈,而非代码逻辑问题。优化连接池配置后,P99 降至 0.6s。
status 作为标签,避免了高基数问题。
3.5 常见误区与总结复盘
在实际使用中,以下误区需要特别留意:
- Counter 误用 Gauge 函数:对 Counter 使用
avg()没有意义,应使用rate()或increase()。 - Histogram 桶边界设置不当:桶过少导致分位数误差大;桶过多增加开销。建议根据业务经验设置,如延迟指标可设为
[0.01, 0.05, 0.1, 0.5, 1, 2.5, 5]。 - 忽略标签一致性:同一指标在不同实例上标签不一致会导致查询结果异常。例如,一个实例有
code="200",另一个实例没有该标签,则sum()会出错。 - Summary 跨实例聚合:Summary 的分位数在客户端计算,不能直接相加。若需要全局分位数,应使用 Histogram。