Prometheus 作为一款开源的系统监控和报警工具,其核心在于其独特的数据模型和强大的指标监控能力。为了更好地利用 Prometheus,我们需要深入理解其数据模型的构成、数据的收集方式以及如何定义和使用指标监控。本指南将详细探讨 Prometheus 的数据模型、指标类型、数据收集机制和查询语言(PromQL),帮助你构建对 Prometheus 的全面理解。
Prometheus 的数据模型是基于时间序列的,每个时间序列都由一个 metric 名称和一组键值对(labels)唯一标识。时间序列的核心在于它记录了随时间变化的数据点,每个数据点包含时间戳和一个对应的值。Prometheus 的数据模型可以灵活应对各种监控需求,从简单的计数到复杂的聚合计算。
Prometheus 中的时间序列是指一组与时间相关的值。每个时间序列由以下部分组成:
http_requests_total
表示 HTTP 请求的总数。{method="GET", handler="/api"}
。Prometheus 支持四种主要的 metric 类型,每种类型适用于不同的监控场景:
Counter(计数器):只能递增的计数器,用于记录事件的累计次数,例如 HTTP 请求总数。计数器的值不会减少,除非系统重启或被明确重置。
示例:http_requests_total
,表示累计的 HTTP 请求次数。
Gauge(仪表):可以增减的指标,用于表示瞬时值,例如当前内存使用量或 CPU 利用率。仪表的值可以上下波动,适合用于监控资源使用情况。
示例:memory_usage_bytes
,表示当前内存使用量。
Histogram(直方图):用于测量事件的分布情况,例如请求延迟。直方图会将测量值分布在预先定义的桶(buckets)中,并记录每个桶内的事件数量。
示例:http_request_duration_seconds
,表示 HTTP 请求的响应时间分布。
Summary(摘要):类似于直方图,用于统计事件的分布情况和总数,同时提供分位数计算。与直方图不同,摘要是在客户端进行分位数计算,因此更加适合低延迟场景。
示例:rpc_duration_seconds
,表示 RPC 调用的持续时间分布。
Prometheus 通过 Pull 模式主动从监控目标中收集数据,这与很多传统监控系统的 Push 模式(即目标主动推送数据到监控系统)不同。Prometheus 定期轮询目标中的 /metrics
端点,从中获取时间序列数据。
Scrape 是 Prometheus 数据收集的核心机制。Prometheus 会周期性地从配置好的 targets(目标)中抓取数据。这些 targets 可以是物理服务器、虚拟机、容器、应用程序等,Prometheus 通过 HTTP 请求目标的 /metrics
端点来收集指标数据。
以下是一个典型的 scrape 配置示例:
scrape_configs:
- job_name: 'node_exporter'
scrape_interval: 15s
static_configs:
- targets: ['localhost:9100']
在上述配置中,Prometheus 每 15 秒抓取一次运行在 localhost:9100
的 node_exporter
的指标数据。
Exporters 是 Prometheus 的扩展组件,用于将非原生 Prometheus 兼容的服务、应用和系统的指标数据转化为 Prometheus 可识别的格式。常用的 exporters 包括:
Prometheus 支持多种服务发现方式,自动发现需要监控的目标,无需手动配置 targets。这对于动态环境(如 Kubernetes)尤为重要。Prometheus 支持的服务发现机制包括:
例如,在 Kubernetes 中,Prometheus 可以通过如下配置自动发现集群中的 Pod:
scrape_configs:
- job_name: 'kubernetes-pods'
kubernetes_sd_configs:
- role: pod
relabel_configs:
- source_labels: [__meta_kubernetes_pod_label_app]
action: keep
regex: my-app
此配置将自动发现并监控标签为 app=my-app
的所有 Pods。
Prometheus 强大的监控能力主要体现在它能够灵活定义和查询指标。理解如何定义、收集和查询指标是使用 Prometheus 进行监控的关键。
定义和导出指标通常是通过在应用程序中嵌入 Prometheus 客户端库实现的。Prometheus 提供了多种编程语言的客户端库,如 Go、Java、Python、Ruby 等。这些库用于在应用中定义指标(metrics),并通过 HTTP 端点暴露给 Prometheus。
以下是一个使用 Go 客户端库定义指标的示例:
package main
import (
"net/http"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
)
var (
httpRequestsTotal = prometheus.NewCounterVec(
prometheus.CounterOpts{
Name: "http_requests_total",
Help: "Total number of HTTP requests.",
},
[]string{"method", "endpoint"},
)
)
func init() {
prometheus.MustRegister(httpRequestsTotal)
}
func handler(w http.ResponseWriter, r *http.Request) {
httpRequestsTotal.WithLabelValues(r.Method, r.URL.Path).Inc()
w.Write([]byte("Hello, Prometheus!"))
}
func main() {
http.Handle("/metrics", promhttp.Handler())
http.HandleFunc("/", handler)
http.ListenAndServe(":8080", nil)
}
在上述代码中,我们定义了一个名为 http_requests_total
的计数器,用于记录 HTTP 请求的总数。通过 promhttp.Handler()
,我们将所有注册的指标暴露在 /metrics
端点上,供 Prometheus 抓取。
Prometheus 的查询语言 PromQL 是其监控能力的核心。通过 PromQL,可以灵活地对时间序列数据进行查询、过滤和聚合,以生成有意义的监控信息。
PromQL 具有强大的查询能力,以下是一些基础的语法和示例:
选择器:用于选择时间序列。选择特定指标名称和标签的序列,例如:
http_requests_total{method="GET", endpoint="/api"}
函数:用于对时间序列进行操作,例如 rate()
、avg()
、sum()
等。
rate(http_requests_total[5m])
该查询返回过去 5 分钟内 HTTP 请求的速率。
操作符:支持多种数学和逻辑操作符,如 +
, -
, *
, /
以及 and
, or
等。
sum(rate(http_requests_total[5m])) by (method)
该查询计算按 HTTP 方法分组的请求速率总和。