3.12 Linux 系统监控与告警方案

预计阅读时间:13 分钟

📖 目录

学习目标

学完本章后,你将能够:

  • 使用命令行工具实时监控 CPU、内存、磁盘、网络四大维度
  • 理解 Prometheus + Grafana 监控架构的核心组件和工作流程
  • 编写自定义监控脚本并集成到告警体系
  • 定义 SLO/SLI 并基于 Error Budget 设计告警规则
  • 配置 Alertmanager 告警路由与通知

核心知识

  • 监控四维度——CPU(使用率/负载)、内存(可用/交换)、磁盘(使用率/I/O)、网络(带宽/连接数)
  • Prometheus——开源的监控和告警工具,通过拉取(Pull)模式采集指标,使用 PromQL 查询
  • Node Exporter——Prometheus 的官方主机指标采集器,暴露 CPU、内存、磁盘等系统指标
  • Grafana——指标可视化平台,支持 Prometheus、InfluxDB、Elasticsearch 等多种数据源
  • SLI(服务级别指标)——衡量服务质量的具体指标(如请求成功率、P99 延迟)
  • SLO(服务级别目标)——SLI 的目标值(如"月度请求成功率 ≥ 99.9%")
  • Error Budget(错误预算)——SLO 允许的故障时间,超出后应放缓新功能上线
  • Alertmanager——Prometheus 生态的告警管理组件,负责去重、分组、路由和静默

知识关联

原理讲解

1. 命令行实时监控

htop / btop / glances              # 综合仪表盘
# 输出: (进入交互式仪表盘,按 q 退出)
top / mpstat -P ALL 1 / sar -u 1 10  # CPU
# 输出: (CPU 实时监控,按 q 退出)
free -h / vmstat 1 / sar -r 1 10      # 内存
# 输出:                total        used        free
# 输出: Mem:            31G         8.2G          16G
df -h / iostat -x 1 / iotop            # 磁盘
# 输出: Filesystem      Size  Used Avail Use% Mounted on
# 输出: /dev/sda2       931G  234G  697G  26% /
iftop / nethogs / sar -n DEV 1 10      # 网络
ss -s                                    # Socket 统计
# 输出: Total: 345 (kernel 0)
# 输出: TCP:   12 (estab 8, closed 0, orphaned 0, synrecv 0, timewait 0/0)

2. Prometheus + Grafana

架构:Prometheus(采集+存储)→ Node Exporter(主机指标)→ Grafana(可视化+告警)。

为什么推荐 Prometheus 而不是 Zabbix?

Zabbix 是老牌的企业级监控工具,功能全面但架构较重(需要数据库后端、复杂的模板系统)。Prometheus 是云原生时代的监控标准,核心优势在于:

  • Pull 模型:Prometheus 主动从目标拉取指标,而不是目标主动推送。好处是:监控目标不需要知道 Prometheus 的地址,配置简单;Prometheus 可以主动探测目标是否存活;不存在推送失败导致数据丢失的问题。
  • 服务发现:Prometheus 原生支持 Kubernetes、Consul、DNS 等服务发现机制,自动发现新实例并开始采集。Zabbix 需要手动注册主机。
  • PromQL:Prometheus 的查询语言 PromQL 功能强大且直观,可以实时计算复杂的聚合指标。Zabbix 的查询能力相对有限。
  • 云原生生态:Prometheus 是 CNCF 毕业项目,与 Kubernetes、Grafana、Alertmanager 无缝集成。Zabbix 更适合传统基础设施。
  • 轻量:Prometheus 单二进制部署,无外部数据库依赖。Zabbix 需要 MySQL/PostgreSQL + 前端 + Agent + Server 多组件。

选型建议:云原生/Kubernetes 环境用 Prometheus;传统企业环境(大量物理服务器、需要现成模板)可以考虑 Zabbix。新项目默认选 Prometheus + Grafana 是业界共识。

为什么监控要做 Pull 而不是 Push?

Push 模式(如 StatsD、InfluxDB Telegraf)由被监控端主动上报指标,Pull 模式(Prometheus)由监控端主动拉取。Pull 的核心优势是解耦:被监控端不需要知道监控服务器的地址,只需暴露一个 HTTP 端点。这意味着你可以随时更换监控后端而不修改任何应用代码。另外,Pull 模式下监控端可以主动探测目标是否存活——如果拉取失败,说明目标已经挂了。Push 模式下,目标挂了就停止推送,监控端可能很久才发现。

3. 自定义监控脚本

#!/bin/bash
CPU=$(top -bn1 | grep "Cpu(s)" | awk '{print $2}' | cut -d'%' -f1)
MEM=$(free | grep Mem | awk '{print $3/$2 * 100.0}')
if (( $(echo "$CPU > 90" | bc -l) )); then echo "WARNING: CPU ${CPU}%"; fi
if (( $(echo "$MEM > 90" | bc -l) )); then echo "WARNING: Memory ${MEM}%"; fi
df -h | awk 'NR>1 {if ($5+0 > 85) print "WARNING: Disk " $6 " is " $5 " full"}'
for svc in nginx mysql docker; do
    systemctl is-active --quiet $svc || echo "ERROR: $svc is down"
done

4. Grafana 面板设计

好的面板设计让故障排查时间从小时级降到分钟级。核心原则是"一图一指标,关键信息一目了然"。

# Grafana 面板 JSON 模型核心结构
{
  "title": "CPU 使用率",
  "type": "timeseries",
  "datasource": "Prometheus",
  "targets": [{
    "expr": "100 - (avg by(instance) (rate(node_cpu_seconds_total{mode='idle'}[5m])) * 100)",
    "legendFormat": "{{ instance }}"
  }],
  "fieldConfig": {
    "defaults": {
      "unit": "percent",
      "thresholds": {
        "mode": "absolute",
        "steps": [
          {"color": "green", "value": null},
          {"color": "yellow", "value": 80},
          {"color": "red", "value": 95}
        ]
      }
    }
  }
}
# 变量模板(让面板在不同环境间切换)
# Grafana Settings → Variables → Add variable
# Name: env
# Type: Query
# Query: label_values(node_uname_info, env)
# 在 PromQL 中使用: $env 变量

# 推荐的面板布局
# 行1: CPU + 内存 + 磁盘(TimeSeries 面板,每个一行)
# 行2: 网络速率(TimeSeries,分进/出双向)
# 行3: 服务状态(Stat 面板,绿色=正常/红色=异常)
# 行4: 进程列表(Table 面板,显示 CPU/MEM Top N)
💡 面板类型选择 TimeSeries:展示指标随时间变化(CPU、内存、网络)。Stat:展示当前值(服务状态、磁盘用量百分比)。Table:展示列表数据(Top N 进程、错误日志)。Bar Gauge:直观展示阈值(磁盘/内存使用率)。

5. 告警规则编写

Prometheus 告警分两种:记录规则(recording rules) 提前聚合常用指标,告警规则(alerting rules) 触发告警通知。

# /etc/prometheus/rules/alerts.yml
groups:
  - name: node_alerts
    interval: 30s
    rules:
      # 记录规则:预计算 CPU 使用率(提高查询性能)
      - record: node:cpu_usage:avg5m
        expr: |
          100 - (avg by(instance) (rate(node_cpu_seconds_total{mode='idle'}[5m])) * 100)

      # 告警规则:CPU 持续高负载
      - alert: HighCpuUsage
        expr: node:cpu_usage:avg5m > 90
        for: 10m
        labels:
          severity: critical
        annotations:
          summary: "{{ $labels.instance }} CPU 使用率 > 90%"
          description: "{{ $labels.instance }} CPU 已达 {{ $value | humanizePercentage }},持续超过 10 分钟"

      # 告警规则:磁盘即将满
      - alert: DiskSpaceLow
        expr: |
          (node_filesystem_avail_bytes{fstype!="", mountpoint!="/boot"} /
           node_filesystem_size_bytes{fstype!="", mountpoint!="/boot"}) * 100 < 15
        for: 5m
        labels:
          severity: warning
        annotations:
          summary: "{{ $labels.mountpoint }} 磁盘空间不足 15%"

      # 告警规则:节点不可达
      - alert: InstanceDown
        expr: up == 0
        for: 1m
        labels:
          severity: critical
        annotations:
          summary: "实例 {{ $labels.instance }} 已下线"

  - name: service_alerts
    rules:
      # 服务质量告警:HTTP 错误率
      - alert: HighHttpErrorRate
        expr: |
          sum(rate(nginx_http_requests_total{status=~"5.."}[5m])) /
          sum(rate(nginx_http_requests_total[5m])) * 100 > 5
        for: 5m
        labels:
          severity: critical
        annotations:
          summary: "HTTP 5xx 错误率超过 5%"
# 检查告警规则语法
promtool check rules /etc/prometheus/rules/alerts.yml
# 输出: Checking /etc/prometheus/rules/alerts.yml
# 输出:   SUCCESS: 5 rules found

# 查看当前触发的告警
kubectl port-forward svc/prometheus-k8s 9090:9090 -n monitoring
# 输出: Forwarding from 127.0.0.1:9090 -> 9090
# 打开: http://localhost:9090/alerts

6. SLO / SLI 定义

SLO(Service Level Objective)是服务的可靠性目标,SLI(Service Level Indicator)是衡量这一目标的具体指标。没有 SLO 的监控就是"不知道什么算好什么算坏"。

服务SLISLO 目标
Web API请求成功率(非 5xx)99.9%(月度)
API 延迟P99 请求延迟< 500ms(月度)
数据库查询成功率99.95%(月度)
CDN缓存命中率≥ 90%(月度)
# Error Budget 计算:SLO 允许的"犯错时间"
# 99.9% SLO → 月度 Error Budget = 30天 × 24小时 × 60分钟 × 0.001 = 43.2 分钟
# 当前 Error Budget 消耗 = 停机时间 / 总时间 × 1000000 (单位:ppm)

# PromQL 计算 Error Budget
# 过去 30 天的请求成功率(用于计算 error budget 消耗)
sum(rate(http_requests_total{status!~"5.."}[30d])) /
sum(rate(http_requests_total[30d])) * 100

# 用 Burn Rate 判断是否需要立即响应
# 如果错误率突然高出 SLO 目标的 10 倍以上 → 需要立即响应
# < 3x burn rate → 可以等到工作时间处理
⚠️ 不要监控一切 选择 3-5 个核心 SLI 作为 SLO 告警。每个多余的指标都是噪音。一条精心设计的 SLO 告警胜过 100 条"CPU > 80%"的阈值告警。

7. 告警路由与静默

# Alertmanager 配置文件:/etc/alertmanager/alertmanager.yml
route:
  receiver: 'default'
  group_by: ['alertname', 'cluster']  # 按告警名+集群分组
  group_wait: 30s                     # 组内第一条告警等待聚合
  group_interval: 5m                  # 组内新告警的发送间隔
  repeat_interval: 4h                 # 已发送告警的重复间隔

  # 路由树:不同级别走不同通知渠道
  routes:
    - receiver: 'critical-pager'
      match:
        severity: critical
      repeat_interval: 30m            # 关键告警每 30 分钟重发

    - receiver: 'warning-email'
      match:
        severity: warning
      repeat_interval: 4h

    - receiver: 'team-db'
      match:
        service: database
      repeat_interval: 1h

receivers:
  - name: 'critical-pager'
    webhook_configs:
      - url: 'https://hooks.example.com/pagerduty'

  - name: 'warning-email'
    email_configs:
      - to: 'team@example.com'
        headers:
          subject: '{{ .GroupLabels.alertname }}'

  - name: 'team-db'
    webhook_configs:
      - url: 'http://db-team-bot:8080/alert'

# 静默规则(Alertmanager WebUI):维护窗口关闭告警
# 或者通过 amtool 命令行
amtool silence add alertname=HighCpuUsage --duration=2h --comment="维护窗口 2026-07-30 14:00-16:00"
# 输出: silence "silence-xxxxx" created
# 告警分级策略
# P0 (Critical) — 服务完全不可用 → 立即通知 Oncall → 15 分钟响应
# P1 (Warning)  — 服务质量下降 → 工作时间处理 → 2 小时响应
# P2 (Info)     — 需要关注但非紧急 → 记录到工单系统

# Alertmanager WebUI
kubectl port-forward svc/alertmanager-main 9093:9093 -n monitoring
# 输出: Forwarding from 127.0.0.1:9093 -> 9093
# 打开: http://localhost:9093 → 查看/管理告警

示例代码

以下是一套完整的 Node Exporter 文本采集器脚本,将自定义指标暴露给 Prometheus:

#!/bin/bash
# /usr/local/bin/custom_metrics.sh
# Node Exporter textfile collector — 每 5 分钟由 cron 调用
# 输出到 /var/lib/node_exporter/textfile/custom.prom

OUTPUT_DIR="/var/lib/node_exporter/textfile"
mkdir -p "$OUTPUT_DIR"

# 自定义服务健康检查
for svc in nginx mysql docker; do
    systemctl is-active --quiet "$svc" \
        && echo "custom_service_up{service=\"$svc\"} 1" \
        || echo "custom_service_up{service=\"$svc\"} 0"
done > "$OUTPUT_DIR/custom.prom.$$"

mv "$OUTPUT_DIR/custom.prom.$$" "$OUTPUT_DIR/custom.prom"
# 输出:
# custom_service_up{service="nginx"} 1
# custom_service_up{service="mysql"} 0
# custom_service_up{service="docker"} 1
# cron 配置(每 5 分钟执行)
*/5 * * * * /usr/local/bin/custom_metrics.sh

# 验证 Prometheus 是否采集到
curl -s http://localhost:9090/api/v1/query?query=custom_service_up | jq .
# 输出: {
# 输出:   "status": "success",
# 输出:   "data": {
# 输出:     "result": [
# 输出:       {"metric": {"__name__": "custom_service_up"}, "value": [1785393000, "1"]}
# 输出:     ]
# 输出:   }
# 输出: }

常见错误

错误表现根因正确做法
Grafana 面板显示 "No data"Prometheus 未能从 Node Exporter 采集到数据检查 systemctl status prometheus prometheus-node-exporter(Debian 包的服务名是 prometheus-node-exporter,不是 node_exporter),确认 prometheus.yml 中的 target 地址正确
告警规则从未触发过阈值设置不合理(过高或过低)或 PromQL 语法错误在 Prometheus WebUI 的 Graph 页面手动执行告警 PromQL 验证表达式;用 promtool check rules 检查语法
告警太多,团队麻木没有区分告警级别,CPU>80% 和 服务宕机走同一通道按 severity 路由,P0 走即时通知(电话/短信),P1 走邮件,P2 走工单系统
磁盘监控没有覆盖关键挂载点node_filesystem_* 默认包含 /boot/dev 等非关键路径用 PromQL 过滤:node_filesystem_avail_bytes{mountpoint=~"/|/data|/var"}
Prometheus 内存 OOM采集指标基数过大且没有合理设置存储限制设置 storage.tsdb.retention.time=15dstorage.tsdb.retention.size=50GB

最佳实践

实践原理示例
先设 SLO,再写告警没有目标的监控无法判断优先级定义"API P99 延迟 < 500ms"为 SLO,用 Error Budget 消耗速率决定告警级别
用 USE 和 RED 方法选择指标避免监控一切:USE=利用率/饱和度/错误数,RED=速率/错误/延迟USE 适合基础设施(CPU 利用率+排队数+硬件错误),RED 适合服务(请求率+错误率+延迟)
告警要有 Actionable 信息收到告警的人应知道做什么,而非只是一个警告告警描述包含:当前值、阈值、持续时长、Runbook 链接
定期 Review 告警规则减少噪音告警,保持告警体系健康每季度统计告警触发率,沉默/合并/删除从未触发或总是触发的规则
仪表盘设计遵循"一图一指标"混合多个指标在一张图上难以快速解读CPU 一张图、内存一张图,而非将 CPU/内存/网络混在一个 Panel

练习题

  1. (概念)监控的四大维度是什么?每个维度至少列出两个常用的命令行排查工具。
  2. (概念)什么是 SLO 和 Error Budget?如果一个服务的 SLO 是 99.9%,月度 Error Budget 是多少分钟?
  3. (实操)安装 htopsysstatiotop,运行 stress 命令(需安装)模拟 CPU 压力:stress --cpu 4 --timeout 60,同时用 htopmpstat -P ALL 1 观察 CPU 变化。
  4. (实操)编写一个简单的 Node Exporter 文本文件采集:在 /var/lib/node_exporter/textfile/ 目录下创建一个脚本,每 5 分钟输出自定义指标(如 custom_up 1),在 Prometheus 中验证该指标能被采集到。
  5. (🔍 挑战)在本地或测试环境部署 Prometheus + Node Exporter + Grafana,连接到任意一台服务器。设计一个 SLO 为"磁盘使用率 < 80%"的告警规则,配置 Alertmanager 发送邮件通知。然后模拟磁盘使用率超过 80%,验证告警链路的完整流程(采集→规则评估→告警触发→通知到达)。
点击查看答案
  1. (概念)四大维度:CPU(topmpstathtop)、内存(freevmstat)、磁盘 I/O(iostatiotop)、网络(ssiftopnload)。
  2. (概念)SLO(服务等级目标)是期望的可靠性目标(如 99.9% 可用性);Error Budget(错误预算)是 SLO 允许的不可用时间。99.9% 的月度 Error Budget = 30 天 × 24 小时 × 60 分钟 × 0.1% ≈ 43.2 分钟。超过 Error Budget 意味着应暂缓发布新功能,优先提升可靠性。
  3. (实操)sudo apt install htop sysstat iotop stressstress --cpu 4 --timeout 60 会创建 4 个工作进程占满 CPU。同时 htop 显示 4 个 CPU 核心接近 100%,mpstat -P ALL 1 显示每个核心的 %usr 飙升。注意 stress 命令可能不在默认源中,需 sudo apt install stress
  4. (实操)创建脚本 /usr/local/bin/custom-metrics.sh#!/bin/bash echo "custom_metric_up $(date +%s)" > /var/lib/node_exporter/textfile/custom.prom。chmod +x 后在 crontab 中设置 */5 * * * * /usr/local/bin/custom-metrics.sh。Prometheus target 页面(/targets)验证 node 的 textfile collector 已采集该指标。
  5. (🔍 挑战)部署步骤:① docker-compose.yml 定义 Prometheus + Node Exporter + Grafana + Alertmanager;② 告警规则示例:ALERT DiskUsageHigh IF node_filesystem_avail_bytes{mountpoint="/"} / node_filesystem_size_bytes{mountpoint="/"} < 0.2 FOR 5m;③ Alertmanager 配置 email 接收者;④ 模拟:dd if=/dev/zero of=/tmp/bigfile bs=1M count=10240 填充磁盘。验证 Grafana Alerting 页面和邮件收件箱。

学习检查点

学完本章后,请检验自己是否掌握以下内容:

检查项自测问题验证方法
概念理解能用自己的话解释监控系统的架构和组件作用尝试向他人讲解
命令操作能不查文档完成 Prometheus 配置、Grafana 面板创建在终端实际执行
原理掌握能说出 Prometheus 的拉取模型和时序数据库原理画出流程图
故障排查能独立排查监控数据丢失、告警不触发、面板显示异常模拟故障并修复
最佳实践能说明为什么需要设置合理的告警阈值和通知渠道对比不同方案

本章总结

监控是运维的"眼睛"。从命令行快速排查(topfreedfss)到 Prometheus + Grafana 集中监控,再到基于 SLO 的告警体系,三层架构覆盖了"问题发生了→怎么快速发现→怎么确定严重程度→怎么通知对的人"全流程。好的监控不是指标越多越好,而是选择正确的 SLI、设定合理的 SLO、编写 actionable 的告警规则。

速查表

命令/组件用途
htop / btop / glances综合系统监控仪表盘
mpstat -P ALL 1按 CPU 核心查看使用率
free -h / vmstat 1内存使用情况
iostat -x 1 / iotop磁盘 I/O 监控
ss -tlnp / ss -sSocket 统计和监听端口
Prometheus指标采集和 PromQL 查询引擎
Node Exporter主机指标暴露(CPU/内存/磁盘等)
Grafana仪表盘可视化和告警
Alertmanager告警去重、分组、路由、静默
promtool check rules检查告警规则语法

学习路径建议

延伸阅读

常见问题

Prometheus pull 模式有什么优缺点?
优点:监控中心主动拉取数据,天然知道目标是否在线,无需业务组件直接推送。缺点:目标地址需要静态配置或服务发现,防火墙需要允许 Prometheus 连接所有目标,大规模的 Pushgateway 使用场景受限。哪些场景用 Push:短命任务(cron job)、批处理作业。
Grafana 仪表盘有推荐的模板吗?
Grafana Dashboards 官网(https://grafana.com/grafana/dashboards)有海量分享模板。推荐:Node Exporter Full(1860 号)、Linux Server Dashboard(11074)、Prometheus 2.0 Stats。导入后用 JSON model 调整数据源和变量即可。
USE 和 RED 方法论分别适用什么场景?
USE(Utilization、Saturation、Errors)适用于基础设施资源:CPU、内存、磁盘、网络。RED(Rate、Error、Duration)适用于服务层面:请求速率、错误率、响应时间。黄金信号四大指标:延迟、流量、错误数、饱和度。监控体系应该两者兼顾。
↑ 回到顶部