Prometheus —— 指标采集与时序查询
Prometheus —— 指标采集与时序查询
分类:09 日志与监控 适用:Prometheus 2.x(2.40 ~ 2.55) 一句话:拉模式采集指标 + PromQL 查询 + 规则告警,云原生监控的事实标准。
1. 它解决什么问题
- 需要看到"过去 7 天 CPU 趋势"而不是当前一个点。
- 用统一方式采集几百个 target 的指标。
- 按标签多维聚合(按实例、按接口、按状态码)。
- 基于指标配告警(错误率 > 1% 持续 5 分钟)。
不适合:日志检索(用 Loki/ELK)、链路追踪(用 Jaeger/Tempo)、精确计费(时序会降采样)。
2. 架构与组件
应用 /exporters ←──scrape── Prometheus ──alert──→ Alertmanager ──→ 邮件/企微
│
└──query──→ Grafana
- Pull 模型:Prometheus 主动抓
/metrics。 - Exporter:把系统/中间件指标翻译成 Prometheus 格式。
- Alertmanager:去重、分组、静默、路由。
3. 安装与启动
# 二进制
curl -LO https://github.com/prometheus/prometheus/releases/download/v2.55.0/prometheus-2.55.0.linux-amd64.tar.gz
tar xf prometheus-*.tar.gz && cd prometheus-*
./prometheus --config.file=prometheus.yml \
--storage.tsdb.path=/data/prometheus \
--storage.tsdb.retention.time=30d \
--web.enable-lifecycle
# systemd 管理
systemctl enable --now prometheus
systemctl reload prometheus # 需要 --web.enable-lifecycle
Docker:
docker run -d --name prom -p 9090:9090 \
-v $PWD/prometheus.yml:/etc/prometheus/prometheus.yml \
-v /data/prom:/prometheus \
prom/prometheus --config.file=/etc/prometheus/prometheus.yml \
--storage.tsdb.retention.time=30d
4. 核心配置
global:
scrape_interval: 15s
evaluation_interval: 15s
external_labels:
cluster: prod
region: cn-hangzhou
rule_files:
- /etc/prometheus/rules/*.yml
alerting:
alertmanagers:
- static_configs:
- targets: ['localhost:9093']
scrape_configs:
- job_name: prometheus
static_configs:
- targets: ['localhost:9090']
- job_name: node
static_configs:
- targets: ['10.0.0.11:9100', '10.0.0.12:9100']
labels:
env: prod
- job_name: mysql
static_configs:
- targets: ['10.0.0.21:9104']
# 文件服务发现(配置变更不用重启)
- job_name: file-sd
file_sd_configs:
- files: ['/etc/prometheus/targets/*.json']
refresh_interval: 30s
# Kubernetes 服务发现
- job_name: kubernetes-pods
kubernetes_sd_configs:
- role: pod
relabel_configs:
- source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scrape]
action: keep
regex: "true"
校验:
promtool check config /etc/prometheus/prometheus.yml
promtool check rules /etc/prometheus/rules/*.yml
5. 指标类型
| 类型 | 特点 | 例子 |
|---|---|---|
| Counter | 只增不减,重启归零 | http_requests_total |
| Gauge | 可增可减 | node_memory_MemAvailable_bytes |
| Histogram | 分桶统计,可算分位数 | http_request_duration_seconds_bucket |
| Summary | 客户端算分位 | rpc_duration_seconds{quantile="0.99"} |
命名规范:<namespace>_<subsystem>_<name>_<unit>,Counter 以 _total 结尾。
6. PromQL 必备
# 瞬时值
node_load1
up{job="node"}
# 过滤
http_requests_total{job="api", status="500"}
http_requests_total{status=~"5.."} # 正则
http_requests_total{status!="200"} # 取反
# 速率(Counter 专用,窗口至少 4 个采样点)
rate(http_requests_total[5m])
irate(http_requests_total[5m]) # 瞬时速率,抖动大
# 增量
increase(http_requests_total[1h])
# 聚合
sum(rate(http_requests_total[5m]))
sum by (instance) (rate(http_requests_total[5m]))
sum by (status) (rate(http_requests_total{job="api"}[5m]))
avg without (cpu) (node_cpu_seconds_total)
# 分位数(Histogram)
histogram_quantile(0.99,
sum by (le) (rate(http_request_duration_seconds_bucket[5m])))
# TOP N
topk(5, sum by (instance) (rate(http_requests_total[5m])))
# 变化率、预测
deriv(node_filesystem_avail_bytes[1h])
predict_linear(node_filesystem_avail_bytes[6h], 4*3600) < 0 # 4 小时后是否写满
# 偏移对比
node_load1 offset 1d
# 缺失检测
absent(up{job="node"} == 1)
常用告警表达式
# 实例掉线
up == 0
# CPU 使用率 > 80%
100 - (avg by(instance) (rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100) > 80
# 内存使用率 > 90%
(1 - node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes) * 100 > 90
# 磁盘剩余 < 10%
(node_filesystem_avail_bytes{fstype!~"tmpfs|overlay"} / node_filesystem_size_bytes) * 100 < 10
# 5xx 比例 > 1%
sum(rate(http_requests_total{status=~"5.."}[5m]))
/ sum(rate(http_requests_total[5m])) > 0.01
7. 告警规则
# /etc/prometheus/rules/node.yml
groups:
- name: node
rules:
- alert: InstanceDown
expr: up == 0
for: 2m
labels:
severity: critical
annotations:
summary: "实例 {{ $labels.instance }} 掉线"
description: "已持续 2 分钟,job={{ $labels.job }}"
- alert: DiskWillFillIn4Hours
expr: predict_linear(node_filesystem_avail_bytes{fstype!~"tmpfs"}[6h], 4*3600) < 0
for: 10m
labels:
severity: warning
annotations:
summary: "{{ $labels.instance }} {{ $labels.mountpoint }} 预计 4 小时内写满"
for 是关键:避免瞬时抖动触发告警。
8. 常用 Exporter
| Exporter | 端口 | 采集内容 |
|---|---|---|
node_exporter |
9100 | 主机 CPU/内存/磁盘/网络 |
mysqld_exporter |
9104 | MySQL |
postgres_exporter |
9187 | PostgreSQL |
redis_exporter |
9121 | Redis |
nginx_exporter |
9113 | Nginx stub_status |
blackbox_exporter |
9115 | 探活(HTTP/TCP/ICMP/DNS) |
cadvisor |
8080 | 容器 |
# node_exporter 常用启动参数
node_exporter \
--web.listen-address=:9100 \
--collector.systemd \
--collector.processes \
--collector.textfile.directory=/var/lib/node_exporter/textfile
9. 实战场景
9.1 新增一台机器接入监控
# 目标机
wget https://github.com/prometheus/node_exporter/releases/download/v1.8.2/node_exporter-1.8.2.linux-amd64.tar.gz
tar xf node_exporter-*.tar.gz && sudo mv node_exporter-*/node_exporter /usr/local/bin/
sudo useradd -rs /bin/false node_exporter
sudo tee /etc/systemd/system/node_exporter.service <<'EOF'
[Unit]
Description=Node Exporter
[Service]
User=node_exporter
ExecStart=/usr/local/bin/node_exporter
Restart=always
[Install]
WantedBy=multi-user.target
EOF
sudo systemctl enable --now node_exporter
curl -s localhost:9100/metrics | head
Prometheus 侧加 target,systemctl reload prometheus,然后在 /targets 页面确认 UP。
9.2 用 API 查询(脚本/巡检)
# 即时查询
curl -s 'http://localhost:9090/api/v1/query?query=up' | jq '.data.result | length'
# 区间查询
curl -s --data-urlencode 'query=rate(node_cpu_seconds_total{mode="idle"}[5m])' \
--data-urlencode "start=$(date -d '-1h' +%s)" \
--data-urlencode "end=$(date +%s)" \
--data-urlencode 'step=60' \
http://localhost:9090/api/v1/query_range | jq '.data.result | length'
# 查 targets 健康
curl -s localhost:9090/api/v1/targets | jq -r '.data.activeTargets[] | select(.health!="up") | "\(.labels.instance) \(.lastError)"'
9.3 磁盘写满预警
predict_linear(node_filesystem_avail_bytes{mountpoint="/"}[6h], 24*3600) < 0
按当前 6 小时的增长斜率预测 24 小时后是否耗尽,比"剩余 10%"更早发现问题。
9.4 排查 target 抓不到
curl -s localhost:9090/api/v1/targets | jq '.data.activeTargets[] | select(.health=="down")'
# 或直接访问 http://prom:9090/targets
curl -v http://<target>:9100/metrics # 从 Prometheus 机器上验证连通
常见原因:网络/防火墙、exporter 没起、metrics_path 不对、scheme 需要 https。
10. 常见坑
rate()窗口太短:小于 2 个采样间隔会得到空值,scrape_interval 15s时窗口至少 1m,推荐5m。- Counter 重启归零:
rate/increase会自动处理,但delta不会。 irate只取最后两个点:适合看瞬时,不适合告警。- 高基数标签:把
user_id、request_id、原始 URL 做标签会撑爆内存,必须metric_relabel_configs丢弃或聚合。 sum忘记by:结果丢失维度,无法定位实例。- 时间戳对齐:Prometheus 按抓取时间存,不是应用上报时间。
- 存储无限增长:不设
retention会写满磁盘,同时配size上限。 - 配置改了不生效:没加
--web.enable-lifecycle时reload无效,只能重启。 - 告警不触发:
for太长、表达式恒为 false、Alertmanager 没配路由。 histogram_quantile结果偏差:桶边界设计不合理,或没有sum by (le)。- 多副本重复告警:Prometheus 高可用需要 Alertmanager 集群去重。
up == 0抓不到:target 被 relabel 丢弃了,看/targets的droppedTargets。- 时钟不同步:时间偏差大会导致查询结果错乱,务必配 NTP。
11. 速查表
promtool check config prometheus.yml
promtool check rules rules/*.yml
curl -X POST http://localhost:9090/-/reload # 需 enable-lifecycle
curl localhost:9090/api/v1/targets | jq
curl 'localhost:9090/api/v1/query?query=up'
rate(x_total[5m])
increase(x_total[1h])
sum by (label) (rate(x_total[5m]))
histogram_quantile(0.99, sum by (le) (rate(x_bucket[5m])))
topk(5, ...)
predict_linear(node_filesystem_avail_bytes[6h], 86400) < 0
up == 0
# 页面
/targets /graph /rules /alerts /config