电商系统监控告警体系从0到1:Prometheus+Grafana+AlertManager的全链路可观测性实践

一、 那个凌晨,系统挂了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_count5m) > 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_count2m))) * 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_bucket5m)) 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_total30m)) < sum(increase(order_gmv_total30m offset 1d)) * 0.7

    for: 30m

    labels:

    severity: warning

    annotations:

    summary: "GMV异常下降"

    description: "最近30分钟GMV较昨日同期下降超过30%"

  • alert: OrderPaymentRateDrop

    expr: (sum(rate(order_created_total10m)) / sum(rate(order_paid_total10m))) > 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:

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

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条真正重要的告警。

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

文末思考:

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

相关推荐
踏月的造梦星球5 小时前
DMHS同步原理与DM8到DM8基础搭建
数据库·oracle
G.O.G.O.G7 小时前
LeetCode SQL 从入门到精通(MySQL)05(下)
数据库·sql·oracle
alxraves9 小时前
医院远程会诊系统:数据库模块设计与实现
数据库·oracle
苦瓜汤补钙10 小时前
Oracle JDK8 环境配置-Win11
开发语言·数据库·笔记·oracle
江南风月10 小时前
WGCLOUD支持创建子账号吗
运维·zabbix·运维开发·prometheus
️学习的小王10 小时前
MySQL 数据库基础操作全解:从建库到增删改查
数据库·mysql·oracle
oradh11 小时前
Oracle 11g单库升级至19c单库(dbua图形方式)
数据库·oracle·11g升级19c·dbua升级方式
维C°11 小时前
Grafana-Text面板
grafana
Java面试题总结12 小时前
RAG 入库实战:一份原始资料,如何变成可检索的知识
数据库·oracle