4. 监控体系搭建:三大支柱

监控体系,说白了就是SLA保障的“眼睛”。没有它,故障排查就像蒙着眼睛走夜路。我个人习惯把监控拆成三个维度:指标、日志、链路追踪。业内管这叫“三大支柱”,我觉得挺贴切。

你想想看,一个系统出问题了,你总得知道“哪里出了问题”、“为什么出问题”、“影响范围有多大”吧?指标告诉你“哪里”,日志告诉你“为什么”,链路追踪告诉你“影响范围”。三者缺一不可。

4.1 指标监控(Metrics)—— 先知道“坏了”

指标监控是基础。它回答的是“系统健康吗?”这个核心问题。我见过不少团队,一上来就搞链路追踪,结果基础指标都没配全,出事了连CPU打满都不知道。

指标监控的核心是“黄金信号”。Google SRE 那本书里提过四个:延迟、流量、错误、饱和度。我个人习惯再加一个“资源水位”,一共五个维度。

维度 说明 常见指标
延迟 请求处理耗时 P50/P95/P99 响应时间
流量 系统负载压力 QPS、TPS、并发连接数
错误 请求失败率 HTTP 5xx 率、超时率
饱和度 资源使用程度 CPU/内存/磁盘使用率
资源水位 容量余量 连接池使用率、队列深度
我的习惯:指标采集用 Prometheus + Grafana 这套组合。Prometheus 拉模式适合微服务,Grafana 做可视化。别用推模式,维护成本高。

举个例子,我曾经遇到一个数据同步任务,每天凌晨3点准时超时。查了半天,发现是凌晨有全量备份任务,把磁盘IO打满了。如果当时配了“磁盘IO饱和度”指标,一眼就能看出来。

4.2 日志监控(Logging)—— 搞清楚“为什么”

指标告诉你“坏了”,日志告诉你“为什么”。日志是故障排查的“黑匣子”。

日志监控有三大原则:结构化、集中化、可检索。我见过最坑的日志,就是那种纯文本、无格式、散落在各个服务器上的。出事了,你连 grep 都不知道从哪开始。

避坑指南:我曾经接手过一个项目,日志打印了海量信息,但全是 INFO 级别。真正有用的 ERROR 日志,被淹没在“请求开始”、“请求结束”这种废话里。后来我强制要求:ERROR 日志必须包含异常堆栈、请求ID、业务上下文。

日志采集架构,我推荐用 Filebeat + Kafka + Logstash + Elasticsearch 这条链路。Filebeat 轻量,Kafka 做缓冲,Logstash 做解析,ES 做存储和检索。

# 一个标准的日志格式(JSON 结构化)
{
  "timestamp": "2024-01-15T10:30:00.123Z",
  "level": "ERROR",
  "service": "data-sync-service",
  "trace_id": "abc123def456",
  "message": "数据写入HBase超时",
  "stack_trace": "com.example.DataSyncException: ...",
  "context": {
    "table": "user_profile",
    "row_key": "user_10001",
    "retry_count": 3
  }
}

你看,这种日志,在 Kibana 里一搜 trace_id,整个请求的上下文全出来了。排查效率能提升好几倍。

4.3 链路追踪(Tracing)—— 定位“在哪坏了”

微服务架构下,一个请求可能经过十几个服务。指标和日志只能告诉你“某个服务有问题”,但链路追踪能告诉你“具体是哪个调用环节出了问题”。

链路追踪的核心是“Trace”和“Span”。一个 Trace 代表一次完整的请求,一个 Span 代表请求中的一个步骤。每个 Span 都记录了开始时间、结束时间、父 Span ID。

核心概念:
  • Trace ID: 全局唯一,标识一次完整请求
  • Span ID: 标识请求中的单个操作
  • Parent Span ID: 标识父子关系,形成调用树
  • Duration: 每个操作的耗时

我常用的链路追踪工具是 Jaeger。它和 OpenTelemetry 协议兼容,部署简单。你只需要在代码里埋点,把 Trace 信息透传下去就行。

// 伪代码:在服务间透传 Trace 信息
// 服务A 调用 服务B 时,在 HTTP Header 中传递
headers.put("traceparent", "00-${traceId}-${spanId}-01");

// 服务B 收到请求后,从 Header 中提取 Trace 信息
String traceparent = request.getHeader("traceparent");
// 解析 traceparent,创建新的 Span
Span span = tracer.buildSpan("serviceB.process")
    .asChildOf(extractContext(traceparent))
    .start();

我记得有一次,数据产品报表生成特别慢。指标看 CPU 和内存都正常,日志也没报错。最后靠链路追踪发现,是某个下游的 Redis 缓存查询,因为缓存穿透,每次都要查数据库,耗时从 2ms 变成了 200ms。如果没有链路追踪,这种问题根本定位不到。

4.4 三大支柱的关系

指标、日志、链路追踪,不是互相替代的关系,而是互补的。我画了一张图,帮你理解它们之间的关系。

监控体系三大支柱关系图 指标监控 Metrics 日志监控 Logging 链路追踪 Tracing 核心能力 指标:发现异常 → 日志:定位原因 → 链路:追踪路径 数据流:告警触发 → 查看指标 → 关联日志 → 链路追踪 → 根因定位 Prometheus + Grafana 指标采集与可视化 ELK Stack 日志采集与检索 Jaeger / Zipkin 链路追踪与分析 三者联动,才能实现从“发现异常”到“根因定位”的完整闭环

你看这张图,从左到右,从指标到日志再到链路追踪,是一个层层递进的关系。指标先报警,告诉你“出事了”;然后你去查日志,看看“为什么出事”;最后用链路追踪,定位“具体在哪出的事”。

我的建议:搭建监控体系时,先搞定指标监控,再上日志,最后搞链路追踪。别一上来就想搞全链路,容易消化不良。先把基础打牢,再逐步完善。

4.5 实战:如何快速搭建

说了这么多理论,来点实际的。如果你从零开始搭建监控体系,我建议按这个步骤来:

  1. 第一步:确定核心指标 —— 先配好黄金信号,每个服务至少要有 QPS、错误率、P99 延迟、CPU/内存使用率。
  2. 第二步:统一日志格式 —— 所有服务输出 JSON 结构化日志,包含 trace_id、service、level、message 等字段。
  3. 第三步:部署链路追踪 —— 用 OpenTelemetry SDK 埋点,把 Trace 信息透传到所有下游服务。
  4. 第四步:建立关联 —— 在日志和指标中带上 trace_id,实现“指标 → 日志 → 链路”的一键跳转。
  5. 第五步:配置告警 —— 基于指标设置告警规则,告警信息中附带日志查询链接和链路追踪链接。
注意:我曾经见过一个团队,告警配置了上百条规则,结果每天告警几千条,运维人员直接麻木了。告警不是越多越好,要追求“少而精”。我个人的标准是:每条告警都应该能直接指导下一步操作,否则就是噪音。

好了,三大支柱就讲到这里。记住一句话:指标是“眼睛”,日志是“耳朵”,链路追踪是“手”。三者配合,才能把故障排查这件事做好。