运维实践

服务器监控告警怎么搭:从指标采集到告警收敛

先把四层信号的分工划清

监控搭不起来,绝大多数不是工具不够,而是四类信号被混成一个用途。指标回答「有没有异常、趋势往哪走」,只有它适合长期存储和阈值判断;日志回答「当时具体发生了什么」,用于取证与细节还原;链路回答「请求慢在哪一跳」,用于跨服务定位;事件回答「谁在什么时候改了什么配置、发了什么版」,用于把异常和变更对上时间。结论很直接:告警只从指标层触发,日志与链路做根因支撑,事件做变更关联。

拿日志关键字做告警是最常见的走偏。日志量随流量起伏,关键字没有基线,一次促销带来的正常噪声就能刷出几千条通知,值班的人三天之后开始忽略所有消息。这个分工还有一个推论:阈值必须来自有基线的指标。新建系统先只记录不告警,跑够一到两周,看清 P95 的真实分布再定阈值;跳过这一步,后面所有调参都是在猜。

必采的黄金指标

主机层面盯住下面七项,基本覆盖八成线上事故的前兆。

指标 采集来源 判断标准
CPU steal node_cpu_seconds_total{mode="steal"} 持续高于 5% 说明宿主机超卖或邻居抢资源,云上尤其常见
负载 ÷ 核数 node_load5 除以 idle 计数 持续大于 1.5 需关注,大于 3 基本已经过载
内存 available node_memory_MemAvailable_bytes 低于总量 10%~15% 开始告警,不要用 free 或 used 判断
磁盘 inode node_filesystem_files_free 小文件多的场景 inode 会先耗尽,磁盘还剩一半却写不进去
TCP 重传 重传段增量 ÷ 发送段增量 持续超过 1% 说明链路质量或对端有问题
5xx 率 网关或 web 日志统计 按业务定,通常超过 0.5% 就该有人看
P95 延迟 延迟直方图分位计算 只看平均值会掩盖长尾,用户感知的永远是 P95 以上

平均值是给报表看的,P95 和 P99 才是用户真正感受到的。任何用平均延迟推出的容量结论都值得怀疑。

最小可用组成:Prometheus + node_exporter + Grafana

三个组件就够跑起来,不必一上来就上平台。node_exporter 在每台机器暴露 /metrics,Prometheus 按固定间隔拉取并按时序存储,Grafana 负责看板,告警交给 Alertmanager 分派。

  1. node_exporter 只监听回环或内网地址。公网暴露等于把主机指纹、内核版本和进程信息一起送出去,端口收敛的做法与 云服务器安全加固清单 一致。
  2. 采集间隔与规则评估间隔统一到 15~30 秒。间隔减半,存储量大约翻倍,而收益很小。
  3. 本地保留先给 15 天,长期趋势用远程写或降采样落到对象存储,不要把时序库当归档用。
  4. 看板按「业务错误率 → 主机资源 → 容量趋势」三层组织,先看业务,再看机器。

这三个组件通常用容器跑,网络与数据卷的处理可以对照 Docker 入门 里的网络与卷两节,能少踩不少坑。如果服务已经在 Kubernetes 上,指标端点、标签体系和抓取配置的组织方式差别很大,先弄清 Pod、Deployment、Service 的关系 再动手会顺很多。

告警分级与收敛

分级的原则是「一个级别只对应一种通知渠道」,否则级别形同虚设。

  • P1:核心链路不可用或面临数据丢失,电话加短信,五分钟内响应,必须有值班表与升级路径。
  • P2:性能明显劣化或部分功能异常,IM 群通知,三十分钟内处理。
  • P3:容量预警、非核心指标异常,进工单,当日或当周处理。

收敛不是在通知层把消息关掉,而是在派发前做聚合、抑制和延迟,三招各管一类问题。

  • 分组:按服务、实例、告警名聚合,同一次机房抖动只出一条汇总,而不是两百条单实例消息。
  • 抑制:上层故障抑制下层衍生告警。机器宕机时抑制这台机所有资源告警,网关 5xx 抑制后端实例超时。
  • 静默:发版、迁移、演练前按时段静默,必须写清原因和到期时间,否则静默会悄悄变成永久静音。

误报的三个常见来源

  • 阈值拍脑袋:没有基线就照抄别人的 80%,业务空闲时段自然触发。
  • 只看单点:一个采集点抖动就报警,缺少多实例聚合与连续次数判断。
  • 没有持续时间:规则里不写 for,瞬时毛刺被当成故障。这是误报里最容易修、也最常被忽略的一条。

一条可以落地的规则

下面这条规则同时做了多实例聚合、持续时间和分级标注,改阈值即可用。

groups:
  - name: host-basic
    rules:
      - alert: HostHighLoad
        expr: |
          node_load5 / count by (instance) (node_cpu_seconds_total{mode="idle"}) > 1.5
        for: 10m
        labels:
          severity: P2
        annotations:
          summary: "{{ $labels.instance }} 负载偏高"
          description: "5 分钟负载为核数的 {{ $value }} 倍,已持续 10 分钟"

      - alert: HostDiskWillFillIn4h
        expr: |
          predict_linear(node_filesystem_avail_bytes{fstype!~"tmpfs|overlay"}[1h], 14400) < 0
        for: 15m
        labels:
          severity: P1
        annotations:
          summary: "{{ $labels.instance }} 磁盘预计 4 小时内写满"

第二条用线性预测而不是固定水位,好处是给容量增长留出处理时间;坏处是日志暴涨这类阶跃场景预测会失真,所以两条都要有。指标之外的日志与链路怎么分工,可以顺着 云原生架构入门 里发布与 CI/CD 那部分往下看。

常见问题

告警太多没人看,先砍哪一类?

先砍没有 for 的规则,再砍只基于单实例的规则。这两类贡献了大部分噪声,且修改成本最低。砍完观察一周,如果 P1 数量仍然超过每周三条,说明分级标准定错了,而不是告警太多。

只有一台小机器,也值得上 Prometheus 吗?

值得,但可以更轻。一台机器加三个容器,内存占用通常在几百 MB 量级,换来的是可回溯的趋势和统一的告警出口。如果确实资源紧张,先只装 node_exporter 加一个托管的时序服务,也比完全没有指标强。

CPU 使用率高就一定要告警吗?

不一定。持续高负载但延迟和错误率正常,说明容量还有余量,属于容量规划问题而不是故障。真正该告警的是延迟、错误率这些反映用户体验的指标,CPU 用作解释性指标即可。

阈值该用固定值还是同比波动?

资源类指标用固定值更稳,因为物理上限是客观的;业务类指标适合用同比或环比波动,因为流量本身有周期。混用会导致白天不报夜里狂报,或者反过来。

延伸阅读