Prometheus —— 指标采集与时序查询

运维工具手册 09-日志与监控 8.1 KB 原文

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. 常见坑

  1. rate() 窗口太短:小于 2 个采样间隔会得到空值,scrape_interval 15s 时窗口至少 1m,推荐 5m。
  2. Counter 重启归零:rate/increase 会自动处理,但 delta 不会。
  3. irate 只取最后两个点:适合看瞬时,不适合告警。
  4. 高基数标签:把 user_id、request_id、原始 URL 做标签会撑爆内存,必须 metric_relabel_configs 丢弃或聚合。
  5. sum 忘记 by:结果丢失维度,无法定位实例。
  6. 时间戳对齐:Prometheus 按抓取时间存,不是应用上报时间。
  7. 存储无限增长:不设 retention 会写满磁盘,同时配 size 上限。
  8. 配置改了不生效:没加 --web.enable-lifecycle 时 reload 无效,只能重启。
  9. 告警不触发:for 太长、表达式恒为 false、Alertmanager 没配路由。
  10. histogram_quantile 结果偏差:桶边界设计不合理,或没有 sum by (le)。
  11. 多副本重复告警:Prometheus 高可用需要 Alertmanager 集群去重。
  12. up == 0 抓不到:target 被 relabel 丢弃了,看 /targets 的 droppedTargets。
  13. 时钟不同步:时间偏差大会导致查询结果错乱,务必配 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
Prometheus —— 指标采集与时序查询 - 知识库 - 起航社区