Skip to content

可观测性三支柱:日志、指标与链路

本文是微服务系统学习系列的 L2 核心篇。前置:31. API 网关设计。 学完可以配合面试题食用:07. 分布式追踪08. 日志与 ELK09. 监控

为什么需要三个支柱,不是一个

微服务架构里一个请求会跨 5-10 个服务。出了故障,光看日志没法知道"哪个环节慢";光看指标不知道"具体哪个订单挂了";光看链路不知道"磁盘是不是快满了"。三个维度各自解答不同的问题:

  • 日志:某个具体请求报了什么错,SQL 是什么,参数是多少。个体视角。
  • 指标:这 5 分钟接口平均延迟多少,错误率多少,CPU 用了多少。聚合视角。
  • 链路:一个请求从网关到某个服务到数据库,每步花了多少毫秒。路径视角。

三者互补,缺一个就瞎一只眼。下面分别讲落地方式。

结构化日志:别再用 println 了

日志的进化路径:System.out -> 按格式拼接 -> 结构化 JSON。大多数人停在第二步。

非结构化的痛点

java
log.info("Order {} processed, user={}, amount={}", orderId, userId, amount);

输出是 Order 10086 processed, user=9527, amount=199.0。要搜索"金额超过 100 的订单"得写正则,要按用户 ID 聚合得先提取子串——ELK 里没法直接做字段查询。

结构化的解法

Logback 配置 JSON encoder(依赖 logstash-logback-encoder):

xml
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
  <encoder class="net.logstash.logback.encoder.LogstashEncoder">
    <includeContext>false</includeContext>
    <customFields>{"app":"order-service","env":"prod"}</customFields>
  </encoder>
</appender>

输出变为:

json
{"@timestamp":"2025-11-21T10:30:00.123+08:00","level":"INFO","message":"Order processed","app":"order-service","logger":"com.example.OrderService","order_id":"10086","user_id":"9527","amount":199.0}

直接搜 amount > 100 或者按 user_id 聚合都行。traceId 必须每条日志都带,这是日志和链路关联的桥梁。

采样策略

  • ERROR 以上全量保留(异常不常见)
  • INFO 按 1:10 采样(量大的业务日志)
  • DEBUG 只保留最近 30 分钟,滚动覆盖

指标体系:RED 和 USE 就够了

指标不是越多越好。每增加一个指标面板,排查时多一个分心项。两个方法论覆盖绝大多数场景:

RED 法(服务视角):
  Rate     - 每秒请求数(QPS/TPS)
  Errors   - 错误率(5xx/4xx/业务异常占比)
  Duration - 延迟分布(P50/P90/P99)

USE 法(资源视角):
  Utilization - 利用率(CPU/内存/磁盘 IO)
  Saturation  - 饱和度(线程池队列长度/连接数)
  Errors      - 错误数(磁盘坏道/超时重试次数)

用 Prometheus 暴露指标就一个注解:

java
@RestController
public class OrderController {
    private final Counter orderCounter = Counter.build()
        .name("orders_created_total")
        .help("Total orders created")
        .labelNames("status")
        .register();

    @GetMapping("/order/{id}")
    public Order getOrder(@PathVariable String id) {
        orderCounter.labels("success").inc();
        // ...
    }
}

配合 Grafana 大盘,一个页面看全服务的 RED 指标。告警不要只配阈值,用基于趋势的异常检测(比如错误率 5 分钟滚动比前 30 分钟翻倍触发),避免运维半夜被误报整醒。

分布式追踪:OpenTelemetry 统一标准

在混乱的链路追踪工具里,OpenTelemetry(OTel)已经成了事实标准——把 Jaeger/Zipkin/SkyWalking 的协议统一了。

核心概念

请求 -> 网关生成 TraceId: abc123
         └─ SpanId: 001(网关处理)
              ├─ 调用服务A: SpanId 002, ParentSpanId 001
              │    └─ 查数据库: SpanId 003, ParentSpanId 002
              └─ 调用服务B: SpanId 004, ParentSpanId 001

TraceId 贯穿整条调用链,SpanId 标记每个节点,ParentSpanId 拼出调用树。上下文通过 HTTP 头的 traceparent 字段传播:

traceparent: 00-0af7651916cd43dd8448eb211c80319c-b7ad6b7169203331-01

格式:版本-traceId-spanId-traceFlags。这是个 W3C 标准,Spring Boot 3.x 的 RestTemplate/WebClient 自动携带。

OTel 接入

Spring Boot 3.x 引入 opentelemetry-javaagent.jar 就能自动埋点——零代码改动。启动参数加一行:

bash
-javaagent:opentelemetry-javaagent.jar \
-Dotel.service.name=order-service \
-Dotel.exporter.otlp.endpoint=http://jaeger:4318

框架层面的 HTTP 请求、数据库调用、消息队列操作都会自动生成 Span。需要自定义埋点就用 @WithSpan 注解:

java
@WithSpan("calculate-discount")
public BigDecimal calculateDiscount(Order order) {
    // 这个方法会被追踪
}

落地架构:选型对比

组件选型理由
日志收集Loki(而非 ELK)和 Prometheus 同一家公司,标签查询一致,资源占用低于 ES
指标存储Prometheus社区成熟,Grafana 原生支持,Pull 模式避免集群压力
链路存储Jaeger原生支持 OTel 协议,部署简单,查询 UI 够用
可视化Grafana统一面板,日志/指标/链路可以关联跳转

Grafana 面板可以用 Explore 模式直接查 PromQL 和 LogQL,快速定位故障。每张面板配一个关键信息就够了,别堆叠。

json
{
  "title": "服务 RED 面板",
  "panels": [
    {"title": "QPS", "expr": "rate(http_requests_total[1m])"},
    {"title": "错误率", "expr": "rate(http_requests_total{status=~\"5..\"}[1m]) / rate(http_requests_total[1m])"},
    {"title": "P99 延迟", "expr": "histogram_quantile(0.99, rate(http_request_duration_seconds_bucket[1m]))"}
  ]
}

常见误区与小结

  • 日志不统一格式:不同服务用不同日志格式,排查时没法联合查询。统一 JSON 格式是底线。
  • 指标打太多标签:每个标签组合增加一个时间序列,user_id 这种高基数标签会让 Prometheus 内存爆炸。高基数场景用日志查。
  • 链路只接一个服务:链路追踪的价值在于跨服务关联,只接一个服务等于白接。
  • 告警一锅端:阈值告警太多反而降低响应速度。用 SLO 驱动的告警——先定目标(99.9% 的请求 200ms 内返回),再配告警。
  • 缺了成本视角:全量采集一天 TB 级日志,只采到下个月预算就超了。明确保留周期和采样率。

小结:可观测性在微服务里不是"要不要"的问题,是"怎么做得可维护"的问题。三支柱各司其职,通过 traceId 串联。下一篇 33. 微服务治理实战 讲灰度发布、混沌工程和 K8s 落地。

参考

参考:OpenTelemetry 官方文档(opentelemetry.io)、Google SRE 手册 Monitoring 章节、Prometheus 官方最佳实践

手撕 → 框架 → 生产化,一步步把 AI Agent 工程化搞透。
粤ICP备2026104257号-1