服务器资源监控告警设置

结论:服务器资源监控告警设置的核心是「选对指标、定对阈值、分对级别、收敛到位」。CPU、内存、磁盘、IO、网络、服务存活按 P0~P3 分级,持续 5~10 分钟超阈值才触发,再配合抑制与静默规则避免告警疲劳。

服务器「挂了没发现」和「告警太吵被屏蔽」,是运维最常踩的两个极端。前者往往是因为只监控了「主机是否在线」,而忽略了磁盘将满、证书将过期、数据库连接池打满这类慢变量;后者则是因为把所有指标都设成「一超阈值就打电话」,最后值班人员把告警群静音,等于没有监控。本文给出一套可直接落地的服务器监控告警设置方案:指标清单、阈值建议、分级标准、Prometheus Alertmanager 配置、收敛抑制与值班升级,全部基于 Prometheus 2.53 + Alertmanager 0.27(截至 2026 年主流版本)。

服务器资源监控告警要监控哪些指标?

先给结论:一台服务器只需要盯住 7 类指标——CPU、内存、磁盘空间、磁盘 IO、网络、服务存活、证书到期。其余指标(如 TCP 连接数、进程数、文件句柄)作为排查时的辅助数据入库即可,不直接配告警,否则告警数量会失控。

告警指标选取与建议阈值表

指标类别推荐 PromQL 表达式(node_exporter)建议阈值持续时长建议级别
CPU 使用率100 - (avg by(instance)(rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100)> 85%10mP2
CPU 负载node_load5 / count by(instance)(node_cpu_seconds_total{mode="idle"})> 核数 × 1.510mP2
内存使用率100 * (1 - node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes)> 90%10mP2
磁盘使用率`100 * (1 - node_filesystem_avail_bytes{fstype=~"ext4xfs"} / node_filesystem_size_bytes{fstype=~"ext4xfs"})`> 85%5mP2
磁盘将满预测`predict_linear(node_filesystem_avail_bytes{fstype=~"ext4xfs"}[6h], 4*3600) < 0`4 小时内写满5mP1
inode 剩余`100 * node_filesystem_files_free{fstype=~"ext4xfs"} / node_filesystem_files{fstype=~"ext4xfs"}`< 10%5mP2
磁盘 IO 利用率rate(node_disk_io_time_seconds_total[5m]) * 100> 90%15mP2
网卡出带宽`rate(node_network_transmit_bytes_total{device!~"loveth.*docker."}[5m]) 8`> 带宽上限 × 80%10mP1
主机存活up{job="node"}== 01mP0
服务存活(HTTP)probe_success{job="blackbox-http"}== 02mP0
服务存活(端口)probe_success{job="blackbox-tcp"}== 02mP1
SSL 证书到期(probe_ssl_earliest_cert_expiry - time()) / 86400< 15 天30mP2

阈值不是拍脑袋定的,要注意三点:

  1. 使用率不等于异常。CPU 85% 对于一个跑批任务是正常的,对于一个 Web 前端就是异常,阈值要按角色分组(Web 节点、数据库节点、计算节点分开配)。
  2. 磁盘告警必须双保险。既配「已用 85%」,也配「4 小时内将写满」的线性预测,后者能救你于周末凌晨。
  3. 服务存活优先级最高。up == 0 只持续 1 分钟就报,而资源类指标要 5~15 分钟,因为资源抖动是常态,主机失联不是。

指标采集:先装好 node_exporter

bash
# Ubuntu 24.04 LTS 部署 node_exporter 1.8(截至 2026 年稳定版本)
sudo useradd --no-create-home --shell /bin/false node_exporter
wget https://github.com/prometheus/node_exporter/releases/download/v1.8.2/node_exporter-1.8.2.linux-amd64.tar.gz
tar xzf node_exporter-1.8.2.linux-amd64.tar.gz
sudo cp node_exporter-1.8.2.linux-amd64/node_exporter /usr/local/bin/
sudo chown node_exporter:node_exporter /usr/local/bin/node_exporter

sudo tee /etc/systemd/system/node_exporter.service >/dev/null <<'EOF'
[Unit]
Description=Prometheus Node Exporter
After=network-online.target

[Service]
User=node_exporter
ExecStart=/usr/local/bin/node_exporter \
  --collector.systemd \
  --collector.processes \
  --no-collector.wifi
Restart=always
RestartSec=3

[Install]
WantedBy=multi-user.target
EOF

sudo systemctl daemon-reload
sudo systemctl enable --now node_exporter
curl -s http://127.0.0.1:9100/metrics | grep -E '^node_load5|^node_memory_MemTotal_bytes'

端口 9100 不要对公网开放,只在安全组里放通 Prometheus Server 的内网 IP。

告警分级怎么做?P0~P3 的标准是什么

结论:按「影响面 + 是否需要人立即介入」分级。只有「业务已中断」或「即将中断且无法自愈」才配 P0,其余一律降级,否则 P0 会烂大街。

级别定义典型场景通知方式响应时限
P0业务中断或数据有丢失风险主机失联、HTTP 探测失败、主库不可用电话 + 短信 + IM @所有人5 分钟内响应
P1即将中断,或核心指标严重劣化磁盘 4 小时内写满、带宽打满、CPU 满载 15 分钟电话 + IM 群15 分钟内响应
P2需要关注但不紧急内存 90%、证书 15 天内到期、IO 高IM 群 + 邮件当班内处理(4 小时)
P3提示/趋势类周环比成本上涨、慢查询数上升邮件日报次日处理

分级落地的关键动作:

  • 用 severity 标签承载等级,路由(route)按 severity 分流到不同接收器,而不是靠人肉判断。
  • P0 必须「双通道」:IM 群消息 + 电话外呼。只发 IM 的 P0 在夜间等于没发。
  • P3 只进日报,绝不推送到群,这是控制噪声的第一道闸门。
  • 每季度复盘一次:若某条 P0 连续 3 个月「触发后无需处理」,就降级为 P1 或删除。

Prometheus Alertmanager 告警规则怎么写

结论:规则文件(rules)负责「判定异常」,Alertmanager 负责「发给谁、怎么发」。两者必须分开管理,规则里只写表达式与标签,不写通知渠道。

告警规则 YAML 示例

yaml
# /etc/prometheus/rules/host.yml
groups:
  - name: host-resource
    rules:
      - alert: HostDown
        expr: up{job="node"} == 0
        for: 1m
        labels:
          severity: critical      # P0
          team: ops
        annotations:
          summary: "主机失联:{{ $labels.instance }}"
          description: "node_exporter 连续 1 分钟抓取失败,请检查主机、网络与 9100 端口。"
          runbook: "https://wiki.example.com/runbook/host-down"

      - alert: DiskWillFillIn4Hours
        expr: predict_linear(node_filesystem_avail_bytes{fstype=~"ext4|xfs",mountpoint!~"/boot.*"}[6h], 4*3600) < 0
        for: 5m
        labels:
          severity: warning       # P1
          team: ops
        annotations:
          summary: "磁盘将满:{{ $labels.instance }} {{ $labels.mountpoint }}"
          description: "按当前写入速度,4 小时内将写满,立即清理或扩容。"
          value: "剩余 {{ $value | humanize }} bytes"

      - alert: HighCPUUsage
        expr: 100 - (avg by(instance)(rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100) > 85
        for: 10m
        labels:
          severity: info          # P2
          team: ops
        annotations:
          summary: "CPU 使用率过高:{{ $labels.instance }}"
          description: "CPU 使用率持续 10 分钟超过 85%,当前 {{ $value | printf \"%.1f\" }}%。"

      - alert: SSLCertExpiringSoon
        expr: (probe_ssl_earliest_cert_expiry - time()) / 86400 < 15
        for: 30m
        labels:
          severity: info
          team: ops
        annotations:
          summary: "SSL 证书即将过期:{{ $labels.instance }}"
          description: "证书剩余有效期不足 15 天,请尽快续签。"

写完必须自检语法,否则 Prometheus 加载失败会导致整个规则集不生效:

bash
# 校验规则语法(promtool 随 Prometheus 一起安装)
promtool check rules /etc/prometheus/rules/host.yml

# 让 Prometheus 热加载配置(需启动时加 --web.enable-lifecycle)
curl -X POST http://127.0.0.1:9090/-/reload

# 在 UI 上确认规则已加载
curl -s http://127.0.0.1:9090/api/v1/rules | jq '.data.groups[].rules[].name'

Alertmanager 路由与接收器配置

yaml
# /etc/alertmanager/alertmanager.yml
global:
  resolve_timeout: 5m
  smtp_smarthost: 'smtp.exmail.qq.com:465'
  smtp_from: 'alert@example.com'
  smtp_auth_username: 'alert@example.com'
  smtp_auth_password: '替换为应用专用密码'

templates:
  - '/etc/alertmanager/templates/*.tmpl'

route:
  receiver: 'default-im'
  group_by: ['alertname', 'instance', 'severity']
  group_wait: 30s        # 首次等待,攒一批再发
  group_interval: 5m     # 同组新告警合并间隔
  repeat_interval: 4h    # 未恢复告警的重发间隔
  routes:
    - matchers:
        - severity="critical"
      receiver: 'p0-phone'
      group_wait: 10s
      repeat_interval: 30m
      continue: false
    - matchers:
        - severity="warning"
      receiver: 'p1-im'
      repeat_interval: 1h
    - matchers:
        - severity="info"
      receiver: 'daily-mail'
      group_wait: 5m
      repeat_interval: 24h

receivers:
  - name: 'default-im'
    webhook_configs:
      - url: 'http://127.0.0.1:8060/dingtalk/ops/send'
        send_resolved: true

  - name: 'p0-phone'
    webhook_configs:
      - url: 'http://127.0.0.1:8060/dingtalk/p0/send'
        send_resolved: true
    email_configs:
      - to: 'oncall@example.com'
        send_resolved: true

  - name: 'p1-im'
    webhook_configs:
      - url: 'http://127.0.0.1:8060/dingtalk/ops/send'
        send_resolved: true

  - name: 'daily-mail'
    email_configs:
      - to: 'ops@example.com'
        send_resolved: false

inhibit_rules:
  # 主机已经失联时,抑制该主机上的一切资源类告警
  - source_matchers: ['alertname="HostDown"']
    target_matchers: ['severity="info"']
    equal: ['instance']
  # P0 触发时抑制同实例的 P1,避免刷屏
  - source_matchers: ['severity="critical"']
    target_matchers: ['severity="warning"']
    equal: ['instance']

校验与测试路由:

bash
amtool check-config /etc/alertmanager/alertmanager.yml
amtool config routes test --config.file=/etc/alertmanager/alertmanager.yml \
  severity="critical" instance="web-01:9100"

# 手动造一条告警,验证通知链路是否真的能收到
amtool alert add alertname=TestAlert severity=critical instance=web-01:9100 \
  --alertmanager.url=http://127.0.0.1:9093

告警怎么发到钉钉、企业微信和 Webhook

结论:Alertmanager 原生只支持邮件、Slack、Webhook;钉钉和企业微信走 Webhook 转发器(prometheus-webhook-dingtalk)。不要自己写脚本轮询 API,那会丢告警。

  • 邮件:适合 P2/P3 日报与审计留痕,不适合 P0。
  • 钉钉 / 企业微信机器人:国内团队首选,支持 @手机号 精准提醒值班人。
  • Webhook 自建:用于对接工单系统或电话外呼平台(如阿里云云呼、容联七陌)。
  • 短信 / 电话:P0 必备,建议接第三方,避免依赖单一 IM 厂商。

钉钉机器人的消息模板要包含「级别、实例、摘要、值班人、Runbook 链接」,让值班人点开就知道做什么:

yaml
# /etc/alertmanager/templates/dingtalk.tmpl
{{ define "dingtalk.message" }}
## [{{ .Status | toUpper }}] {{ .CommonLabels.alertname }}({{ .CommonLabels.severity }})
{{ range .Alerts }}
- **级别**:{{ .Labels.severity }}
- **实例**:{{ .Labels.instance }}
- **摘要**:{{ .Annotations.summary }}
- **详情**:{{ .Annotations.description }}
- **开始**:{{ .StartsAt.Format "2006-01-02 15:04:05" }}
{{ end }}
> 值班人请按 Runbook 处理,处理完在群内回复"已恢复"。
{{ end }}

告警太多怎么办?收敛、抑制与静默

结论:抗告警疲劳靠三个机制——分组(group_by)、抑制(inhibit_rules)、静默(silence),再加一个「告警体检」制度。

  1. 分组收敛:同一个 alertname + instance 的告警在 group_wait 窗口内合并成一条消息。一台机器重启时,原本可能刷出 20 条,配置合理后只发 1 条。
  2. 抑制规则:主机失联(HostDown)时,自动抑制该主机的 CPU、内存、磁盘告警——机器都宕了,再报 CPU 高毫无意义。
  3. 计划内静默:发版、压测、机房割接前,用 amtool silence add 提前静默,避免「狼来了」。
  4. 重复间隔拉长:未恢复的 P2 告警 4 小时重发一次即可,不需要每 5 分钟提醒一次。
  5. 月度体检:统计触发次数 Top 10 的告警,凡「30 天内触发 > 20 次且无人处理」的,要么调阈值,要么删除。
bash
# 静默 web-01 上所有告警 2 小时(用于计划内维护)
amtool silence add --alertmanager.url=http://127.0.0.1:9093 \
  --author="zhangsan" --comment="发版维护窗口" \
  --duration=2h instance="web-01:9100"

amtool silence query --alertmanager.url=http://127.0.0.1:9093

值班与升级机制怎么设计

结论:没有升级机制的告警等于把风险压在最前线的人身上。建议「三级值班 + 30 分钟未响应自动升级」。

  • 一线值班(L1):7×24 轮班,收到 P0 后 5 分钟内认领,按 Runbook 执行标准动作(重启服务、切备机、回滚)。
  • 二线专家(L2):L1 在 30 分钟内无法恢复,升级到对应组件负责人(数据库、网络、中间件)。
  • 三线管理(L3):P0 持续超过 60 分钟,通知技术负责人与业务方,启动对外沟通。

配套要求:

  • 每条 P0 告警的 annotations 里必须带 runbook 链接,没写 Runbook 的告警不允许上线。
  • 交接班时要过一遍「当前 firing 告警」清单,避免跨班遗漏。
  • 每月出一份告警统计:触发数、平均响应时长(MTTA)、平均恢复时长(MTTR)、误报率。误报率超过 30% 就说明阈值该调了。

常见误区 / 排错提示

  1. 误区:阈值照抄别人的 80%。不同业务基线不同,正确做法是先用 avg_over_time(...[7d]) 看一周基线,再在基线上加 20%~30% 余量作为阈值。
  2. 误区:for: 0m 立即告警。没有持续时长会导致瞬时抖动狂轰滥炸,资源类指标最少 for: 5m。
  3. 排错:告警不触发。先 promtool check rules 确认语法,再在 Prometheus UI 的 Graph 页直接跑同一条 PromQL,看是否有数据返回——90% 的问题出在指标名或标签写错。
  4. 排错:Alertmanager 收到告警但不发消息。用 amtool config routes test 验证路由匹配;企业微信/钉钉机器人要检查 IP 白名单与关键字校验(很多机器人要求消息里必须包含预设关键字)。
  5. 排错:邮件进垃圾箱。给告警邮箱配置 SPF、DKIM、DMARC,否则运维邮箱大概率被判为垃圾邮件。
  6. 误区:只监控平均值。avg 会掩盖个别实例的问题,单机告警必须用 by(instance) 分组。