一、 那个凌晨,系统挂了30分钟我们才知道
聊监控告警之前,先讲一个让人后背发凉的真实经历。

某个周六凌晨2点,我们的数据库主库突然宕机了。自动切换脚本因为网络超时没有执行成功,系统处于"半死不活"的状态——部分用户能访问,部分用户报错。

问题是:我们直到2点37分才收到第一通报警电话。

整整37分钟,系统处于异常状态,而我们完全不知情。值班工程师在睡觉,监控大屏没有声音告警,邮件告警被淹没在垃圾邮件里。

事后复盘,我们的监控体系存在三个致命问题:

告警渠道单一:只有邮件,深夜没人看。

告警阈值不合理:数据库连接数阈值设置得太高,达到阈值时系统已经半瘫痪了。

缺乏分级告警:P0级故障和P3级警告混在一起,无法区分轻重缓急。

这次事故之后,我们决心从零搭建一套"能用、可靠、不扰民"的监控告警体系。

本文将完整复盘这套体系的建设过程,重点分享监控指标设计、告警规则配置以及值班响应机制的实战经验。

二、 可观测性的三大支柱
在开始搭建之前,需要先理解一个核心概念:可观测性(Observability) 有三个支柱。

支柱 说明 解决什么问题 典型工具
指标(Metrics) 数值型时序数据(QPS、RT、CPU、内存) “系统现在什么状态?” Prometheus
日志(Logging) 结构化/非结构化文本(错误日志、访问日志) “具体发生了什么?” ELK / Loki
链路追踪(Tracing) 请求在分布式系统中的完整路径 “哪个环节出了问题?” Jaeger / SkyWalking
这三个支柱的关系可以这样理解:

Metrics告诉你"系统出问题了"

Logging告诉你"具体是什么错误"

Tracing告诉你"问题出在哪个服务、哪个环节"

三者缺一不可。没有Metrics,你发现不了问题;没有Logging,你定位不了根因;没有Tracing,你不知道问题出在哪个链路上。

三、 技术选型:为什么选Prometheus + Grafana?
监控领域有很多成熟方案,我们做了一番对比:

对比维度 Zabbix Prometheus + Grafana 云厂商监控(如云监控)
数据模型 传统Agent采集 拉取式(Pull Model) 推送式
查询语言 有限 PromQL(强大、灵活) 有限
可视化 一般 Grafana(业界标杆) 良好
云原生支持 较弱 原生支持K8s/容器 中等
告警能力 内置 AlertManager(灵活) 内置
成本 开源免费 开源免费 按量付费
社区生态 成熟但传统 极其活跃、生态丰富 厂商绑定
学习曲线 中等 陡峭(但值得) 低
选型结论:Prometheus + Grafana + AlertManager

理由:

Prometheus的Pull Model更适合动态的容器化环境

PromQL的查询能力远超传统监控方案

Grafana的可视化能力是业界天花板

开源且社区活跃,遇到问题容易找到解决方案

四、 整体架构
text
┌─────────────────────────────────────────────────────────────────┐
│ 数据采集层 │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ Node │ │ JVM │ │ MySQL │ │ Redis │ │ Nginx │ │
│ │Exporter │ │Exporter │ │Exporter │ │Exporter │ │Exporter │ │
│ └────┬────┘ └────┬────┘ └────┬────┘ └────┬────┘ └────┬────┘ │
│ └───────────┴───────────┴───────────┴───────────┘ │
└─────────────────────────────────────────────────────────────────┘
│ Pull(每15秒)

┌─────────────────────────────────────────────────────────────────┐
│ 存储层 │
│ Prometheus TSDB │
│ (时序数据库,默认保留15天) │
└─────────────────────────────────────────────────────────────────┘

├──────────────┐
▼ ▼
┌─────────────────┐ ┌─────────────────────────────────────────┐
│ 告警层 │ │ 展示层 │
│ AlertManager │────▶│ ┌─────────────────────────────────┐ │
│ ├─ 分组 │ │ │ Grafana │ │
│ ├─ 抑制 │ │ │ ├─ 系统总览大盘 │ │
│ ├─ 静默 │ │ │ ├─ 应用性能大盘 │ │
│ └─ 通知渠道 │ │ │ ├─ 数据库大盘 │ │
│ ├─ 钉钉/企微 │ │ │ ├─ 业务指标大盘 │ │
│ ├─ 电话 │ │ │ └─ 自定义告警看板 │ │
│ ├─ 短信 │ │ └─────────────────────────────────┘ │
│ └─ 邮件 │ └─────────────────────────────────────────┘
└─────────────────┘
五、 监控指标设计
监控最怕的事情是"什么都想监控,结果什么都监控不好"。需要遵循分层设计的原则,从基础设施到业务指标逐层覆盖。

5.1 基础设施层(服务器/网络)
指标分类 具体指标 告警阈值参考
CPU 使用率、负载(load average) > 80% 持续5分钟
内存 使用率、可用内存、Swap使用 > 90% 持续5分钟
磁盘 使用率、IOPS、读写延迟 使用率 > 85%
网络 入/出流量、丢包率、连接数 丢包率 > 1%
系统 文件描述符数、进程数 文件描述符 > 80%
yaml

Prometheus告警规则示例

groups:

  • name: node_alerts
    rules:
    • alert: HighCPUUsage
      expr: (100 - (avg(rate(node_cpu_seconds_total{mode=“idle”}[5m])) * 100)) > 80
      for: 5m
      labels:
      severity: warning
      annotations:
      summary: “CPU使用率过高”
      description: “主机 {{ $labels.instance }} CPU使用率 {{ $value }}% 持续超过5分钟”

    • alert: DiskFull
      expr: (node_filesystem_avail_bytes{mountpoint=“/”} / node_filesystem_size_bytes{mountpoint=“/”}) * 100 < 15
      for: 5m
      labels:
      severity: critical
      annotations:
      summary: “磁盘空间不足”
      description: “主机 {{ $labels.instance }} 磁盘可用空间低于15%”
      5.2 应用服务层(JVM/容器)
      指标分类 具体指标 告警阈值参考
      JVM堆内存 使用率、GC频率、GC耗时 Heap使用率 > 85%
      JVM非堆 Metaspace、DirectBuffer Metaspace > 90%
      线程 活跃线程数、阻塞线程数 线程池队列 > 1000
      类加载 已加载类数、卸载类数 异常增长需关注
      容器 Pod CPU/内存使用率、重启次数 重启次数 > 3次/小时
      java
      // Spring Boot Actuator + Micrometer 自动暴露指标
      // application.yml
      management:
      endpoints:
      web:
      exposure:
      include: health,metrics,prometheus
      metrics:
      export:
      prometheus:
      enabled: true
      tags:
      application: order-service
      env: production
      yaml

JVM告警规则

  • alert: JVMHeapUsageHigh
    expr: (sum(jvm_memory_used_bytes{area=“heap”}) / sum(jvm_memory_max_bytes{area=“heap”})) * 100 > 85
    for: 5m
    labels:
    severity: warning
    annotations:
    summary: “JVM堆内存使用率过高”
    description: “服务 {{ $labels.application }} 堆内存使用率 {{ $value }}%”

  • alert: FrequentGC
    expr: rate(jvm_gc_pause_seconds_count[5m]) > 5
    for: 5m
    labels:
    severity: warning
    annotations:
    summary: “GC频率过高”
    description: “服务 {{ $labels.application }} 过去5分钟GC次数超过5次”
    5.3 业务服务层(接口/依赖)
    指标分类 具体指标 告警阈值参考
    请求量 QPS、TP99、TP999 环比波动 > 50%
    错误率 HTTP 5xx、业务异常 错误率 > 1%
    依赖服务 下游RPC RT、错误率 下游RT > 500ms
    数据库 连接池使用率、慢查询 慢查询 > 5次/分钟
    缓存 Redis命中率、连接数 命中率 < 80%
    yaml

服务接口告警规则

  • alert: HighErrorRate
    expr: (sum(rate(http_server_requests_seconds_count{status=~“5…”}[2m])) / sum(rate(http_server_requests_seconds_count[2m]))) * 100 > 1
    for: 2m
    labels:
    severity: critical
    annotations:
    summary: “接口错误率过高”
    description: “服务 {{ $labels.application }} 接口错误率 {{ $value }}%”

  • alert: HighResponseTime
    expr: histogram_quantile(0.99, sum(rate(http_server_requests_seconds_bucket[5m])) by (le, application)) > 1
    for: 5m
    labels:
    severity: warning
    annotations:
    summary: “接口响应时间过长”
    description: “服务 {{ $labels.application }} TP99响应时间 {{ $value }}秒”
    5.4 业务指标层(GMV/订单/用户)
    这是最贴近业务价值的监控,也是CTO/老板最关心的。

指标分类 具体指标 告警阈值参考
交易 实时GMV、订单量、支付成功率 同比波动 > 30%
用户 活跃用户数、新注册数、转化率 新注册数骤降 > 50%
商品 商品浏览量、加购率、库存预警 库存 < 安全水位
营销 优惠券领取/使用率、活动参与 优惠券使用率异常高(薅羊毛)
yaml

业务指标告警规则

  • alert: GMVAnomaly
    expr: sum(increase(order_gmv_total[30m])) < sum(increase(order_gmv_total[30m] offset 1d)) * 0.7
    for: 30m
    labels:
    severity: warning
    annotations:
    summary: “GMV异常下降”
    description: “最近30分钟GMV较昨日同期下降超过30%”

  • alert: OrderPaymentRateDrop
    expr: (sum(rate(order_created_total[10m])) / sum(rate(order_paid_total[10m]))) > 3
    for: 10m
    labels:
    severity: critical
    annotations:
    summary: “支付转化率异常下降”
    description: “创建订单与支付订单比例超过3:1”
    六、 告警规则设计
    好的告警规则要做到"三不":

不错报:不要因为短时抖动就发告警(要有for持续时间)

不漏报:真正的问题必须告警出来(阈值要合理)

不疲劳:不要一天发几百条告警(要分级、分组、抑制)

6.1 告警严重程度分级
级别 标签 响应时间 通知渠道 典型场景
P0 critical 5分钟 电话 + 钉钉 + 短信 服务宕机、核心接口不可用
P1 warning 15分钟 钉钉 + 短信 错误率上升、RT超标
P2 info 1小时 钉钉(工作群) 磁盘使用率高、非核心功能异常
P3 none 不告警 仅记录 用于观察的指标,不触发告警
6.2 AlertManager配置
yaml

alertmanager.yml

route:
group_by: [‘alertname’, ‘cluster’]
group_wait: 10s # 同一组告警等待时间
group_interval: 10s # 同一组告警间隔
repeat_interval: 12h # 相同告警重复发送间隔

按严重程度路由

routes:

  • match:
    severity: critical
    receiver: p0-receiver
    continue: true

  • match:
    severity: warning
    receiver: p1-receiver

  • match:
    severity: info
    receiver: p2-receiver

接收人配置

receivers:

  • name: p0-receiver
    webhook_configs:

    • url: ‘https://your-domain/alert/critical’
      send_resolved: true
      dingtalk_configs:
    • url: ‘https://oapi.dingtalk.com/robot/send?access_token=xxx’
      message: |
      【P0告警】{{ .GroupLabels.alertname }}
      详情:{{ .CommonAnnotations.summary }}
      时间:{{ .StartsAt }}
  • name: p1-receiver
    dingtalk_configs:

    • url: ‘https://oapi.dingtalk.com/robot/send?access_token=xxx’
  • name: p2-receiver
    email_configs:

    • to: ‘ops-team@company.com’

告警抑制(如果服务器宕机了,就不必再发送该服务器上的应用告警)

inhibit_rules:

  • source_match:
    severity: critical
    target_match:
    severity: warning
    equal: [‘instance’]
    6.3 告警收敛策略
    告警风暴是所有运维团队的噩梦。以下是三种有效的收敛策略:

策略一:分组(Group By)

同一类告警聚合为一条发送,而不是每一条都发:

text

不加分组:10台机器磁盘告警 → 发10条消息

加分组后:10台机器磁盘告警 → 发1条消息,包含10台机器列表

策略二:抑制(Inhibit)

高阶告警触发时,抑制低阶告警:

text
场景:数据库宕机(P0)→ 自动抑制"接口超时"告警(P1)
理由:接口超时是数据库宕机的"症状",不是根因,不需要单独告警
策略三:静默(Silence)

已知问题、计划内维护期间,手动静默相关告警:

bash

在AlertManager UI中设置静默

或通过API创建

curl -X POST http://alertmanager:9093/api/v2/silences
-H “Content-Type: application/json”
-d ‘{
“matchers”: [{“name”: “alertname”, “value”: “DiskFull”}],
“startsAt”: “2024-01-01T10:00:00Z”,
“endsAt”: “2024-01-01T12:00:00Z”,
“createdBy”: “ops-team”,
“comment”: “计划内磁盘扩容维护”
}’
七、 日志与链路追踪
7.1 日志体系(ELK/Loki)
日志是定位问题的"显微镜"。我们的日志架构:

text
[应用日志(JSON格式)]

[Filebeat](轻量日志采集器)

[Logstash / Loki](日志解析/聚合)

[Elasticsearch / 对象存储]

[Kibana / Grafana](日志检索/可视化)
关键实践:

java
// 1. 统一日志格式(JSON结构化日志)
// logback-spring.xml




// 2. 关键字段必须包含
// { “timestamp”: “2024-01-01T10:00:00Z”,
// “level”: “ERROR”,
// “traceId”: “abc-123-def”,
// “service”: “order-service”,
// “tenantId”: “tenant-001”,
// “message”: “数据库连接超时”,
// “stackTrace”: “…” }

// 3. 日志分级存储
// - ERROR/WARN → Elasticsearch(7天)
// - INFO → 对象存储(30天)
// - DEBUG → 本地文件(3天,仅开发环境)
7.2 链路追踪(SkyWalking)
分布式系统的核心痛点:一个请求经过4个服务,出问题不知道日志在哪。

java
// SkyWalking接入(通过Java Agent无侵入)
// JVM启动参数
-javaagent:/path/to/skywalking-agent.jar
-Dskywalking.agent.service_name=order-service
-Dskywalking.collector.backend_service=oap-server:11800

// 自动生成TraceId并传递到所有下游服务
// 所有日志自动包含traceId字段
TraceId + 日志 + Metrics 的关联查询:

text

在Grafana中,通过TraceId关联查询

  1. 从Metrics发现某接口RT异常
  2. 从该接口的日志中提取TraceId
  3. 在SkyWalking中查询该TraceId的完整调用链
  4. 定位到具体是哪个服务的哪个方法出了问题
    八、 踩坑实录
    坑1:告警阈值设置不合理
    现象:CPU告警阈值设为95%,结果系统在CPU 90%时就已经响应缓慢,但告警一直没有触发。

教训:告警阈值不能只看"系统崩溃时的值",要看"用户体验开始下降时的值"。

解决方案:

结合用户体验数据(如APDEX指数)来校准阈值

阈值设置要留出缓冲空间(不要等到系统快崩溃了才告警)

坑2:告警发送频率过高
现象:有一次数据库连接池告警,每5分钟发一次,持续了4个小时,钉钉群里被刷了48条相同告警。

教训:重复告警会导致"狼来了"效应,团队成员逐渐对告警麻木。

解决方案:

AlertManager中设置 repeat_interval: 12h

同一告警在持续期间只发一次,状态变化时再发

坑3:Prometheus数据持久化问题
现象:Prometheus容器重启后,历史数据全部丢失,所有监控图表变成"断点"。

教训:Prometheus默认存储是容器内的临时存储,容器重启即清空。

解决方案:

使用持久化存储(PV/PVC)

关键指标配置远程存储(Thanos/Cortex)实现长期存储

调整 --storage.tsdb.retention.time=15d 保留最近15天数据

坑4:监控与业务日志割裂
现象:监控发现接口错误率上升,但去查日志时发现日志太多了,不知道从哪开始查。

教训:Metrics、Logging、Tracing三个体系必须打通,否则排查问题效率极低。

解决方案:

所有日志携带 traceId

Grafana中创建"统一查询视图",在一个面板中同时展示Metrics曲线和对应的日志

引入Loki(Grafana Lab出品的日志聚合系统),与Grafana原生集成

九、 最终成果
经过三轮迭代,监控体系最终覆盖了以下能力:

能力层 覆盖范围 说明
基础设施监控 50+台服务器 CPU/内存/磁盘/网络全覆盖
应用监控 15个微服务 JVM、接口、依赖服务全链路
业务监控 核心业务指标 GMV、订单、用户、转化率
日志采集 全部服务 结构化JSON日志,统一采集
链路追踪 核心链路 覆盖80%的核心接口
告警规则 80+条 P0级15条、P1级35条、P2级30条
告警准确率变化:

阶段 平均日告警数 P0级误报率 MTTR(平均修复时间)
无体系(初期) ~200条 80%+ 45分钟
基础体系 ~50条 40% 25分钟
成熟体系(当前) ~15条 <5% 8分钟
十、 总结
监控告警体系的建设需要关注三个核心维度:

维度 核心要点 常见错误
指标 分层设计(基础设施→应用→业务),每个层级关注不同的指标 只关注技术指标,忽视业务指标
告警 分级(P0/P1/P2)、分组、抑制、静默四件套 阈值不合理、告警疲劳
响应 告警→确认→定位→修复→复盘,形成闭环 只有告警没有后续动作
三条核心原则:

分层设计,从下到上:先搭好基础设施监控,再逐步向上覆盖应用和业务。没有地基的监控体系是空中楼阁。

告警要"少而精":每天发100条告警=没有告警。好的告警体系让值班工程师每天只需关注3-5条真正重要的告警。

可观测性不是一次性工程:随着系统演进,监控指标、告警阈值都需要持续调整。定期复盘告警记录,优化规则。

文末思考:

很多人觉得搭建监控告警是"运维的事",但实际上一线开发工程师才是监控的最大受益者——新版本发布后,第一个发现问题的往往是监控,而不是用户投诉。强烈建议开发团队在项目初期就同步建设监控能力,越早投入,回报越大。

Logo

电商企业物流数字化转型必备!快递鸟 API 接口,72 小时快速完成物流系统集成。全流程实战1V1指导,营造开放的API技术生态圈。

更多推荐