跳到主要内容

Prometheus

架构

核心特点

  • Pull 模式:Prometheus 主动抓取 Target 的 /metrics 端点
  • 时序数据库(TSDB):高效存储时间序列数据
  • PromQL:强大的查询语言
  • 服务发现:自动发现监控目标(K8s / Consul / DNS)

数据模型

# 指标格式:metric_name{label1="value1", label2="value2"} value timestamp
http_requests_total{method="GET", status="200", path="/api"} 1234 1625000000
node_cpu_seconds_total{cpu="0", mode="idle"} 56789.12

四种指标类型

类型说明示例
Counter只增不减的计数器http_requests_total
Gauge可增可减的仪表盘node_memory_free_bytes
Histogram直方图(分桶统计)http_request_duration_seconds_bucket
Summary摘要(分位数)http_request_duration_seconds{quantile="0.99"}

配置

prometheus.yml
global:
scrape_interval: 15s # 全局抓取间隔
evaluation_interval: 15s # 规则评估间隔

# 告警规则文件
rule_files:
- "rules/*.yml"

# Alertmanager 配置
alerting:
alertmanagers:
- static_configs:
- targets: ['alertmanager:9093']

# 抓取配置
scrape_configs:
# Prometheus 自身
- job_name: 'prometheus'
static_configs:
- targets: ['localhost:9090']

# Node Exporter
- job_name: 'node'
static_configs:
- targets: ['node1:9100', 'node2:9100']

# K8s Pod 自动发现
- job_name: 'kubernetes-pods'
kubernetes_sd_configs:
- role: pod
relabel_configs:
# 只抓取有 prometheus.io/scrape: "true" 注解的 Pod
- source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scrape]
action: keep
regex: true
- source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_path]
action: replace
target_label: __metrics_path__
regex: (.+)

PromQL 常用查询

基础查询

# 瞬时向量:最新值
node_cpu_seconds_total{mode="idle"}

# 范围向量:一段时间内的所有值
node_cpu_seconds_total{mode="idle"}[5m]

# 标签匹配
http_requests_total{method=~"GET|POST"} # 正则匹配
http_requests_total{status!="200"} # 不等于

常用函数

# ===== CPU 使用率 =====
100 - avg by(instance)(rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100

# ===== 内存使用率 =====
(1 - node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes) * 100

# ===== 磁盘使用率 =====
(1 - node_filesystem_avail_bytes{fstype!~"tmpfs|fuse.*"} / node_filesystem_size_bytes) * 100

# ===== QPS(请求速率)=====
rate(http_requests_total[5m]) # 每秒请求数
sum(rate(http_requests_total[5m])) by (method, status) # 按方法和状态码分组

# ===== 错误率 =====
sum(rate(http_requests_total{status=~"5.."}[5m])) / sum(rate(http_requests_total[5m]))

# ===== P99 延迟 =====
histogram_quantile(0.99, rate(http_request_duration_seconds_bucket[5m]))

# ===== Top 5 内存使用 Pod =====
topk(5, container_memory_working_set_bytes{namespace="production"})

# ===== 预测磁盘 4 小时后是否满 =====
predict_linear(node_filesystem_avail_bytes[1h], 4*3600) < 0
rate vs irate
  • rate():5 分钟的平均增长率,曲线更平滑,适合告警
  • irate():最近两个点的瞬时增长率,适合看实时变化

常用 Exporter

Exporter端口监控对象
node-exporter9100Linux 主机
mysqld-exporter9104MySQL
redis-exporter9121Redis
kafka-exporter9308Kafka
nginx-exporter9113Nginx
blackbox-exporter9115HTTP/TCP/ICMP 探测
postgres-exporter9187PostgreSQL

应用自定义指标

Python 应用(prometheus_client)
from prometheus_client import Counter, Histogram, start_http_server

# 定义指标
REQUEST_COUNT = Counter(
'http_requests_total', '请求总数',
['method', 'endpoint', 'status']
)
REQUEST_LATENCY = Histogram(
'http_request_duration_seconds', '请求延迟',
['method', 'endpoint'],
buckets=[0.01, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0]
)

# 记录指标
@REQUEST_LATENCY.labels(method='GET', endpoint='/api/users').time()
def get_users():
REQUEST_COUNT.labels(method='GET', endpoint='/api/users', status='200').inc()
# ... 业务逻辑

# 暴露 /metrics 端口
start_http_server(8080)

告警规则

rules/alerts.yml
groups:
- name: host-alerts
rules:
# 主机下线
- alert: HostDown
expr: up == 0
for: 2m
labels:
severity: critical
annotations:
summary: "{{ $labels.instance }} 不可达"

# CPU 使用率过高
- alert: HostHighCPU
expr: 100 - avg by(instance)(rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100 > 85
for: 10m
labels:
severity: warning
annotations:
summary: "{{ $labels.instance }} CPU {{ $value | printf \"%.1f\" }}%"

# 磁盘预测 4 小时内将满
- alert: DiskWillFull
expr: predict_linear(node_filesystem_avail_bytes{fstype!~"tmpfs"}[1h], 4*3600) < 0
for: 15m
labels:
severity: warning
annotations:
summary: "{{ $labels.instance }} 磁盘预计 4 小时内满"

常见面试问题

Q1: Prometheus 为什么不适合长期存储?

答案

Prometheus 本地 TSDB 设计上优化了近期数据的读写性能,但:

  • 单机存储,磁盘容量有限
  • 不支持高可用(单点故障)
  • 长时间范围查询性能下降

解决方案:使用远程存储方案:

  • Thanos:基于对象存储(S3),全局查询
  • Mimir (Grafana):高性能多租户存储
  • VictoriaMetrics:高压缩率,兼容 PromQL

Q2: rate() 和 irate() 的区别?

答案

  • rate(metric[5m]):5 分钟内所有数据点的平均增长率,适合告警规则
  • irate(metric[5m]):最近两个数据点的瞬时增长率,适合实时看板

rate() 更平滑,不会因偶尔的突刺误报;irate() 更灵敏,能反映瞬时变化。

Q3: 如何监控应用的 RED 指标?

答案

RED = Rate / Errors / Duration:

# Rate(请求速率)
sum(rate(http_requests_total[5m]))

# Errors(错误率)
sum(rate(http_requests_total{status=~"5.."}[5m])) / sum(rate(http_requests_total[5m]))

# Duration(延迟分布)
histogram_quantile(0.99, rate(http_request_duration_seconds_bucket[5m]))

应用需要暴露这些指标(使用 Prometheus client library),然后配置 Grafana Dashboard + 告警规则。

相关链接