Prometheus 是由 SoundCloud 于 2012 年开源的监控告警系统,现已成为云原生计算基金会(CNCF)的毕业项目。它以时序数据库为核心,通过拉取(Pull)模式采集指标数据,提供强大的多维数据模型和灵活的查询语言 PromQL,广泛应用于微服务架构、容器化环境和云基础设施的监控场景。
| 特性 | 说明 |
|---|---|
| 多维数据模型 | 指标由名称和键值对标签唯一标识,支持灵活的查询和聚合 |
| 灵活的查询语言 | PromQL 支持实时查询、聚合、运算和告警规则定义 |
| 不依赖分布式存储 | 单个服务器节点自治,易于部署和运维 |
| HTTP 拉取模型 | 通过 HTTP 协议主动拉取指标,支持服务发现和静态配置 |
| 多种可视化方案 | 内置表达式浏览器,深度集成 Grafana 等可视化工具 |
| 高效存储 | 自定义的本地时序数据库,支持压缩和高效检索 |
| 告警管理 | 内置告警规则引擎,通过 Alertmanager 实现告警分组、抑制和路由 |
| 客户端库丰富 | 官方支持 Go、Java、Python、Ruby 等语言,社区覆盖更多语言 |
| Exporter 生态 | 丰富的第三方 Exporter,覆盖数据库、消息队列、硬件等场景 |
Prometheus 的核心数据模型是时序数据(Time Series),即按时间顺序记录的数据点序列。每个时序数据由以下三部分唯一标识:
http_requests_totalmethod="GET", path="/api/users"http_requests_total{method="GET", path="/api/users", status="200"} @1745731200000 1024
http_requests_total{method="POST", path="/api/users", status="201"} @1745731200000 256
样本是时序数据的基本单元,包含:
<--------------- 样本 ---------------->
时间戳: 1745731200.000 值: 1024.0
┌─────────────────────────────────────────────────────────────┐
│ Prometheus Server │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────┐ │
│ │ Retrieval │ │ TSDB │ │ HTTP Server │ │
│ │ (采集器) │ │ (时序数据库) │ │ (API/Web UI) │ │
│ └──────┬──────┘ └─────────────┘ └─────────────────────┘ │
│ │ │
│ ┌──────┴──────────────────────────────────────────────┐ │
│ │ PromQL Engine (查询引擎) │ │
│ └────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
│
▼ Pull (HTTP)
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ Jobs/Exporters │ │ Service │ │ Static │
│ (指标端点) │ │ Discovery │ │ Targets │
└─────────────────┘ └─────────────────┘ └─────────────────┘
│
▼ Push (可选)
┌─────────────────┐
│ Pushgateway │ ← 短期任务、批处理作业
└─────────────────┘
│
▼
┌─────────────────┐ ┌─────────────────┐
│ Alertmanager │───→│ Notification │
│ (告警管理) │ │ Channels │
└─────────────────┘ │ (Email/Slack/ │
│ PagerDuty/...) │
└─────────────────┘
Prometheus 的核心组件,负责数据采集、存储和查询:
用于在应用程序中埋点,暴露指标端点:
| 语言 | 库名称 | 引入方式 |
|---|---|---|
| Go | prometheus/client_golang | go get github.com/prometheus/client_golang |
| Java | prometheus/client_java | Maven/Gradle 依赖 |
| Python | prometheus_client | pip install prometheus_client |
| Ruby | prometheus/client_ruby | gem install prometheus-client |
| Node.js | prom-client | npm install prom-client |
用于将第三方系统的指标转换为 Prometheus 格式:
| Exporter | 用途 |
|---|---|
| node_exporter | Linux/Unix 系统指标(CPU、内存、磁盘、网络) |
| blackbox_exporter | 网络探测(HTTP、TCP、ICMP、DNS) |
| mysqld_exporter | MySQL 数据库指标 |
| redis_exporter | Redis 缓存指标 |
| kafka_exporter | Kafka 消息队列指标 |
| elasticsearch_exporter | Elasticsearch 集群指标 |
| nginx_exporter | Nginx 服务器指标 |
| jmx_exporter | JVM 应用指标(Java) |
用于接收短期任务或批处理作业的推送指标:
处理 Prometheus 发送的告警,实现告警的分组、抑制、静默和路由:
Prometheus 定义了四种核心指标类型,每种类型具有不同的数学语义和使用场景。
定义:单调递增的累计值,只能增加或在重启时归零。
适用场景:
数学特性:
rate() 或 increase() 函数计算每秒增长率使用示例:
# 计算每秒请求速率(过去5分钟平均值)
rate(http_requests_total[5m])
# 计算过去1小时内的请求增长量
increase(http_requests_total[1h])
# 计算错误率
rate(http_requests_total{status=~"5.."}[5m])
/
rate(http_requests_total[5m])
代码埋点(Go 示例):
import "github.com/prometheus/client_golang/prometheus"
var requestCounter = prometheus.NewCounterVec(
prometheus.CounterOpts{
Name: "http_requests_total",
Help: "Total number of HTTP requests",
},
[]string{"method", "path", "status"},
)
func handleRequest(w http.ResponseWriter, r *http.Request) {
requestCounter.WithLabelValues(r.Method, r.URL.Path, "200").Inc()
}
定义:可增可减的瞬时值,反映系统的当前状态。
适用场景:
数学特性:
使用示例:
# 查看当前内存使用率
memory_usage_bytes / memory_limit_bytes * 100
# 查看过去5分钟内的最大连接数
max_over_time(connections_active[5m])
# 查看集群平均 CPU 使用率
avg(cpu_usage_percent) by (cluster)
代码埋点(Python 示例):
from prometheus_client import Gauge
memory_gauge = Gauge('memory_usage_bytes', 'Current memory usage', ['pod'])
def update_memory():
usage = get_current_memory()
memory_gauge.labels(pod=os.environ['POD_NAME']).set(usage)
定义:对样本进行分桶(Bucket)统计,记录每个桶的累计计数,同时提供样本总和和总数。
数据结构:
<basename>_bucket{le="<upper_bound>"}:每个桶的累计计数(小于等于上界)<basename>_sum:所有样本值的总和<basename>_count:样本总数适用场景:
默认桶配置:
.005, .01, .025, .05, .1, .25, .5, 1, 2.5, 5, 10
使用示例:
# 计算 95 分位延迟(近似值)
histogram_quantile(0.95,
rate(http_request_duration_seconds_bucket[5m])
)
# 计算延迟小于 100ms 的请求比例
rate(http_request_duration_seconds_bucket{le="0.1"}[5m])
/
rate(http_request_duration_seconds_count[5m])
# 计算平均延迟
rate(http_request_duration_seconds_sum[5m])
/
rate(http_request_duration_seconds_count[5m])
代码埋点(Java 示例):
import io.prometheus.client.Histogram;
static final Histogram requestLatency = Histogram.build()
.name("http_request_duration_seconds")
.help("Request latency in seconds")
.buckets(0.01, 0.05, 0.1, 0.5, 1.0, 5.0)
.register();
public void handleRequest() {
Histogram.Timer timer = requestLatency.startTimer();
try {
processRequest();
} finally {
timer.observeDuration();
}
}
定义:类似于直方图,但在客户端计算分位数,只上传分位结果。
数据结构:
<basename>{quantile="0.5"}:中位数<basename>{quantile="0.9"}:90 分位<basename>{quantile="0.99"}:99 分位<basename>_sum:样本总和<basename>_count:样本总数与直方图的区别:
| 特性 | Histogram | Summary |
|---|---|---|
| 分位计算位置 | 服务端(PromQL) | 客户端 |
| 聚合能力 | 可跨实例聚合 | 不可跨实例聚合 |
| 精度 | 受桶边界限制 | 客户端精确计算 |
| 灵活性 | 可调整分位和时间段 | 客户端固定配置 |
| 适用场景 | 多实例聚合、动态分位 | 单实例精确分位 |
使用示例:
# 查看 99 分位延迟(客户端预计算)
http_request_duration_seconds{quantile="0.99"}
# 计算平均延迟
rate(http_request_duration_seconds_sum[5m])
/
rate(http_request_duration_seconds_count[5m])
代码埋点(Go 示例):
var requestDuration = prometheus.NewSummaryVec(
prometheus.SummaryOpts{
Name: "http_request_duration_seconds",
Help: "Request latency in seconds",
Objectives: map[float64]float64{
0.5: 0.05, // 中位数,误差 5%
0.9: 0.01, // 90 分位,误差 1%
0.99: 0.001, // 99 分位,误差 0.1%
},
},
[]string{"method", "path"},
)
PromQL(Prometheus Query Language)是 Prometheus 的专属查询语言,用于实时查询、聚合和分析时序数据。
| 类型 | 说明 | 示例 |
|---|---|---|
| Instant Vector | 单个时间点的样本集合 | http_requests_total |
| Range Vector | 一段时间内的样本集合 | http_requests_total[5m] |
| Scalar | 单个浮点数值 | 42.0 |
| String | 字符串(仅用于注释) | "hello" |
# 选择所有 http_requests_total 指标
http_requests_total
# 按标签过滤
http_requests_total{method="GET", status="200"}
# 正则匹配
http_requests_total{status=~"2.."} # 2xx 状态码
http_requests_total{status!~"4..|5.."} # 排除 4xx 和 5xx
# 范围向量选择器(过去5分钟)
http_requests_total[5m]
http_requests_total[1h:5m] # 1小时内的数据,每5分钟一个点
# 计算内存使用率百分比
memory_usage_bytes / memory_limit_bytes * 100
# 计算每核 CPU 使用率
cpu_usage_seconds_total / count(cpu_usage_seconds_total)
# 筛选使用率超过 80% 的实例
memory_usage_bytes / memory_limit_bytes * 100 > 80
# 筛选非 200 状态码的请求
http_requests_total{status!="200"}
# 按方法聚合请求总数
sum(http_requests_total) by (method)
# 计算每个实例的平均延迟
avg(http_request_duration_seconds) by (instance)
# 查看最大延迟
max(http_request_duration_seconds) by (service)
# 计算分位数
quantile(0.95, http_request_duration_seconds)
# 统计唯一值数量
count(count(http_requests_total) by (path))
# 计算每秒增长率(用于 Counter)
rate(http_requests_total[5m])
# 计算过去一段时间的总增长量
increase(http_requests_total[1h])
# 计算导数(用于 Gauge)
derivative(temperature_celsius[10m])
# 预测4小时后磁盘是否满
predict_linear(disk_free_bytes[1h], 4 * 3600) < 0
# 查询1小时前的数据
http_requests_total offset 1h
# 同比昨天同一时间
count_over_time(http_requests_total[1h])
/
count_over_time(http_requests_total[1h] offset 24h)
# 计算 95 分位延迟
histogram_quantile(0.95,
rate(http_request_duration_seconds_bucket[5m])
)
# 计算各服务的 99 分位延迟
histogram_quantile(0.99,
sum(rate(http_request_duration_seconds_bucket[5m])) by (service, le)
)
# 计算一段时间内的最大值
max_over_time(cpu_usage[1h])
# 计算一段时间内的平均值
avg_over_time(memory_usage[30m])
# 去除数值,保留标签
count(http_requests_total) by (instance)
# 排序(仅用于图表)
topk(10, http_requests_total)
bottomk(5, http_requests_total)
Prometheus 通过 YAML 配置文件定义采集目标、规则、告警等:
global:
scrape_interval: 15s # 默认采集间隔
evaluation_interval: 15s # 规则评估间隔
external_labels:
cluster: 'production'
replica: 'prometheus-1'
# 采集目标配置
scrape_configs:
- job_name: 'prometheus'
static_configs:
- targets: ['localhost:9090']
- job_name: 'node-exporter'
static_configs:
- targets: ['node-1:9100', 'node-2:9100']
metrics_path: '/metrics'
scrape_interval: 10s
- job_name: 'kubernetes-pods'
kubernetes_sd_configs:
- role: pod
relabel_configs:
- source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scrape]
action: keep
regex: true
# 告警规则文件
rule_files:
- '/etc/prometheus/rules/*.yml'
# Alertmanager 配置
alerting:
alertmanagers:
- static_configs:
- targets: ['alertmanager:9093']
Prometheus 支持多种服务发现机制,自动发现采集目标:
| 类型 | 用途 |
|---|---|
| static_configs | 静态配置目标列表 |
| file_sd_configs | 从文件动态加载目标列表 |
| kubernetes_sd_configs | 自动发现 K8s Pod、Service、Node |
| consul_sd_configs | 从 Consul 服务注册中心发现 |
| dns_sd_configs | 通过 DNS 记录发现 |
| ec2_sd_configs | 自动发现 AWS EC2 实例 |
| gce_sd_configs | 自动发现 GCP 实例 |
Prometheus 通过 HTTP GET 请求拉取指标,端点需返回纯文本格式:
# HELP http_requests_total Total number of HTTP requests
# TYPE http_requests_total counter
http_requests_total{method="GET",path="/api/users",status="200"} 1024
http_requests_total{method="POST",path="/api/users",status="201"} 256
# HELP http_request_duration_seconds HTTP request latency
# TYPE http_request_duration_seconds histogram
http_request_duration_seconds_bucket{le="0.1"} 500
http_request_duration_seconds_bucket{le="0.5"} 900
http_request_duration_seconds_bucket{le="1.0"} 950
http_request_duration_seconds_bucket{le="+Inf"} 1000
http_request_duration_seconds_sum 450.0
http_request_duration_seconds_count 1000
Relabeling 是在采集前修改目标标签的强大机制:
relabel_configs:
# 丢弃特定标签的指标
- source_labels: [__name__]
regex: 'go_.*'
action: drop
# 替换标签值
- source_labels: [__address__]
regex: '(.*):.*'
target_label: 'instance'
replacement: '${1}'
# 保留特定目标
- source_labels: [env]
regex: 'production'
action: keep
告警规则定义在 YAML 文件中,由 Prometheus 定期评估:
groups:
- name: service_alerts
interval: 30s
rules:
# 高错误率告警
- alert: HighErrorRate
expr: |
sum(rate(http_requests_total{status=~"5.."}[5m]))
/
sum(rate(http_requests_total[5m])) > 0.05
for: 2m
labels:
severity: critical
team: backend
annotations:
summary: "High error rate on {{ $labels.service }}"
description: "Error rate is {{ $value | humanizePercentage }} for the last 2 minutes"
# 高延迟告警
- alert: HighLatency
expr: |
histogram_quantile(0.95,
sum(rate(http_request_duration_seconds_bucket[5m])) by (le, service)
) > 0.5
for: 5m
labels:
severity: warning
annotations:
summary: "P95 latency exceeds 500ms"
# 磁盘空间不足
- alert: DiskSpaceLow
expr: |
(node_filesystem_avail_bytes / node_filesystem_size_bytes) < 0.1
for: 1m
labels:
severity: critical
annotations:
summary: "Disk space low on {{ $labels.instance }}"
description: "Only {{ $value | humanizePercentage }} disk space remaining"
| 变量 | 说明 |
|---|---|
{{ $labels.<name> }} |
告警指标的标签值 |
{{ $value }} |
告警表达式的计算结果 |
{{ $externalLabels.<name> }} |
全局外部标签 |
Alertmanager 处理告警的路由、分组和通知:
global:
smtp_smarthost: 'smtp.example.com:587'
smtp_from: 'alert@example.com'
slack_api_url: 'https://hooks.slack.com/services/xxx'
# 路由树
templates:
- '/etc/alertmanager/templates/*.tmpl'
route:
group_by: ['alertname', 'cluster', 'service']
group_wait: 30s
group_interval: 5m
repeat_interval: 4h
receiver: 'default'
routes:
- match:
severity: critical
receiver: 'pagerduty-critical'
continue: true
- match:
team: backend
receiver: 'slack-backend'
# 抑制规则
inhibit_rules:
- source_match:
severity: 'critical'
target_match:
severity: 'warning'
equal: ['alertname', 'cluster']
# 接收器
receivers:
- name: 'default'
email_configs:
- to: 'oncall@example.com'
- name: 'slack-backend'
slack_configs:
- channel: '#backend-alerts'
send_resolved: true
title: '{{ .GroupLabels.alertname }}'
text: '{{ range .Alerts }}{{ .Annotations.summary }}{{ end }}'
- name: 'pagerduty-critical'
pagerduty_configs:
- service_key: '<pagerduty-key>'
severity: critical
http://prometheus:9090# 获取所有应用名称
label_values(application)
# 获取特定应用的 Pod 列表
label_values(jvm_memory_used_bytes{application="$application"}, pod)
# 获取所有命名空间
label_values(namespace)
# 获取所有实例
label_values(instance)
| 用途 | 社区模板 ID |
|---|---|
| Node Exporter 全量 | 1860 |
| JVM 监控 | 4701 |
| MySQL 监控 | 7362 |
| Redis 监控 | 763 |
| Kubernetes 集群 | 315 |
| Docker 容器 | 893 |
| Spring Boot | 10280 |
问题描述:标签值域过大导致时序数量爆炸,是 Prometheus 最常见的性能问题。
示例:
# 危险:user_id 可能有数百万个值
trading_volume_accumulated{currency="CNY", user_id="12345"}
# 200 种货币 × 10000 用户 = 200 万时序/秒
解决方案:
| 策略 | 说明 |
|---|---|
| 避免高 Cardinality 标签 | 不在标签中使用用户 ID、订单 ID 等唯一值 |
| 使用 Recording Rules | 预聚合高频查询,降低查询负载 |
| 标签值规范化 | 将连续值分桶,如将延迟分为 "fast", "normal", "slow" |
| 分片采集 | 使用联邦集群或 Thanos 分散存储压力 |
| 限制样本数量 | 通过 sample_limit 限制单个目标的样本数 |
| 指标 | 单节点建议上限 |
|---|---|
| 活跃时序数 | 100 万 - 300 万 |
| 每秒样本数 | 100 万 |
| 数据保留期 | 15 天(本地存储) |
| 内存使用 | 约 3KB / 活跃时序 |
| 方案 | 特点 |
|---|---|
| Thanos | 最流行的 Prometheus 长期存储方案,支持全局查询视图 |
| Cortex | 多租户、水平可扩展的 Prometheus 即服务 |
| VictoriaMetrics | 高性能、低资源占用,兼容 PromQL |
| Mimir | Grafana Labs 推出的 Cortex 继任者 |
| Remote Write | 直接写入 InfluxDB、Elasticsearch 等后端 |
Recording Rules 用于预计算高频查询,提升查询性能:
groups:
- name: recording_rules
interval: 30s
rules:
# 预计算请求速率
- record: job:http_requests_rate:sum
expr: sum(rate(http_requests_total[5m])) by (job)
# 预计算错误率
- record: job:http_error_rate:ratio
expr: |
sum(rate(http_requests_total{status=~"5.."}[5m])) by (job)
/
sum(rate(http_requests_total[5m])) by (job)
# 预计算 P95 延迟
- record: job:http_latency:p95
expr: |
histogram_quantile(0.95,
sum(rate(http_request_duration_seconds_bucket[5m])) by (job, le)
)
http_requests_totalstatus 而非 is_error_seconds、_bytes、_total# 正确
http_requests_total
process_cpu_seconds_total
node_memory_MemAvailable_bytes
# 错误
httpRequestsTotal # 应使用 snake_case
cpu # 缺少单位和上下文
request_count # Counter 应使用 _total 后缀
| 问题 | 原因 | 解决方案 |
|---|---|---|
| 内存溢出 | 高 Cardinality 导致时序爆炸 | 优化标签设计,限制样本数 |
| 查询缓慢 | 大量原始数据扫描 | 使用 Recording Rules 预聚合 |
| 数据丢失 | 目标不可达或采集超时 | 增加超时时间,检查网络 |
| 告警风暴 | 未配置告警分组 | 在 Alertmanager 中配置 group_by |
| 磁盘满 | 数据保留期过长 | 缩短 retention_time,使用远程存储 |
Prometheus 专注于指标监控,与日志、链路追踪形成可观测性三大支柱:
| 类型 | 数据特征 | 工具示例 |
|---|---|---|
| Metrics(指标) | 聚合的数值,适合趋势分析 | Prometheus、Grafana |
| Logs(日志) | 离散事件,适合详情排查 | ELK、Loki |
| Traces(链路) | 请求路径,适合性能分析 | Jaeger、Zipkin |
集成方案:
# CPU 使用率
100 - (avg by (instance) (irate(node_cpu_seconds_total{mode="idle"}[5m])) * 100)
# 内存使用率
(node_memory_MemTotal_bytes - node_memory_MemAvailable_bytes)
/ node_memory_MemTotal_bytes * 100
# 磁盘使用率
(node_filesystem_size_bytes - node_filesystem_avail_bytes)
/ node_filesystem_size_bytes * 100
# 网络流量
rate(node_network_receive_bytes_total[5m])
rate(node_network_transmit_bytes_total[5m])
# QPS(每秒查询数)
sum(rate(http_requests_total[5m])) by (service)
# 错误率
sum(rate(http_requests_total{status=~"5.."}[5m])) by (service)
/
sum(rate(http_requests_total[5m])) by (service)
# P99 延迟
histogram_quantile(0.99,
sum(rate(http_request_duration_seconds_bucket[5m])) by (service, le)
)
# 活跃连接数
count(increase(http_requests_total[5m]) > 0) by (service)
# 每分钟订单量
sum(rate(orders_created_total[1m])) by (region)
# 支付成功率
sum(rate(payments_completed_total[5m]))
/
sum(rate(payments_initiated_total[5m]))
# 用户活跃度(DAU 估算)
count(count_over_time(user_actions_total[24h]) > 0) by (user_id)
# Pod CPU 使用率
rate(container_cpu_usage_seconds_total[5m])
# Pod 内存使用率
container_memory_working_set_bytes / container_spec_memory_limit_bytes
# Pod 重启次数
increase(kube_pod_container_status_restarts_total[1h])
# 节点资源压力
kube_node_status_condition{condition="MemoryPressure",status="true"}
Prometheus 作为云原生时代的监控标准,以其多维数据模型、强大的查询语言和活跃的生态系统,成为现代基础设施和应用监控的首选方案。掌握 Prometheus 的核心概念、指标类型、PromQL 查询和最佳实践,能够有效构建全面的可观测性体系,及时发现和定位系统问题。