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-exporter | 9100 | Linux 主机 |
| mysqld-exporter | 9104 | MySQL |
| redis-exporter | 9121 | Redis |
| kafka-exporter | 9308 | Kafka |
| nginx-exporter | 9113 | Nginx |
| blackbox-exporter | 9115 | HTTP/TCP/ICMP 探测 |
| postgres-exporter | 9187 | PostgreSQL |
应用自定义指标
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 + 告警规则。