你正盯着凌晨三点的告警风暴,订单系统每分钟抛500+异常,偏偏没有一条告警告诉你到底是MySQL死锁还是Redis内存爆了——这就是四年前我刚接手电商运维时的真实场景。当时我们监控项上百,真正能定位问题的不足10个。后来花了一年重构,经历了双11和618的考验,才搞出一套勉强合格的体系。

这篇文章,我把从零设计电商监控的完整思路和可复用的配置整理出来。读完你至少能拿到一套直接套用的分层监控蓝图,避开我当初熬夜排障的坑。


前置条件:

  • 你的系统大概是 Spring Cloud 或 Go 微服务那套,跑在 K8s 或云主机上。
  • 假设你对 Prometheus、Grafana 有基本概念,知道 metric 是什么。
  • 手头有权限部署 Exporter、修改服务配置、调整网络策略。

我用过的环境:生产集群是 Kubernetes 1.24,Prometheus 版本 2.45,Grafana 9.5。监控组件我习惯用 prometheus-operator 部署,但文中配置都给出了独立部署的版本,方便你用。


别再一上来就堆 Exporter,先画三层

很多兄弟一上来就装 node_exporter、mysql_exporter,恨不得把所有 exporter 都挂上,然后导入一堆 Grafana 模板,看着挺全。结果出了问题,一边被电话轰炸,一边在十几个 dashboard 里翻指标,毛用没有。 因为缺少分层思路,告警也是一锅粥。

我个人坚持三层模型:基础设施层 → 应用服务层 → 业务指标层。每一层的目标不同,告警策略也不同。

基础设施层:稳住底座,但别报警太灵敏

这层包含主机、容器、网络、K8s 节点。核心指标就那几个:CPU、内存、磁盘、网络丢包、kubelet 状态。

说个我栽过的坑:早期我们把节点 CPU 超过 80% 设为严重告警,结果每次大促预热阶段告警狂刷,真正要紧的磁盘写满反而被淹没了。后来我改了策略——基础层指标默认只做趋势预测和容量规划,不做即时告警,只有严重影响可用性时才触发(比如磁盘使用>90%且增速过快,或节点NotReady超过2分钟)。

配置 node_exporter 就略过了,常规操作。但有一个指标你要额外采集:磁盘IO util 和 await。电商在大促期间会有大量日志落盘和临时文件,IO 打满比 CPU 更致命。用 Prometheus 采集:

# prometheus.yml 片段
scrape_configs:
  - job_name: 'node-exporter'
    static_configs:
      - targets: ['node1:9100', 'node2:9100']
    params:
      collect[]:
        - cpu
        - meminfo
        - diskstats
        - filesystem
        - netdev

这里提醒一下,别用 node_exporter 的默认全量采集。我之前没限制采集项,结果一个节点的 metric 量级达到 5 万+,Prometheus 内存吃了 16G。用 params 精确指定,必要时在 relabel 里 drop 掉不必要的 label。

应用服务层:RED 与 USE 结合,抓准瓶颈

应用层监控,我全用 RED 方法(Rate, Errors, Duration) 来做 HTTP/gRPC 服务的黄金指标。加上 USE(Utilization, Saturation, Errors)看线程池、连接池饱和度。

在这个场景下,必须按调用链路来组织指标,否则你根本不知道是网关超时还是下单服务把库存服务拖慢了。我们用的是 Micrometer(Java)给 Spring Boot 暴露 Prometheus endpoint,Go 就用 promhttp。

示例:下单服务的指标暴露(Java,Spring Boot 2.7):

@Bean
public MeterRegistryCustomizer<PrometheusMeterRegistry> metricsCommonTags() {
    return registry -> registry.config().commonTags(
        "service", "order-service",
        "version", "2.1.0"
    );
}

然后要在 Prometheus 抓取配置里增加这个 pod 的注解发现。我用的是 podmonitor(prometheus-operator),等效的静态配置类似:

- job_name: 'order-service'
  kubernetes_sd_configs:
    - role: pod
  relabel_configs:
    - source_labels: [__meta_kubernetes_pod_label_app]
      action: keep
      regex: order-service
    - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_path]
      action: replace
      target_label: __metrics_path__
      regex: (.+)

这里我多强调一句:一定要把服务名和版本打进指标的标签里,否则上线发布时你没法对比新旧版本的错误率和延迟,只能盲回滚。

对于数据库连接池的饱和度,我单独采集 HikariCP 的指标(如果是 Go 就采 db.Stats)。曾经因为没有采 hikaricp_active_connections,结果流量上来连接池被打满,服务假死,应用层显示 502,基础层什么报警都没有。现在我的告警规则里有一条:

groups:
  - name: application
    rules:
      - alert: HighConnectionPoolUsage
        expr: hikaricp_active_connections / hikaricp_max_connections > 0.8
        for: 3m
        labels:
          severity: warning
        annotations:
          summary: "实例 {{ $labels.instance }} 连接池使用率超过80%"

业务指标层:监控订单、支付、库存的“真实血量”

这一层才是最体现电商特性的地方。就算你的所有服务都返回 200,只要用户不能下单,那就是故障。指标从业务日志或数据库从库中提取,比如:

  • 每分钟下单数
  • 支付成功率(支付回调失败/超时占比)
  • 库存扣减失败率
  • 优惠券核销率异常(突然跌零)

这些指标通常用 埋点 SDK定时任务查询数据库 实现。我个人倾向在服务里直接埋点暴露成 Prometheus counter,因为时效性好,而且和调用链路关联上。比如下单成功计数器:

Counter orderSuccessCounter = Counter.builder("biz_order_success_total")
    .description("成功下单数量")
    .register(meterRegistry);
// 在业务逻辑成功后
orderSuccessCounter.increment();

然后配一条告警:最近5分钟下单量相比昨日同期暴跌超过50%。这个规则要用 PromQL 的 offset 来做:

- alert: OrderDropRateAbnormal
  expr: |
    (
      rate(biz_order_success_total[5m])
      /
      rate(biz_order_success_total[5m] offset 1d)
    ) < 0.5
  for: 5m
  labels:
    severity: critical
  annotations:
    summary: "订单量同比暴跌超过50%,疑似故障"

老实说,这种同比告警在白天可能误报(因为业务波动),但夜间量小的时候很准,好几次帮我抓住了凌晨的数据管道中断。


告警怎么设计才不变成“狼来了”

以前我们的告警多到值班同事直接把 PagerDuty 静音。后来我定了三条铁律,效果还行:

  1. 告警必须可行动:凡是接到告警,看 summary 就知道该重启服务还是查数据库。不可以行动的监控项,只做看板,不报警。
  2. 收敛和分级:只有 critical 级别推送电话,warning 进群消息。同一个服务在10分钟内重复告警合并。
  3. 依赖链告警:当数据库故障时,抑制下游服务的连接池告警,否则告警风暴能把人埋了。

Alertmanager 的配置片段:

route:
  receiver: 'default'
  group_by: ['alertname', 'service']
  group_wait: 10s
  group_interval: 5m
  repeat_interval: 4h
  routes:
    - match:
        severity: critical
      receiver: 'oncall-phone'
      continue: true
    - match:
        severity: warning
      receiver: 'slack-warning'
inhibit_rules:
  - source_match:
      alertname: 'MySQLDown'
    target_match_re:
      alertname: '.*ConnectionPool.*'
    equal: ['env']

小心,这里的 group_intervalrepeat_interval 很关键。我当初设过 group_interval: 1m,结果一个抖动能刷几十条消息。5分钟是个比较平衡的值,大促期间可以临时改成1分钟。


链路追踪和日志必须和指标打通

单看 metric 有时候不能定位根因,比如错误率高了,你很难知道是哪个下游超时。我个人觉得,必须让 metric、trace、log 能互相跳转。实现方式:在日志里注入 trace ID,在 Grafana 的 dashboard 里放个 link 到 Jaeger 的查询。

我们在 Spring Cloud 项目里用的是 Sleuth + Zipkin,后来切成了 OpenTelemetry。不管哪个,关键是确保 trace ID 出现在日志里,例如在 logback 里配置:

<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} traceId=%X{traceId} spanId=%X{spanId} - %msg%n</pattern>

然后在 Grafana 面板上放一个 dashboard link,${__value.raw} 变量可以作为 trace ID 传过去。这个技巧算是个小彩蛋吧,很多资料不讲。

说个实际案例:去年双11发现订单创建延迟飙高,通过 metric 定位到库存服务变慢,但库存服务自身 CPU 不高。然后从日志的 trace ID 打开链路,发现是在调用第三方风控接口时超时重试。没有打通这三者,很可能就在那儿调优 JVM 半天,徒劳。

大促保障:流控与压测的监控扩展

平时跑得好好的监控,在秒杀场景下很容易跪。需要额外加两个维度:

  • 限流熔断指标:Sentinel 或 Hystrix 的拒绝次数、降级次数。Sentinel 有 dashboard,但它的 metric 我也拉进了 Prometheus,方便统一告警。
  • 压测流量标识:全链路压测时,我们会在 header 里打 x-stress-test: true,然后在服务里把这个 tag 传给 metric,Grafana 里可以分流量看。别小看这个,有次压测把生产数据污染了,就是从监控面板上发现订单量有两条线才揪出来的。

压测期间,Prometheus 采集间隔从15s临时调到5s,告警评估时间缩短,但事后必须恢复,不然磁盘扛不住。

部署和验证步骤简述

我这里假设你用 Kubernetes,但不用 operator 也能玩:

  1. 部署 Prometheus 和 Alertmanager,映射配置文件和存储卷。
  2. 部署 Grafana,挂载预置的 JSON dashboard(我后面会给个链接)。
  3. 在所有 K8s 节点上以 DaemonSet 部署 node_exporter。
  4. 在业务服务中暴露 metrics 端点,并创建对应的 ServiceMonitor(或静态抓取配置)。
  5. 配置业务埋点,确保 biz_order_success_total 等计数器有数据。
  6. 进入 Grafana 导入 dashboard,看见数据就表示通了。

验证:模拟一次下单接口调用,然后去 Prometheus UI 查询 biz_order_success_total,看是否有增量。再登录 Grafana 的 “电商核心业务大盘”,右上角应该有实时下单速率。

常见坑:Pod 的 metrics 端口不要暴露到公网,用 K8s Service 内部访问就行。我在某次护网行动中,发现有人把 /actuator/prometheus 映射到了公网,所有指标直接裸奔,非常危险。


我的仪表盘长什么样(结构描述)

不想贴一大段 JSON 凑字数,直接说设计思路:

  • 第一行:三个大数字面板——当前订单速率、支付成功率、活跃用户数。旁边小字显示同比昨天。
  • 第二行:RED 指标,下单接口的请求速率、错误率、P95延迟,按服务分列。
  • 第三行:关键中间件,MySQL QPS 与慢查询、Redis 内存与命中率、消息队列积压量。
  • 第四行:基础设施总览,K8s 节点资源使用 TOP,磁盘 IO。
  • 额外有一个 drill-down 链路视图,点击服务名能下钻到该服务详细的 JVM、线程池、依赖调用图。

这个布局是从多次故障复盘中迭代出来的,确保排障者 5 秒内看到业务是否受损,30 秒内定位大致层面。不需要在十几个 tab 间切换。


尾声

整套体系不是一蹴而就的。如果你现在从零开始,我的建议是:先上业务指标和 RED,基础设施那套可以慢慢补,因为基础设施故障往往反映在应用错误率上,不致命的不需要立刻报警。

监控的目标不是消灭告警,而是让每次告警都逼着你做出决策。 任何一条没给出决策方向的告警,都是在浪费人生。

我用的 Prometheus 和 Grafana 版本可能会更新,具体细节以官方文档为准。你有更好的分层方案或者踩过的坑,评论区说说看——或许下个双11我能用上。

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐