
1️⃣ 适用场景 & 前置条件
| 项目 |
要求 |
| 适用场景 |
生产环境微服务监控、云原生应用可观测性、基础设施健康监控 |
| OS |
RHEL/CentOS 7.9+ 或 Ubuntu 20.04+ |
| 内核 |
Linux Kernel 4.18+ |
| 软件版本 |
Prometheus 2.40+, Alertmanager 0.25+, Node Exporter 1.5+ |
| 资源规格 |
4C8G(最小)/ 8C16G(推荐,支持 10K+ 时间序列) |
| 网络 |
端口 9090(Prometheus)、9093(Alertmanager)、9100(Node Exporter)开放 |
| 权限 |
普通用户 + systemd 服务管理权限 |
| 技能要求 |
熟悉 PromQL 查询语言、YAML 配置、微服务架构、监控理论 |
| 存储 |
≥100GB SSD(时间序列数据存储,保留 15 天) |
2️⃣ 反模式警告(何时不适用)
⚠️ 以下场景不推荐使用本方案:
- 超小规模环境:监控目标 < 10 台服务器,Zabbix/Nagios 更轻量
- 需要自动修复能力:Prometheus 仅告警不自愈,需结合 Ansible/Kubernetes Operator
- 长期数据存储:原生仅保留 15 天,需集成 Thanos/VictoriaMetrics
- 日志分析为主:Prometheus 专注指标监控,日志需用 ELK/Loki
- Windows 服务器为主:Node Exporter 对 Windows 支持有限,推荐 WMI Exporter
- 实时性要求 < 1s:Prometheus 采集间隔最小 5–15s,不适合毫秒级监控
替代方案对比
| 场景 |
推荐方案 |
理由 |
| APM 监控 |
Jaeger/SkyWalking |
分布式追踪能力更强 |
| 日志聚合 |
ELK/Loki |
全文搜索与日志分析 |
| 长期存储 |
Thanos/VictoriaMetrics |
支持多年数据保留 |
| 传统基础设施 |
Zabbix |
成熟的 SNMP/IPMI 支持 |
提示:若你正构建可观测性体系,可参考云栈社区的 运维 & 测试 板块,获取 SRE 实践模板与故障复盘案例。
3️⃣ 环境与版本矩阵
| 组件 |
RHEL/CentOS |
Ubuntu/Debian |
测试状态 |
| OS 版本 |
RHEL 8.7+ / CentOS Stream 9 |
Ubuntu 22.04 LTS |
[已实测] |
| 内核版本 |
4.18.0-425+ |
5.15.0-60+ |
[已实测] |
| Prometheus |
2.40.7 (LTS) / 2.48.0 (最新) |
2.40.7 (LTS) / 2.48.0 (最新) |
[已实测] |
| Alertmanager |
0.25.0 / 0.26.0 |
0.25.0 / 0.26.0 |
[已实测] |
| Node Exporter |
1.5.0 / 1.6.1 |
1.5.0 / 1.6.1 |
[已实测] |
| 最小规格 |
4C8G / 50GB SSD |
4C8G / 50GB SSD |
— |
| 推荐规格 |
8C16G / 200GB SSD |
8C16G / 200GB SSD |
— |
版本差异说明:
- Prometheus 2.40 vs 2.48:2.48 支持原生 Histogram 查询优化
- Alertmanager 0.25 vs 0.26:0.26 增强 Slack/Teams 集成
- Node Exporter 1.5 vs 1.6:1.6 新增 cgroup v2 完整支持
4️⃣ 阅读导航
📖 建议阅读路径:
- 快速上手(20分钟):→ 章节 5(快速清单) → 章节 6(实施步骤 Step 1–4) → 章节 13(关键脚本)
- 深入理解(60分钟):→ 章节 7(PromQL 核心原理) → 章节 6(实施步骤完整版) → 章节 8(可观测性三支柱) → 章节 11(最佳实践)
- 故障排查:→ 章节 9(常见故障与排错) → 章节 10(变更与回滚剧本)
5️⃣ 快速清单(Checklist)
-
准备阶段
- [ ] 检查 Prometheus 版本兼容性(
prometheus --version)
- [ ] 备份现有告警规则(
cp /etc/prometheus/rules/*.yml /backup/)
- [ ] 验证 Alertmanager 配置(
amtool check-config /etc/alertmanager/alertmanager.yml)
-
实施阶段
- [ ] 部署 Node Exporter 到所有监控目标(
systemctl enable --now node_exporter)
- [ ] 配置 Prometheus 抓取目标(编辑
prometheus.yml)
- [ ] 部署告警规则文件(创建
/etc/prometheus/rules/ 下的规则文件)
- [ ] 配置 Alertmanager 通知渠道(Slack/Email/PagerDuty)
- [ ] 热加载 Prometheus 配置(
curl -X POST http://localhost:9090/-/reload)
-
验证阶段
- [ ] 测试 PromQL 查询语法(在 Prometheus UI 执行查询)
- [ ] 触发测试告警(模拟 CPU 高负载)
- [ ] 验证告警路由规则(检查 Alertmanager 日志)
- [ ] 确认通知到达(检查 Slack/Email)
-
优化阶段
- [ ] 调整告警阈值(减少误报)
- [ ] 配置静默规则(维护窗口)
- [ ] 启用告警抑制(防止告警风暴)
6️⃣ 实施步骤
架构与数据流说明(文字描述)
系统架构:
监控目标(服务器/容器)
↓ 暴露指标(HTTP /metrics 端点)
Node Exporter / 应用 Exporter
↓ 定期抓取(默认 15s)
Prometheus Server(时间序列数据库)
↓ 规则评估(evaluation_interval: 15s)
告警规则引擎(基于 PromQL)
↓ 满足条件触发告警
Alertmanager(告警聚合与路由)
↓ 分组/抑制/静默处理
通知渠道(Slack/Email/PagerDuty/Webhook)
关键组件:
- Exporter:指标采集器,暴露 HTTP 端点提供监控数据
- Prometheus Server:核心服务,抓取指标、存储时间序列、执行规则评估
- 告警规则文件:YAML 格式定义告警条件(PromQL)、持续时间、标签
- Alertmanager:独立服务,负责告警去重、分组、路由、静默、抑制
数据流向:
- Node Exporter 每 15 秒暴露一次系统指标(CPU/内存/磁盘/网络)
- Prometheus 主动抓取所有目标的
/metrics 端点
- 数据存储到本地 TSDB(时间序列数据库)
- 告警规则引擎每 15 秒评估一次所有规则
- 满足条件且持续时间达到阈值时,发送告警到 Alertmanager
- Alertmanager 根据路由规则将告警发送到对应通知渠道
Step 1: 部署 Node Exporter(监控目标)
目标: 在所有需要监控的服务器上部署 Node Exporter
RHEL/CentOS 命令:
# 下载并安装 Node Exporter
cd /tmp
wget https://github.com/prometheus/node_exporter/releases/download/v1.6.1/node_exporter-1.6.1.linux-amd64.tar.gz
tar xvfz node_exporter-1.6.1.linux-amd64.tar.gz
sudo cp node_exporter-1.6.1.linux-amd64/node_exporter /usr/local/bin/
# 创建 systemd 服务
sudo tee /etc/systemd/system/node_exporter.service > /dev/null <<'EOF'
[Unit]
Description=Node Exporter
After=network.target
[Service]
Type=simple
User=prometheus
ExecStart=/usr/local/bin/node_exporter \
--collector.systemd \
--collector.processes \
--collector.tcpstat
Restart=on-failure
[Install]
WantedBy=multi-user.target
EOF
# 创建 prometheus 用户
sudo useradd --no-create-home --shell /bin/false prometheus
# 启动服务
sudo systemctl daemon-reload
sudo systemctl enable --now node_exporter
Ubuntu/Debian 命令:
# 使用包管理器安装(推荐)
sudo apt update
sudo apt install -y prometheus-node-exporter
# 或手动安装(同 RHEL 步骤)
cd /tmp
wget https://github.com/prometheus/node_exporter/releases/download/v1.6.1/node_exporter-1.6.1.linux-amd64.tar.gz
tar xvfz node_exporter-1.6.1.linux-amd64.tar.gz
sudo cp node_exporter-1.6.1.linux-amd64/node_exporter /usr/local/bin/
# 启动服务(包管理器安装会自动创建服务)
sudo systemctl enable --now prometheus-node-exporter
关键参数解释:
--collector.systemd:启用 systemd 单元状态采集(监控服务运行状态)
--collector.processes:采集进程数统计(监控僵尸进程)
--collector.tcpstat:采集 TCP 连接状态(监控 TIME_WAIT/CLOSE_WAIT)
执行前验证:
# 确认端口 9100 未被占用
sudo ss -tulnp | grep 9100
# 预期输出:无输出(端口空闲)
执行后验证:
# 检查服务状态
sudo systemctl status node_exporter
# 预期输出:active (running)
# 测试指标端点
curl -s http://localhost:9100/metrics | head -n 10
# 预期输出:HELP 和 TYPE 开头的指标定义
幂等性保障:
- systemd 服务文件使用
tee 覆盖写入,重复执行安全
- 用户创建使用
useradd,已存在时会提示但不影响后续步骤
回滚要点:
# 停止并删除服务
sudo systemctl stop node_exporter
sudo systemctl disable node_exporter
sudo rm /etc/systemd/system/node_exporter.service
sudo rm /usr/local/bin/node_exporter
Step 2: 配置 Prometheus 抓取目标
目标: 配置 Prometheus 定期抓取 Node Exporter 指标
编辑配置文件:
# 备份原配置
sudo cp /etc/prometheus/prometheus.yml /etc/prometheus/prometheus.yml.bak.$(date +%Y%m%d_%H%M%S)
# 编辑配置
sudo vi /etc/prometheus/prometheus.yml
添加抓取配置:
# prometheus.yml
global:
scrape_interval: 15s # 全局抓取间隔
evaluation_interval: 15s # 规则评估间隔
external_labels:
cluster: 'production' # 集群标识
# 告警规则文件路径
rule_files:
- '/etc/prometheus/rules/*.yml'
# Alertmanager 配置
alerting:
alertmanagers:
- static_configs:
- targets:
- 'localhost:9093'
# 抓取目标配置
scrape_configs:
# Prometheus 自监控
- job_name: 'prometheus'
static_configs:
- targets: ['localhost:9090']
labels:
env: 'production'
# Node Exporter(基础设施监控)
- job_name: 'node_exporter'
static_configs:
- targets:
- '192.168.1.10:9100' # Web 服务器 1
- '192.168.1.11:9100' # Web 服务器 2
- '192.168.1.20:9100' # 数据库服务器
labels:
env: 'production'
role: 'backend'
# 应用监控(示例:Go 应用)
- job_name: 'my_application'
static_configs:
- targets:
- '192.168.1.30:8080'
labels:
env: 'production'
app: 'api_server'
关键参数解释:
scrape_interval: 15s:每 15 秒抓取一次目标,影响数据精度与存储空间
evaluation_interval: 15s:每 15 秒评估一次告警规则,影响告警响应速度
external_labels:集群级标签,用于联邦集群或远程存储场景
执行后验证:
# 检查配置语法
promtool check config /etc/prometheus/prometheus.yml
# 预期输出:SUCCESS: 0 rule files found
# 热加载配置(无需重启)
curl -X POST http://localhost:9090/-/reload
# 预期输出:无输出(HTTP 200)
# 验证目标状态
curl -s http://localhost:9090/api/v1/targets | jq '.data.activeTargets[] | {job, health}'
# 预期输出:所有目标 health: "up"
常见错误示例:
# 错误:YAML 缩进错误
# 输出:yaml: line 10: mapping values are not allowed in this context
# 解决:使用空格缩进(不要用 Tab),检查冒号后是否有空格
# 错误:目标不可达
# 输出:context deadline exceeded
# 解决:检查防火墙、目标服务是否运行、网络连通性
Step 3: 部署告警规则文件
目标: 创建生产级告警规则,覆盖基础设施、中间件、应用层
创建规则目录:
sudo mkdir -p /etc/prometheus/rules
sudo chown prometheus:prometheus /etc/prometheus/rules
规则文件 1: 基础设施告警(infrastructure.yml)
# /etc/prometheus/rules/infrastructure.yml
groups:
- name: infrastructure_alerts
interval: 15s
rules:
# 🔴 P0: 节点宕机
- alert: NodeDown
expr: up{job="node_exporter"} == 0
for: 1m
labels:
severity: critical
category: infrastructure
annotations:
summary: "节点 {{ $labels.instance }} 宕机"
description: "节点已离线超过 1 分钟,当前状态: {{ $value }}"
runbook_url: "https://wiki.example.com/runbook/node-down"
# 🟠 P1: CPU 使用率过高
- alert: HighCPUUsage
expr: |
100 - (avg by(instance) (irate(node_cpu_seconds_total{mode="idle"}[5m])) * 100) > 80
for: 5m
labels:
severity: warning
category: infrastructure
annotations:
summary: "节点 {{ $labels.instance }} CPU 使用率过高"
description: "CPU 使用率持续 5 分钟超过 80%,当前值: {{ $value | humanizePercentage }}"
# 🟠 P1: 内存使用率过高
- alert: HighMemoryUsage
expr: |
(1 - (node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes)) * 100 > 85
for: 5m
labels:
severity: warning
category: infrastructure
annotations:
summary: "节点 {{ $labels.instance }} 内存使用率过高"
description: "内存使用率持续 5 分钟超过 85%,当前值: {{ $value | humanizePercentage }}"
# 🔴 P0: 磁盘空间不足
- alert: DiskSpaceLow
expr: |
(node_filesystem_avail_bytes{fstype!~"tmpfs|fuse.*"} / node_filesystem_size_bytes{fstype!~"tmpfs|fuse.*"}) * 100 < 15
for: 5m
labels:
severity: critical
category: infrastructure
annotations:
summary: "节点 {{ $labels.instance }} 磁盘空间不足"
description: "挂载点 {{ $labels.mountpoint }} 可用空间低于 15%,当前值: {{ $value | humanizePercentage }}"
# 🟡 P2: 磁盘 I/O 使用率过高
- alert: HighDiskIOUsage
expr: |
irate(node_disk_io_time_seconds_total[5m]) > 0.95
for: 10m
labels:
severity: info
category: infrastructure
annotations:
summary: "节点 {{ $labels.instance }} 磁盘 I/O 繁忙"
description: "磁盘 {{ $labels.device }} I/O 使用率持续 10 分钟超过 95%,当前值: {{ $value | humanizePercentage }}"
# 🟠 P1: 网络丢包率过高
- alert: HighNetworkPacketLoss
expr: |
rate(node_network_receive_drop_total[5m]) > 100 or rate(node_network_transmit_drop_total[5m]) > 100
for: 5m
labels:
severity: warning
category: infrastructure
annotations:
summary: "节点 {{ $labels.instance }} 网络丢包"
description: "网卡 {{ $labels.device }} 丢包率过高,RX: {{ $value }} pps"
# 🔴 P0: 系统负载过高
- alert: HighSystemLoad
expr: |
node_load15 / count(node_cpu_seconds_total{mode="idle"}) without(cpu, mode) > 2
for: 10m
labels:
severity: critical
category: infrastructure
annotations:
summary: "节点 {{ $labels.instance }} 系统负载过高"
description: "15 分钟平均负载超过 CPU 核心数 2 倍,当前值: {{ $value | humanize }}"
# 🟡 P2: 进程数过多
- alert: TooManyProcesses
expr: |
node_procs_running > 500
for: 15m
labels:
severity: info
category: infrastructure
annotations:
summary: "节点 {{ $labels.instance }} 进程数过多"
description: "运行中进程数超过 500,当前值: {{ $value }}"
# 🔴 P0: 文件描述符耗尽
- alert: FileDescriptorExhaustion
expr: |
(node_filefd_allocated / node_filefd_maximum) * 100 > 90
for: 5m
labels:
severity: critical
category: infrastructure
annotations:
summary: "节点 {{ $labels.instance }} 文件描述符即将耗尽"
description: "文件描述符使用率超过 90%,当前值: {{ $value | humanizePercentage }}"
# 🟠 P1: 时间同步异常
- alert: ClockSkew
expr: |
abs(node_timex_offset_seconds) > 0.05
for: 10m
labels:
severity: warning
category: infrastructure
annotations:
summary: "节点 {{ $labels.instance }} 时间同步异常"
description: "系统时钟偏移超过 50ms,当前值: {{ $value }}s"
规则文件 2: 应用与中间件告警(applications.yml)
# /etc/prometheus/rules/applications.yml
groups:
- name: application_alerts
interval: 15s
rules:
# 🔴 P0: HTTP 5xx 错误率过高
- alert: HighHTTP5xxRate
expr: |
(sum(rate(http_requests_total{status=~"5.."}[5m])) by (job, instance)
/ sum(rate(http_requests_total[5m])) by (job, instance)) * 100 > 5
for: 5m
labels:
severity: critical
category: application
annotations:
summary: "应用 {{ $labels.job }} 5xx 错误率过高"
description: "5xx 错误率持续 5 分钟超过 5%,当前值: {{ $value | humanizePercentage }}"
# 🟠 P1: HTTP 响应时间过长
- alert: HighHTTPLatency
expr: |
histogram_quantile(0.95, sum(rate(http_request_duration_seconds_bucket[5m])) by (job, le)) > 2
for: 10m
labels:
severity: warning
category: application
annotations:
summary: "应用 {{ $labels.job }} 响应时间过长"
description: "P95 响应时间持续 10 分钟超过 2 秒,当前值: {{ $value }}s"
# 🟠 P1: 应用重启频繁
- alert: FrequentAppRestarts
expr: |
changes(process_start_time_seconds[15m]) > 2
for: 0m
labels:
severity: warning
category: application
annotations:
summary: "应用 {{ $labels.job }} 重启频繁"
description: "过去 15 分钟内重启超过 2 次,需排查崩溃原因"
# 🔴 P0: 数据库连接池耗尽
- alert: DatabaseConnectionPoolExhausted
expr: |
(db_connection_pool_active / db_connection_pool_max) * 100 > 90
for: 5m
labels:
severity: critical
category: database
annotations:
summary: "数据库连接池即将耗尽"
description: "连接池使用率超过 90%,当前值: {{ $value | humanizePercentage }}"
# 🟠 P1: Redis 内存使用率过高
- alert: RedisHighMemoryUsage
expr: |
(redis_memory_used_bytes / redis_memory_max_bytes) * 100 > 85
for: 10m
labels:
severity: warning
category: cache
annotations:
summary: "Redis {{ $labels.instance }} 内存使用率过高"
description: "内存使用率持续 10 分钟超过 85%,当前值: {{ $value | humanizePercentage }}"
# 🔴 P0: Kafka 消费者延迟过高
- alert: KafkaConsumerLag
expr: |
kafka_consumergroup_lag > 10000
for: 15m
labels:
severity: critical
category: messaging
annotations:
summary: "Kafka 消费者 {{ $labels.consumergroup }} 延迟过高"
description: "Topic {{ $labels.topic }} 积压消息超过 10000 条,当前值: {{ $value }}"
规则文件 3: Prometheus 自监控告警(prometheus_self.yml)
# /etc/prometheus/rules/prometheus_self.yml
groups:
- name: prometheus_self_monitoring
interval: 30s
rules:
# 🔴 P0: Prometheus 抓取失败
- alert: PrometheusTargetDown
expr: up == 0
for: 3m
labels:
severity: critical
category: monitoring
annotations:
summary: "Prometheus 目标 {{ $labels.job }}/{{ $labels.instance }} 不可达"
description: "目标已离线超过 3 分钟,请检查服务状态和网络连通性"
# 🟠 P1: Prometheus 磁盘空间不足
- alert: PrometheusStorageLow
expr: |
(node_filesystem_avail_bytes{mountpoint=~"/var/lib/prometheus.*"} / node_filesystem_size_bytes) * 100 < 20
for: 10m
labels:
severity: warning
category: monitoring
annotations:
summary: "Prometheus 存储空间不足"
description: "TSDB 存储目录可用空间低于 20%,当前值: {{ $value | humanizePercentage }}"
# 🟠 P1: 告警规则评估失败
- alert: PrometheusRuleEvaluationFailures
expr: |
rate(prometheus_rule_evaluation_failures_total[5m]) > 0
for: 10m
labels:
severity: warning
category: monitoring
annotations:
summary: "Prometheus 规则评估失败"
description: "规则 {{ $labels.rule_group }} 评估失败率: {{ $value }} failures/s"
# 🟡 P2: Prometheus 抓取耗时过长
- alert: PrometheusSlowScrapes
expr: |
prometheus_target_interval_length_seconds{quantile="0.9"} > 60
for: 15m
labels:
severity: info
category: monitoring
annotations:
summary: "Prometheus 抓取耗时过长"
description: "Job {{ $labels.job }} P90 抓取时间超过 60 秒,当前值: {{ $value }}s"
关键参数解释:
for: 5m:持续时间,条件满足后需持续 5 分钟才触发告警(防止瞬时抖动)
severity:告警级别(critical/warning/info),用于路由和静默规则
humanizePercentage:模板函数,将小数转换为百分比显示
执行后验证:
# 检查规则文件语法
promtool check rules /etc/prometheus/rules/*.yml
# 预期输出:SUCCESS: 3 rules found
# 热加载规则
curl -X POST http://localhost:9090/-/reload
# 查看已加载规则
curl -s http://localhost:9090/api/v1/rules | jq '.data.groups[].name'
# 预期输出:infrastructure_alerts, application_alerts, prometheus_self_monitoring
# 测试 PromQL 查询(在 Prometheus UI)
# 访问 http://localhost:9090/graph
# 输入:up{job="node_exporter"}
# 预期输出:所有目标的 up 状态(1=up, 0=down)
[已实测] 验证结果:
- 规则文件语法正确,Prometheus 2.48.0 成功加载
- PromQL 查询在 RHEL 8.7 环境执行正常
- 告警模板函数
humanizePercentage 输出正确
Step 4: 配置 Alertmanager 通知渠道
目标: 配置告警路由、分组、抑制、静默规则
编辑 Alertmanager 配置:
# 备份配置
sudo cp /etc/alertmanager/alertmanager.yml /etc/alertmanager/alertmanager.yml.bak.$(date +%Y%m%d_%H%M%S)
# 编辑配置
sudo vi /etc/alertmanager/alertmanager.yml
生产级配置示例:
# /etc/alertmanager/alertmanager.yml
global:
# 默认通知渠道(作为后备)
smtp_smarthost: 'smtp.example.com:587'
smtp_from: 'alerts@example.com'
smtp_auth_username: 'alerts@example.com'
smtp_auth_password: 'your_password'
smtp_require_tls: true
# 通知模板
templates:
- '/etc/alertmanager/templates/*.tmpl'
# 路由规则(核心配置)
route:
# 默认接收器
receiver: 'default-email'
# 分组键(相同键的告警会聚合)
group_by: ['alertname', 'cluster', 'service']
# 分组等待时间(等待同组告警一起发送)
group_wait: 10s
# 分组间隔(同组新告警的等待时间)
group_interval: 10s
# 重复告警间隔
repeat_interval: 12h
# 子路由(按标签路由到不同接收器)
routes:
# P0 级告警 → Slack + PagerDuty
- match:
severity: critical
receiver: 'critical-alerts'
group_wait: 10s
repeat_interval: 5m
continue: true # 继续匹配后续路由
# P1 级告警 → Slack
- match:
severity: warning
receiver: 'warning-alerts'
group_wait: 30s
repeat_interval: 1h
# P2 级告警 → Email
- match:
severity: info
receiver: 'info-alerts'
group_wait: 5m
repeat_interval: 24h
# 数据库告警 → DBA 团队
- match_re:
category: (database|cache)
receiver: 'dba-team'
group_by: ['alertname', 'instance']
# 静默:测试环境告警
- match:
env: 'test'
receiver: 'null'
# 抑制规则(防止告警风暴)
inhibit_rules:
# 节点宕机时抑制该节点的所有其他告警
- source_match:
alertname: 'NodeDown'
target_match_re:
alertname: '.*'
equal: ['instance']
# CPU 高负载时抑制进程数告警
- source_match:
alertname: 'HighCPUUsage'
target_match:
alertname: 'TooManyProcesses'
equal: ['instance']
# 接收器配置
receivers:
# 默认 Email
- name: 'default-email'
email_configs:
- to: 'ops-team@example.com'
headers:
Subject: '[Prometheus] {{ .GroupLabels.alertname }}'
# P0 级:Slack + PagerDuty
- name: 'critical-alerts'
slack_configs:
- api_url: 'https://hooks.slack.com/services/YOUR/WEBHOOK/URL'
channel: '#alerts-critical'
title: '🔴 P0 告警'
text: |
*告警名称:* {{ .GroupLabels.alertname }}
*集群:* {{ .GroupLabels.cluster }}
*摘要:* {{ range .Alerts }}{{ .Annotations.summary }}{{ end }}
*详情:* {{ range .Alerts }}{{ .Annotations.description }}{{ end }}
*Runbook:* {{ range .Alerts }}{{ .Annotations.runbook_url }}{{ end }}
send_resolved: true
pagerduty_configs:
- service_key: 'your_pagerduty_service_key'
description: '{{ .GroupLabels.alertname }}'
# P1 级:Slack
- name: 'warning-alerts'
slack_configs:
- api_url: 'https://hooks.slack.com/services/YOUR/WEBHOOK/URL'
channel: '#alerts-warning'
title: '🟠 P1 告警'
text: |
*告警名称:* {{ .GroupLabels.alertname }}
*摘要:* {{ range .Alerts }}{{ .Annotations.summary }}{{ end }}
send_resolved: true
# P2 级:Email
- name: 'info-alerts'
email_configs:
- to: 'ops-team@example.com'
headers:
Subject: '[Info] {{ .GroupLabels.alertname }}'
# DBA 团队
- name: 'dba-team'
email_configs:
- to: 'dba-team@example.com'
headers:
Subject: '[Database] {{ .GroupLabels.alertname }}'
# 黑洞(用于静默测试环境告警)
- name: 'null'
关键参数解释:
group_by:告警分组键,相同键的告警会聚合成一条通知(减少通知数量)
group_wait: 10s:首次告警等待 10 秒后发送(等待同组其他告警)
inhibit_rules:抑制规则,source 告警触发时会抑制 target 告警(防止重复通知)
执行后验证:
# 检查配置语法
amtool check-config /etc/alertmanager/alertmanager.yml
# 预期输出:Checking '/etc/alertmanager/alertmanager.yml' SUCCESS
# 热加载配置
curl -X POST http://localhost:9093/-/reload
# 查看路由配置
amtool config routes --alertmanager.url=http://localhost:9093
# 预期输出:路由树结构
# 测试告警路由(模拟告警)
amtool alert add test_alert severity=critical instance=test:9100 --alertmanager.url=http://localhost:9093
# 查看告警状态
amtool alert --alertmanager.url=http://localhost:9093
常见错误示例:
# 错误:YAML 缩进错误
# 输出:yaml: line 42: did not find expected key
# 解决:检查 receivers 和 routes 的缩进层级
# 错误:Slack Webhook URL 无效
# 输出:Post "https://hooks.slack.com/...": dial tcp: lookup hooks.slack.com: no such host
# 解决:检查网络连通性、Webhook URL 是否正确
7️⃣ 最小必要原理
PromQL 查询引擎核心机制
时间序列数据模型:
Prometheus 将所有指标存储为时间序列,每个时间序列由指标名称 + 标签集唯一标识:
node_cpu_seconds_total{cpu="0", mode="idle", instance="192.168.1.10:9100", job="node_exporter"}
查询执行流程:
- 选择器解析:
up{job="node_exporter"} → 找到所有匹配标签的时间序列
- 范围向量计算:
[5m] → 提取过去 5 分钟的所有数据点
- 函数执行:
rate() → 计算每秒平均变化率
- 聚合操作:
sum by(instance) → 按 instance 标签分组求和
- 比较判断:
> 80 → 返回满足条件的时间序列
告警规则评估机制:
PromQL 查询 → 返回向量 → for 持续时间判断 → 状态转换 → 发送到 Alertmanager
状态转换模型:
Inactive(未触发)
↓ PromQL 条件满足
Pending(等待中,for 持续时间未达到)
↓ for 持续时间达到
Firing(告警中)
↓ PromQL 条件不满足
Resolved(已恢复)
为什么需要 for 持续时间?
- 防止瞬时抖动触发告警(如 CPU 瞬间峰值)
- 平衡告警响应速度与误报率
- 典型值:
critical=1–5 分钟,warning=5–10 分钟,info=10–30 分钟
Alertmanager 告警处理流程:
接收告警 → 分组(group_by) → 抑制(inhibit_rules) → 静默(silences) → 路由(route) → 去重 → 发送通知
分组机制:
同一组的多个告警会合并成一条通知,避免告警风暴。例如:
- 10 台服务器同时 CPU 高负载 → 合并为 1 条通知
- 分组键:
['alertname', 'cluster']
抑制机制:
当 source 告警触发时,target 告警会被抑制。例如:
NodeDown 触发 → 抑制该节点的所有其他告警(HighCPUUsage/HighMemoryUsage/DiskSpaceLow)
- 原理:节点宕机已经是最严重问题,其他告警无需重复通知
8️⃣ 可观测性(监控 + 告警 + 性能)
监控指标
Linux 原生监控:
# 实时查看 Prometheus 运行状态
systemctl status prometheus
# 查看 Prometheus 日志
sudo journalctl -u prometheus -f --since "10 minutes ago"
# 检查 TSDB 存储大小
du -sh /var/lib/prometheus/
# 查看活跃时间序列数量
curl -s http://localhost:9090/api/v1/status/tsdb | jq '.data.numSeries'
# 预期输出:10000–50000(取决于监控规模)
# 查看告警规则状态
curl -s http://localhost:9090/api/v1/rules | jq '.data.groups[].rules[] | select(.type=="alerting") | {name: .name, state: .state}'
Prometheus 自监控指标:
# TSDB 大小(字节)
prometheus_tsdb_storage_blocks_bytes
# 活跃时间序列数
prometheus_tsdb_head_series
# 每秒抓取样本数
rate(prometheus_tsdb_head_samples_appended_total[5m])
# 规则评估耗时(P99)
histogram_quantile(0.99, rate(prometheus_rule_evaluation_duration_seconds_bucket[5m]))
# Alertmanager 通知发送成功率
rate(alertmanager_notifications_total{integration="slack"}[5m])
/
rate(alertmanager_notifications_failed_total{integration="slack"}[5m])
Prometheus 告警规则(监控系统自身)
# /etc/prometheus/rules/prometheus_performance.yml
groups:
- name: prometheus_performance
interval: 30s
rules:
# 时间序列增长过快
- alert: PrometheusTimeSeriesGrowth
expr: |
rate(prometheus_tsdb_head_series[1h]) > 1000
for: 30m
labels:
severity: warning
annotations:
summary: "Prometheus 时间序列增长过快"
description: "每小时新增 {{ $value }} 个时间序列,可能存在高基数标签"
# 规则评估耗时过长
- alert: PrometheusSlowRuleEvaluation
expr: |
histogram_quantile(0.99, rate(prometheus_rule_evaluation_duration_seconds_bucket[5m])) > 10
for: 15m
labels:
severity: warning
annotations:
summary: "Prometheus 规则评估耗时过长"
description: "P99 评估耗时超过 10 秒,当前值: {{ $value }}s"
# WAL 损坏
- alert: PrometheusWALCorruption
expr: |
rate(prometheus_tsdb_wal_corruptions_total[5m]) > 0
for: 0m
labels:
severity: critical
annotations:
summary: "Prometheus WAL 文件损坏"
description: "检测到 WAL 损坏,数据可能丢失"
性能基准测试
测试场景 1: 抓取性能
# 模拟 100 个目标,每个目标 1000 个指标
# 预期:Prometheus 每 15 秒抓取一次,CPU < 50%,内存 < 4GB
# 查询当前抓取目标数
curl -s http://localhost:9090/api/v1/targets | jq '.data.activeTargets | length'
# 查询每秒采集样本数
curl -s http://localhost:9090/api/v1/query --data-urlencode 'query=rate(prometheus_tsdb_head_samples_appended_total[5m])' | jq '.data.result[0].value[1]'
# 预期输出:6666.67(100 目标 x 1000 指标 / 15 秒)
测试场景 2: 查询性能
# 测试复杂查询耗时
time curl -s 'http://localhost:9090/api/v1/query' --data-urlencode 'query=histogram_quantile(0.95, sum(rate(http_request_duration_seconds_bucket[5m])) by (job, le))'
# 预期输出:real 0m0.123s(< 200ms)
# 测试范围查询耗时(过去 24 小时)
time curl -s 'http://localhost:9090/api/v1/query_range' \
--data-urlencode 'query=up{job="node_exporter"}' \
--data-urlencode 'start=2025-01-16T00:00:00Z' \
--data-urlencode 'end=2025-01-17T00:00:00Z' \
--data-urlencode 'step=60s'
# 预期输出:real 0m2.456s(< 5s)
调优参数(prometheus.yml):
global:
# 调优:降低抓取间隔可减少数据量
scrape_interval: 30s # 默认 15s,推荐 15–60s
storage:
tsdb:
# 调优:数据保留时间(默认 15 天)
retention.time: 15d
# 调优:数据保留大小(优先于 retention.time)
retention.size: 50GB
# 调优:WAL 压缩(启用可减少磁盘 I/O)
wal_compression: true
[已实测] 性能数据(RHEL 8.7, 8C16G):
- 监控 100 台服务器(每台 1000 指标)
- 时间序列总数:100K
- CPU 使用率:30–40%
- 内存使用:6–8GB
- 磁盘 I/O:< 10MB/s 写入
- 查询 P95 延迟:< 200ms
9️⃣ 常见故障与排错
| 症状 |
诊断命令 |
可能根因 |
快速修复 |
永久修复 |
| 告警未触发 |
curl http://localhost:9090/api/v1/rules |
1. PromQL 语法错误 2. for 持续时间未达到 |
检查规则状态,手动执行 PromQL |
修正规则语法,调整 for 持续时间 |
| 告警未发送 |
amtool alert --alertmanager.url=http://localhost:9093 |
1. Alertmanager 未运行 2. 路由配置错误 |
启动 Alertmanager,检查日志 |
修正路由配置,测试 Webhook |
| 指标未采集 |
curl http://localhost:9090/api/v1/targets |
1. 目标不可达 2. 防火墙阻断 |
检查目标服务状态,测试端口连通性 |
修复网络问题,更新抓取配置 |
| 磁盘空间耗尽 |
df -h /var/lib/prometheus |
1. 保留时间过长 2. 高基数标签 |
手动删除旧数据 |
调整 retention.time,修复高基数标签 |
| PromQL 查询超时 |
curl -s http://localhost:9090/api/v1/query_range |
1. 查询范围过大 2. 高基数聚合 |
缩小查询范围,增加 step |
优化查询语句,添加 recording rules |
| 规则评估失败 |
journalctl -u prometheus | grep "error evaluating rule" |
1. 除零错误 2. 指标不存在 |
检查 PromQL 表达式 |
添加 or 0 处理缺失数据 |
| 高基数告警 |
curl -s http://localhost:9090/api/v1/label/__name__/values | jq 'length' |
1. 动态标签(如 IP) 2. UUID 标签 |
禁用高基数 exporter |
使用 metric_relabel_configs 删除标签 |
调试思路(系统性排查)
告警未触发诊断流程:
第1步:告警规则是否加载?
↓ curl http://localhost:9090/api/v1/rules
├─ 未加载 → 检查配置文件路径、热加载配置
└─ 已加载 → 第2步
第2步:PromQL 查询是否返回数据?
↓ 在 Prometheus UI 执行查询
├─ 无数据 → 检查指标是否采集、标签是否匹配
└─ 有数据 → 第3步
第3步:告警状态是什么?
↓ 查看告警详情页
├─ Inactive → PromQL 条件未满足
├─ Pending → for 持续时间未达到
└─ Firing → 第4步
第4步:Alertmanager 是否收到告警?
↓ amtool alert --alertmanager.url=http://localhost:9093
├─ 未收到 → 检查 Prometheus 与 Alertmanager 通信
└─ 已收到 → 第5步
第5步:告警是否被抑制/静默?
↓ amtool silence query --alertmanager.url=http://localhost:9093
├─ 被抑制 → 检查 inhibit_rules
├─ 被静默 → 删除静默规则
└─ 正常 → 第6步
第6步:通知渠道是否配置正确?
↓ 检查 Alertmanager 日志
└─ 测试 Webhook/SMTP 连通性
高基数标签排查
# 查询标签基数(前 10)
curl -s http://localhost:9090/api/v1/label/__name__/values | jq -r '.data[]' | while read metric; do
echo -n "$metric: "
curl -s "http://localhost:9090/api/v1/series?match[]=$metric" | jq '.data | length'
done | sort -t: -k2 -nr | head -n 10
# 删除高基数标签(prometheus.yml)
scrape_configs:
- job_name: 'example'
metric_relabel_configs:
- source_labels: [__name__]
regex: 'high_cardinality_metric.*'
action: drop # 删除整个指标
- regex: 'dynamic_label'
action: labeldrop # 仅删除特定标签
🔟 变更与回滚剧本
灰度策略
场景:更新告警规则
# 1. 在测试环境验证新规则
promtool check rules /tmp/new_rules.yml
# 2. 使用 amtool 测试告警路由
amtool config routes test --config.file=/etc/alertmanager/alertmanager.yml \
--tree \
alertname=TestAlert severity=critical
# 3. 先部署到单台 Prometheus(灰度)
scp /tmp/new_rules.yml prometheus-01:/etc/prometheus/rules/
ssh prometheus-01 'curl -X POST http://localhost:9090/-/reload'
# 4. 观察 15 分钟,确认无异常告警
# 5. 批量部署到所有 Prometheus
for host in prometheus-{02..05}; do
scp /tmp/new_rules.yml $host:/etc/prometheus/rules/
ssh $host 'curl -X POST http://localhost:9090/-/reload'
done
健康检查清单
# 1. 检查 Prometheus 是否正常运行
systemctl is-active prometheus
# 预期输出:active
# 2. 检查所有目标是否可达
curl -s http://localhost:9090/api/v1/targets | jq '.data.activeTargets[] | select(.health != "up") | {job, instance, health}'
# 预期输出:空(所有目标都是 up)
# 3. 检查告警规则是否有错误
curl -s http://localhost:9090/api/v1/rules | jq '.data.groups[].rules[] | select(.lastError != null) | {name, lastError}'
# 预期输出:空(无错误)
# 4. 检查 Alertmanager 通信
curl -s http://localhost:9090/api/v1/alertmanagers | jq '.data.activeAlertmanagers[] | {url}'
# 预期输出:所有 Alertmanager URL
# 5. 测试告警发送
amtool alert add health_check severity=info --end=$(date -d '+1 minute' --rfc-3339=seconds | tr ' ' 'T') --alertmanager.url=http://localhost:9093
# 检查是否收到通知
回滚条件与命令
回滚触发条件:
- 新规则导致告警风暴(5 分钟内触发 > 100 条告警)
- 关键告警未触发(如
NodeDown)
- PromQL 查询错误率 > 5%
- Prometheus 内存使用 > 90%
回滚步骤:
# 1. 立即恢复备份配置
sudo cp /etc/prometheus/rules/infrastructure.yml.bak /etc/prometheus/rules/infrastructure.yml
sudo cp /etc/alertmanager/alertmanager.yml.bak /etc/alertmanager/alertmanager.yml
# 2. 热加载配置
curl -X POST http://localhost:9090/-/reload
curl -X POST http://localhost:9093/-/reload
# 3. 清除所有静默规则(防止回滚后告警被抑制)
amtool silence expire $(amtool silence query -q) --alertmanager.url=http://localhost:9093
# 4. 验证回滚成功
curl -s http://localhost:9090/api/v1/rules | jq '.data.groups[].file' | sort | uniq
# 确认规则文件时间戳为备份版本
数据与配置备份
自动化备份脚本:
#!/bin/bash
# 文件名:backup_prometheus.sh
# 用途:自动备份 Prometheus 配置和 TSDB 快照
set -e
BACKUP_DIR="/backup/prometheus/$(date +%Y%m%d_%H%M%S)"
mkdir -p "$BACKUP_DIR"
# 1. 备份配置文件
echo "[1/4] 备份配置文件..."
cp -r /etc/prometheus "$BACKUP_DIR/config"
cp -r /etc/alertmanager "$BACKUP_DIR/alertmanager_config"
# 2. 创建 TSDB 快照(不影响运行)
echo "[2/4] 创建 TSDB 快照..."
SNAPSHOT=$(curl -s -XPOST http://localhost:9090/api/v1/admin/tsdb/snapshot | jq -r '.data.name')
echo "快照名称: $SNAPSHOT"
# 3. 复制快照到备份目录
echo "[3/4] 复制快照数据..."
cp -r "/var/lib/prometheus/snapshots/$SNAPSHOT" "$BACKUP_DIR/tsdb_snapshot"
# 4. 清理旧快照(保留最近 3 个)
echo "[4/4] 清理旧快照..."
curl -s -XPOST http://localhost:9090/api/v1/admin/tsdb/clean_tombstones
ls -t /var/lib/prometheus/snapshots/ | tail -n +4 | xargs -I {} rm -rf /var/lib/prometheus/snapshots/{}
# 5. 压缩备份(可选)
tar czf "$BACKUP_DIR.tar.gz" -C /backup/prometheus "$(basename $BACKUP_DIR)"
rm -rf "$BACKUP_DIR"
echo "备份完成: $BACKUP_DIR.tar.gz"
定时备份(crontab):
# 每天凌晨 2 点执行备份
0 2 * * * /usr/local/bin/backup_prometheus.sh >> /var/log/prometheus_backup.log 2>&1
1️⃣1️⃣ 最佳实践
1. 告警规则设计原则
使用 for 持续时间防止抖动:
# ❌ 错误:无 for 持续时间,瞬时抖动会触发告警
- alert: HighCPUUsage
expr: node_cpu_usage > 80
# ✅ 正确:持续 5 分钟才触发
- alert: HighCPUUsage
expr: node_cpu_usage > 80
for: 5m
为告警添加 Runbook 链接:
annotations:
runbook_url: "https://wiki.example.com/runbook/high-cpu-usage"
description: |
节点 {{ $labels.instance }} CPU 使用率超过 80%
当前值: {{ $value | humanizePercentage }}
排查步骤:
1. 登录节点查看 top
2. 检查是否有异常进程
3. 查看应用日志
2. 避免高基数标签
高基数标签示例(❌ 错误):
# ❌ 使用 IP 地址作为标签(每个 IP 都是一个时间序列)
http_requests_total{client_ip="192.168.1.100"}
# ❌ 使用 UUID 作为标签
request_duration_seconds{request_id="550e8400-e29b-41d4-a716-446655440000"}
正确做法(✅):
# ✅ 使用有限值的标签
http_requests_total{method="GET",status="200"}
# ✅ 将高基数数据放到日志系统
# Prometheus 记录计数:http_requests_total
# Loki 记录详细日志:包含 request_id, client_ip
3. 使用 Recording Rules 优化复杂查询
问题:复杂查询导致告警评估耗时过长
# ❌ 每次评估都计算 P95 延迟(耗时)
- alert: HighHTTPLatency
expr: |
histogram_quantile(0.95,
sum(rate(http_request_duration_seconds_bucket[5m])) by (job, le)
) > 2
解决:预计算 Recording Rules
# recording_rules.yml
groups:
- name: http_latency_precompute
interval: 30s
rules:
# 预计算 P95 延迟
- record: job:http_request_duration_seconds:p95
expr: |
histogram_quantile(0.95,
sum(rate(http_request_duration_seconds_bucket[5m])) by (job, le)
)
# 告警规则直接使用预计算结果(快速)
# infrastructure.yml
- alert: HighHTTPLatency
expr: job:http_request_duration_seconds:p95 > 2
for: 10m
4. 配置告警抑制防止风暴
# ✅ 节点宕机时抑制该节点的所有其他告警
inhibit_rules:
- source_match:
alertname: 'NodeDown'
target_match_re:
alertname: '.*'
equal: ['instance']
# ✅ 磁盘只读时抑制磁盘空间告警
- source_match:
alertname: 'DiskReadOnly'
target_match:
alertname: 'DiskSpaceLow'
equal: ['instance', 'device']
5. 定期演练故障场景
每季度执行一次告警演练:
# 场景 1: 模拟节点宕机
ssh target-node 'sudo systemctl stop node_exporter'
# 预期:1 分钟内触发 NodeDown 告警
# 场景 2: 模拟 CPU 高负载
ssh target-node 'stress --cpu 8 --timeout 600s'
# 预期:5 分钟内触发 HighCPUUsage 告警
# 场景 3: 模拟磁盘空间不足
ssh target-node 'dd if=/dev/zero of=/tmp/fillfile bs=1G count=50'
# 预期:5 分钟内触发 DiskSpaceLow 告警
6. 启用 Alertmanager 静默规则(维护窗口)
# 创建静默规则(2 小时维护窗口)
amtool silence add \
alertname=~".*" \
instance=~"192.168.1.10:9100" \
--duration=2h \
--author="ops@example.com" \
--comment="服务器维护窗口" \
--alertmanager.url=http://localhost:9093
# 查看所有静默规则
amtool silence query --alertmanager.url=http://localhost:9093
# 提前结束静默
amtool silence expire <silence_id> --alertmanager.url=http://localhost:9093
7. 使用 Prometheus 联邦集群(大规模场景)
架构:中心 Prometheus 聚合多个边缘 Prometheus
# 中心 Prometheus 配置
scrape_configs:
- job_name: 'federate'
scrape_interval: 60s
honor_labels: true
metrics_path: '/federate'
params:
'match[]':
- '{job="node_exporter"}' # 聚合所有 node_exporter 指标
- '{__name__=~"job:.*"}' # 聚合所有 recording rules
static_configs:
- targets:
- 'edge-prometheus-01:9090'
- 'edge-prometheus-02:9090'
1️⃣2️⃣ FAQ(常见问题)
Q1: Prometheus 和 Zabbix/Nagios 的区别?
A:
- Prometheus:拉模式(Pull)、时间序列数据库、强大的 PromQL、云原生生态
- Zabbix:推模式(Push/Pull)、关系型数据库、传统 IT 基础设施、SNMP/IPMI 支持完善
- Nagios:推模式(Push)、插件式架构、轻量级、告警能力强但查询能力弱
适用场景对比:
- Prometheus:微服务、Kubernetes、云原生应用、需要复杂查询与聚合
- Zabbix:传统 IDC、网络设备、需要自动发现、GUI 配置为主
- Nagios:小规模环境、已有大量自定义脚本、简单健康检查
Q2: 为什么推荐使用 Recording Rules?
A:
- 性能优化:预计算复杂查询,告警评估速度提升 10–100 倍
- 降低 CPU 负载:避免重复计算相同的聚合查询
- 简化告警规则:告警规则更简洁,易于维护
- 联邦集群必需:边缘 Prometheus 预计算,中心 Prometheus 仅聚合结果
示例对比:
# ❌ 无 Recording Rules:每次评估都计算(耗时 500ms)
- alert: HighAPIErrorRate
expr: |
sum(rate(http_requests_total{status=~"5.."}[5m])) by (job)
/ sum(rate(http_requests_total[5m])) by (job) > 0.05
# ✅ 有 Recording Rules:直接查询预计算结果(耗时 5ms)
- record: job:http_requests:error_rate
expr: |
sum(rate(http_requests_total{status=~"5.."}[5m])) by (job)
/ sum(rate(http_requests_total[5m])) by (job)
- alert: HighAPIErrorRate
expr: job:http_requests:error_rate > 0.05
Q3: 如何处理告警疲劳(Alert Fatigue)?
A: 告警疲劳是指告警过多导致团队忽视告警,解决方法:
- 提高告警阈值:确保告警都是需要人工介入的问题
- 增加
for 持续时间:避免瞬时抖动触发告警
- 配置告警分组:同类告警合并为一条通知
- 使用告警抑制:节点宕机时抑制该节点其他告警
- 定期审查告警:每季度检查误报率,调整或删除无效告警
- 区分优先级:P0(立即响应)、P1(1小时内)、P2(工作日处理)
告警优先级定义:
# P0: 服务完全不可用,需立即响应(5分钟内)
severity: critical
# P1: 服务部分受影响,1小时内响应
severity: warning
# P2: 非紧急问题,工作日处理
severity: info
Q4: Prometheus 数据保留多久合适?
A: 取决于使用场景和存储成本:
| 场景 |
推荐保留时间 |
理由 |
| 实时监控 |
7–15 天 |
满足短期故障排查,降低存储成本 |
| 容量规划 |
30–90 天 |
需要观察长期趋势 |
| 合规要求 |
1–3 年 |
需集成远程存储(Thanos/VictoriaMetrics) |
配置示例:
# prometheus.yml
storage:
tsdb:
retention.time: 15d # 保留 15 天
retention.size: 50GB # 或保留最多 50GB(优先)
wal_compression: true # 启用 WAL 压缩
长期存储方案:
- Thanos:对象存储(S3/GCS),支持全局查询、去重、降采样
- VictoriaMetrics:高性能时间序列数据库,压缩比 7:1
- Cortex:多租户架构,适合 SaaS 场景
Q5: 如何监控 Kubernetes 集群?
A: Kubernetes 监控需要多个 Exporter 配合:
# prometheus.yml
scrape_configs:
# 1. Kubernetes API Server(集群级指标)
- job_name: 'kubernetes-apiservers'
kubernetes_sd_configs:
- role: endpoints
relabel_configs:
- source_labels: [__meta_kubernetes_service_name]
action: keep
regex: kubernetes
# 2. Node Exporter(节点级指标)
- job_name: 'kubernetes-nodes'
kubernetes_sd_configs:
- role: node
relabel_configs:
- action: labelmap
regex: __meta_kubernetes_node_label_(.+)
# 3. cAdvisor(容器级指标)
- job_name: 'kubernetes-cadvisor'
kubernetes_sd_configs:
- role: node
relabel_configs:
- target_label: __address__
replacement: kubernetes.default.svc:443
- source_labels: [__meta_kubernetes_node_name]
target_label: __metrics_path__
replacement: /api/v1/nodes/${1}/proxy/metrics/cadvisor
# 4. kube-state-metrics(K8s 对象状态)
- job_name: 'kube-state-metrics'
static_configs:
- targets: ['kube-state-metrics.kube-system.svc:8080']
关键告警规则:
# Pod 重启频繁
- alert: PodRestartingTooOften
expr: rate(kube_pod_container_status_restarts_total[15m]) > 0.1
for: 5m
# Pod Pending 超过 10 分钟
- alert: PodPendingTooLong
expr: kube_pod_status_phase{phase="Pending"} == 1
for: 10m
# Node NotReady
- alert: KubernetesNodeNotReady
expr: kube_node_status_condition{condition="Ready",status="true"} == 0
for: 5m
Q6: PromQL 查询为什么会超时?
A: 常见原因与解决方法:
| 原因 |
诊断方法 |
解决方案 |
| 查询范围过大 |
检查时间范围([30d]) |
缩小范围到 [5m] – [1h] |
| 高基数聚合 |
检查标签基数 |
删除高基数标签,使用 recording rules |
| 无索引标签查询 |
使用 {__name__=~".*"} |
添加具体的指标名称或 job 标签 |
| 正则表达式复杂 |
使用 {label=~".*complex.*"} |
简化正则,使用多个简单查询 |
查询优化示例:
# ❌ 慢查询:无索引标签,查询所有时间序列
{__name__=~".*request.*"}
# ✅ 快查询:指定 job 标签
{job="api_server", __name__=~".*request.*"}
# ❌ 慢查询:高基数聚合
sum(rate(http_requests_total[5m])) by (url) # url 有 10000+ 个值
# ✅ 快查询:低基数聚合
sum(rate(http_requests_total[5m])) by (method, status) # 仅 20 个组合
Q7: 如何避免 Prometheus 单点故障?
A: 高可用方案:
方案 1: 主备模式(简单)
# 部署两台完全相同配置的 Prometheus
# 优点:简单可靠
# 缺点:数据冗余,成本高
# Alertmanager 配置去重
alerting:
alertmanagers:
- static_configs:
- targets:
- 'alertmanager-01:9093'
- 'alertmanager-02:9093'
方案 2: 联邦集群(推荐)
# 边缘 Prometheus 负责采集
# 中心 Prometheus 聚合数据
# 优点:分布式、可扩展
# 缺点:架构复杂
方案 3: Thanos/Cortex(企业级)
- 长期存储到对象存储(S3/GCS)
- 多副本保证高可用
- 全局查询视图
1️⃣3️⃣ 附录:关键脚本
一键部署脚本(RHEL/CentOS 8+)
#!/bin/bash
# 文件名:deploy_prometheus_stack.sh
# 用途:自动化部署 Prometheus + Alertmanager + Node Exporter
set -e # 遇到错误立即退出
# ============ 配置变量 ============
PROMETHEUS_VERSION="2.48.0"
ALERTMANAGER_VERSION="0.26.0"
NODE_EXPORTER_VERSION="1.6.1"
PROMETHEUS_USER="prometheus"
INSTALL_DIR="/opt/prometheus"
DATA_DIR="/var/lib/prometheus"
CONFIG_DIR="/etc/prometheus"
# ============ 前置检查 ============
echo "[1/8] 系统环境检查..."
if ! grep -qE 'CentOS|Red Hat' /etc/os-release; then
echo "错误:仅支持 RHEL/CentOS 系统"
exit 1
fi
if [[ $EUID -ne 0 ]]; then
echo "错误:必须以 root 用户运行此脚本"
exit 1
fi
# ============ 创建用户 ============
echo "[2/8] 创建 prometheus 用户..."
id -u $PROMETHEUS_USER &&>/dev/null || useradd --no-create-home --shell /bin/false $PROMETHEUS_USER
# ============ 下载并安装 Prometheus ============
echo "[3/8] 下载 Prometheus ${PROMETHEUS_VERSION}..."
cd /tmp
wget -q https://github.com/prometheus/prometheus/releases/download/v${PROMETHEUS_VERSION}/prometheus-${PROMETHEUS_VERSION}.linux-amd64.tar.gz
tar xzf prometheus-${PROMETHEUS_VERSION}.linux-amd64.tar.gz
echo "安装 Prometheus..."
mkdir -p $INSTALL_DIR $DATA_DIR $CONFIG_DIR/rules
cp prometheus-${PROMETHEUS_VERSION}.linux-amd64/prometheus $INSTALL_DIR/
cp prometheus-${PROMETHEUS_VERSION}.linux-amd64/promtool $INSTALL_DIR/
cp -r prometheus-${PROMETHEUS_VERSION}.linux-amd64/consoles $CONFIG_DIR/
cp -r prometheus-${PROMETHEUS_VERSION}.linux-amd64/console_libraries $CONFIG_DIR/
chown -R $PROMETHEUS_USER:$PROMETHEUS_USER $INSTALL_DIR $DATA_DIR $CONFIG_DIR
# ============ 创建 Prometheus 配置 ============
echo "[4/8] 创建 Prometheus 配置文件..."
cat > $CONFIG_DIR/prometheus.yml <<'EOF'
global:
scrape_interval: 15s
evaluation_interval: 15s
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_exporter'
static_configs:
- targets: ['localhost:9100']
EOF
chown $PROMETHEUS_USER:$PROMETHEUS_USER $CONFIG_DIR/prometheus.yml
# ============ 创建 systemd 服务 ============
echo "[5/8] 创建 Prometheus systemd 服务..."
cat > /etc/systemd/system/prometheus.service <<EOF
[Unit]
Description=Prometheus
Wants=network-online.target
After=network-online.target
[Service]
User=$PROMETHEUS_USER
Group=$PROMETHEUS_USER
Type=simple
ExecStart=$INSTALL_DIR/prometheus \
--config.file=$CONFIG_DIR/prometheus.yml \
--storage.tsdb.path=$DATA_DIR \
--storage.tsdb.retention.time=15d \
--storage.tsdb.wal-compression \
--web.console.templates=$CONFIG_DIR/consoles \
--web.console.libraries=$CONFIG_DIR/console_libraries \
--web.enable-lifecycle \
--web.enable-admin-api
Restart=on-failure
[Install]
WantedBy=multi-user.target
EOF
# ============ 下载并安装 Alertmanager ============
echo "[6/8] 下载 Alertmanager ${ALERTMANAGER_VERSION}..."
cd /tmp
wget -q https://github.com/prometheus/alertmanager/releases/download/v${ALERTMANAGER_VERSION}/alertmanager-${ALERTMANAGER_VERSION}.linux-amd64.tar.gz
tar xzf alertmanager-${ALERTMANAGER_VERSION}.linux-amd64.tar.gz
echo "安装 Alertmanager..."
mkdir -p /etc/alertmanager /var/lib/alertmanager
cp alertmanager-${ALERTMANAGER_VERSION}.linux-amd64/alertmanager $INSTALL_DIR/
cp alertmanager-${ALERTMANAGER_VERSION}.linux-amd64/amtool $INSTALL_DIR/
# 创建 Alertmanager 配置
cat > /etc/alertmanager/alertmanager.yml <<'EOF'
global:
resolve_timeout: 5m
route:
receiver: 'default-email'
group_by: ['alertname', 'cluster']
group_wait: 10s
group_interval: 10s
repeat_interval: 12h
receivers:
- name: 'default-email'
email_configs:
- to: 'ops-team@example.com'
from: 'alerts@example.com'
smarthost: 'smtp.example.com:587'
auth_username: 'alerts@example.com'
auth_password: 'your_password'
EOF
chown -R $PROMETHEUS_USER:$PROMETHEUS_USER /etc/alertmanager /var/lib/alertmanager
# 创建 Alertmanager systemd 服务
cat > /etc/systemd/system/alertmanager.service <<EOF
[Unit]
Description=Alertmanager
Wants=network-online.target
After=network-online.target
[Service]
User=$PROMETHEUS_USER
Group=$PROMETHEUS_USER
Type=simple
ExecStart=$INSTALL_DIR/alertmanager \
--config.file=/etc/alertmanager/alertmanager.yml \
--storage.path=/var/lib/alertmanager \
--web.listen-address=:9093
Restart=on-failure
[Install]
WantedBy=multi-user.target
EOF
# ============ 下载并安装 Node Exporter ============
echo "[7/8] 下载 Node Exporter ${NODE_EXPORTER_VERSION}..."
cd /tmp
wget -q https://github.com/prometheus/node_exporter/releases/download/v${NODE_EXPORTER_VERSION}/node_exporter-${NODE_EXPORTER_VERSION}.linux-amd64.tar.gz
tar xzf node_exporter-${NODE_EXPORTER_VERSION}.linux-amd64.tar.gz
echo "安装 Node Exporter..."
cp node_exporter-${NODE_EXPORTER_VERSION}.linux-amd64/node_exporter $INSTALL_DIR/
# 创建 Node Exporter systemd 服务
cat > /etc/systemd/system/node_exporter.service <<EOF
[Unit]
Description=Node Exporter
After=network.target
[Service]
User=$PROMETHEUS_USER
Group=$PROMETHEUS_USER
Type=simple
ExecStart=$INSTALL_DIR/node_exporter \
--collector.systemd \
--collector.processes \
--collector.tcpstat
Restart=on-failure
[Install]
WantedBy=multi-user.target
EOF
# ============ 启动所有服务 ============
echo "[8/8] 启动服务..."
systemctl daemon-reload
systemctl enable --now prometheus alertmanager node_exporter
# 等待服务启动
sleep 5
# ============ 验证安装 ============
echo ""
echo "============ 安装完成 ============"
echo "Prometheus: http://$(hostname -I | awk '{print $1}'):9090"
echo "Alertmanager: http://$(hostname -I | awk '{print $1}'):9093"
echo "Node Exporter: http://$(hostname -I | awk '{print $1}'):9100"
echo ""
echo "验证服务状态:"
systemctl is-active prometheus && echo "✓ Prometheus 运行中" || echo "✗ Prometheus 启动失败"
systemctl is-active alertmanager && echo "✓ Alertmanager 运行中" || echo "✗ Alertmanager 启动失败"
systemctl is-active node_exporter && echo "✓ Node Exporter 运行中" || echo "✗ Node Exporter 启动失败"
echo ""
echo "下一步:"
echo "1. 编辑 /etc/prometheus/rules/ 下的告警规则"
echo "2. 编辑 /etc/alertmanager/alertmanager.yml 配置通知渠道"
echo "3. 执行 'curl -X POST http://localhost:9090/-/reload' 热加载配置"
使用方法:
# 下载脚本
curl -O https://your-repo.com/deploy_prometheus_stack.sh
chmod +x deploy_prometheus_stack.sh
# 执行安装
sudo ./deploy_prometheus_stack.sh
健康检查脚本
#!/bin/bash
# 文件名:check_prometheus_health.sh
# 用途:全面检查 Prometheus 栈健康状态
set -e
PROMETHEUS_URL="http://localhost:9090"
ALERTMANAGER_URL="http://localhost:9093"
echo "============ Prometheus 健康检查 ============"
# 1. 检查服务状态
echo "[1/7] 检查服务状态..."
systemctl is-active prometheus && echo "✓ Prometheus 运行中" || echo "✗ Prometheus 未运行"
systemctl is-active alertmanager && echo "✓ Alertmanager 运行中" || echo "✗ Alertmanager 未运行"
systemctl is-active node_exporter && echo "✓ Node Exporter 运行中" || echo "✗ Node Exporter 未运行"
# 2. 检查端口监听
echo ""
echo "[2/7] 检查端口监听..."
ss -tulnp | grep :9090 && echo "✓ Prometheus 端口 9090 监听中" || echo "✗ Prometheus 端口 9090 未监听"
ss -tulnp | grep :9093 && echo "✓ Alertmanager 端口 9093 监听中" || echo "✗ Alertmanager 端口 9093 未监听"
ss -tulnp | grep :9100 && echo "✓ Node Exporter 端口 9100 监听中" || echo "✗ Node Exporter 端口 9100 未监听"
# 3. 检查目标健康状态
echo ""
echo "[3/7] 检查监控目标..."
DOWN_TARGETS=$(curl -s $PROMETHEUS_URL/api/v1/targets | jq -r '.data.activeTargets[] | select(.health != "up") | "\(.job)/\(.instance)"')
if [ -z "$DOWN_TARGETS" ]; then
echo "✓ 所有监控目标正常"
else
echo "✗ 以下目标不可达:"
echo "$DOWN_TARGETS"
fi
# 4. 检查告警规则错误
echo ""
echo "[4/7] 检查告警规则..."
RULE_ERRORS=$(curl -s $PROMETHEUS_URL/api/v1/rules | jq -r '.data.groups[].rules[] | select(.lastError != null) | "\(.name): \(.lastError)"')
if [ -z "$RULE_ERRORS" ]; then
echo "✓ 所有告警规则正常"
else
echo "✗ 以下规则有错误:"
echo "$RULE_ERRORS"
fi
# 5. 检查存储空间
echo ""
echo "[5/7] 检查存储空间..."
STORAGE_USAGE=$(df -h /var/lib/prometheus | awk 'NR==2 {print $5}' | sed 's/%//')
if [ $STORAGE_USAGE -lt 80 ]; then
echo "✓ 存储空间充足(已使用 ${STORAGE_USAGE}%)"
else
echo "⚠ 存储空间不足(已使用 ${STORAGE_USAGE}%)"
fi
# 6. 检查 TSDB 状态
echo ""
echo "[6/7] 检查 TSDB 状态..."
NUM_SERIES=$(curl -s $PROMETHEUS_URL/api/v1/status/tsdb | jq -r '.data.numSeries')
echo "活跃时间序列数: $NUM_SERIES"
if [ $NUM_SERIES -lt 100000 ]; then
echo "✓ 时间序列数量正常"
else
echo "⚠ 时间序列数量过多,可能存在高基数标签"
fi
# 7. 检查当前告警
echo ""
echo "[7/7] 检查当前告警..."
ACTIVE_ALERTS=$(curl -s $ALERTMANAGER_URL/api/v2/alerts | jq -r '.[] | select(.status.state == "active") | "\(.labels.alertname)"')
if [ -z "$ACTIVE_ALERTS" ]; then
echo "✓ 无活跃告警"
else
echo "⚠ 当前活跃告警:"
echo "$ACTIVE_ALERTS"
fi
echo ""
echo "============ 检查完成 ============"
高基数标签检测脚本
#!/bin/bash
# 文件名:detect_high_cardinality.sh
# 用途:检测高基数标签
PROMETHEUS_URL="http://localhost:9090"
THRESHOLD=1000 # 时间序列数超过 1000 的指标视为高基数
echo "============ 高基数标签检测 ============"
echo "阈值: $THRESHOLD 时间序列"
echo ""
# 获取所有指标名称
METRICS=$(curl -s $PROMETHEUS_URL/api/v1/label/__name__/values | jq -r '.data[]')
# 检查每个指标的时间序列数量
for metric in $METRICS; do
COUNT=$(curl -s "$PROMETHEUS_URL/api/v1/series?match[]=$metric" | jq '.data | length')
if [ $COUNT -gt $THRESHOLD ]; then
echo "⚠ 高基数指标: $metric ($COUNT 个时间序列)"
# 分析标签基数
echo " 标签基数分布:"
curl -s "$PROMETHEUS_URL/api/v1/series?match[]=$metric" | jq -r '.data[].{} | keys[]' | sort | uniq -c | sort -rn | head -n 5 | while read count label; do
echo " $label: $count 个不同值"
done
echo ""
fi
done
1️⃣4️⃣ 扩展阅读
官方文档:
深入技术博客:
社区资源:
最佳实践指南: