面试知识库
中 进阶

可观测性三件套#

一句话答案#

可观测性三件套:Metrics(发现问题)→ Tracing(定位链路)→ Logging(确认根因),三者协同才能在微服务环境下快速排障。

核心要点

全景概览#

维度解决问题典型工具数据形态
Metrics”系统是不是有问题?“Prometheus + Grafana时序数值(Counter/Gauge/Histogram)
Logging”具体报了什么错?“ELK(Elasticsearch + Logstash + Kibana)结构化文本
Tracing”请求经过了哪些服务,哪里慢?“Jaeger / SkyWalking / Zipkin分布式调用链

采集标准现状: OpenTelemetry(OTel)已成为三类数据统一的采集标准(SDK + Collector + OTLP 协议),Traces/Metrics/Logs 三类信号的规范均已 stable(各语言 SDK 成熟度不一);Profiles 作为第四类信号仍在 Alpha。后端存储仍可选 Prometheus / ES / Jaeger 等。

1. Metrics —— 发现问题#

四种指标类型(Prometheus):

类型用途示例
Counter只增不减的累加值请求总数、错误总数
Gauge可增可减的瞬时值当前线程数、队列长度
Histogram分布统计(分桶)请求延迟分布(P50/P99)
Summary客户端计算分位数类似 Histogram,但在客户端算

核心监控指标(RED 方法):

  • Rate:请求速率(QPS)
  • Errors:错误率(5xx 比例)
  • Duration:延迟分布(P50/P99/P999)

告警规则示例:

# 5 分钟内错误率 > 5% 触发告警
- alert: HighErrorRate
  # 分子分母都要 sum 聚合掉 status 标签,否则按标签一一匹配,5xx 序列只会和自己相除
  expr: sum(rate(http_requests_total{status=~"5.."}[5m])) / sum(rate(http_requests_total[5m])) > 0.05
  for: 2m
yaml

2. Logging —— 确认根因#

结构化日志#

为什么用 JSON 而不是纯文本?

  • 纯文本:2026-05-25 10:30:00 ERROR OrderService - 创建订单失败: 库存不足
  • 结构化:
{
  "timestamp": "2026-05-25T10:30:00.123Z",
  "level": "ERROR",
  "service": "order-service",
  "traceId": "abc123def456",
  "spanId": "span789",
  "class": "OrderService",
  "method": "createOrder",
  "userId": 12345,
  "orderId": "ORD-20260525-001",
  "message": "创建订单失败",
  "reason": "库存不足",
  "skuId": "SKU-100"
}
json

结构化日志能被 ES 索引,支持按任意字段搜索和聚合。

TraceID 透传#

请求进入网关 → 生成 TraceID(如 UUID)
  → 放入 HTTP Header(X-Trace-Id)
  → 服务 A 取出放入 MDC(SLF4J)
  → 服务 A 调用服务 B 时透传 Header
  → 所有服务的日志都带同一个 TraceID
  → 在 ELK 中按 TraceID 搜索 → 一次请求的全链路日志
plaintext

Spring Boot 实现: Spring Boot 3+ 用 Micrometer Tracing(桥接 Brave 或 OpenTelemetry)自动生成/透传 TraceID 并放入 MDC,默认用 W3C traceparent 头;Spring Cloud Sleuth 只支持 Spring Boot 2.x,已停止维护。

日志级别规范#

级别用途示例
ERROR需要立即处理的错误数据库连接失败、支付失败
WARN异常但可自愈重试成功、降级生效
INFO关键业务节点订单创建成功、用户登录
DEBUG开发调试信息方法入参出参(生产关闭)

注意: 生产环境日志级别通常设 INFO,不要开 DEBUG——日志量会暴增。

ELK 架构#

应用日志 → Filebeat(采集) → Logstash(解析/过滤) → Elasticsearch(存储/索引) → Kibana(查询/可视化)
plaintext

3. Tracing —— 定位链路#

核心概念#

  • Trace:一次完整请求的调用链,由一个 TraceID 标识
  • Span:Trace 中的一个操作单元(如一次 RPC 调用、一次 DB 查询)
  • Parent-Child:Span 之间的父子关系构成调用树
Trace: abc123
├── Span 1: API Gateway (50ms)
│   ├── Span 2: Order Service (30ms)
│   │   ├── Span 3: MySQL Query (5ms)
│   │   └── Span 4: Redis Get (2ms)
│   └── Span 5: Inventory Service (15ms)
│       └── Span 6: MySQL Update (8ms)
plaintext

Jaeger vs SkyWalking#

维度JaegerSkyWalking
侵入性自身不再提供客户端(Jaeger 客户端 2022 年已退役),用 OpenTelemetry SDK 或 OTel Java Agent 埋点(Agent 也可零代码)Java Agent 自动埋点,零代码侵入
语言支持多语言(Go/Java/Python)以 Java 为主,其他语言支持较弱
功能专注 Tracing 存储与查询(Jaeger v2 基于 OTel Collector 重写,原生收 OTLP)Tracing + Metrics + Logging 一体化
适用多语言微服务Java 技术栈

三者协同排障流程#

1. Grafana 告警:订单服务 P99 延迟从 200ms 飙升到 2s
   ↓
2. Jaeger/SkyWalking 查看慢 Trace:
   发现 Span "Redis Get" 从 2ms 变成 800ms
   ↓
3. Kibana 搜索该 TraceID 的日志:
   发现 Redis 连接池满,等待获取连接
   ↓
4. 根因:Redis 连接数配置过小 + 流量突增
   ↓
5. 修复:调大连接池 + 加连接池监控指标
plaintext

日志敏感信息脱敏#

生产日志中不能出现:

  • 用户密码、Token
  • 完整手机号、身份证号
  • 信用卡号

脱敏方式: 日志框架层做正则替换,或用 Logback 的自定义 Converter。

面试回答(2分钟版)

可观测性三件套是Metrics、Tracing和Logging,三者协同才能在微服务环境下快速定位问题。Metrics回答”系统是不是有问题”,用Prometheus+Grafana监控RED指标(请求速率、错误率、延迟分布),发现P99飙高了就知道有问题。Tracing回答”问题在哪个环节”,通过Jaeger或SkyWalking查看分布式调用链,一个Trace由多个Span组成,能精确看到哪个服务、哪个SQL慢了。Logging回答”具体错了什么”,在ELK中按TraceID搜索,拿到那一次请求经过所有服务的完整日志,确认根因。实际排障流程就是这三步闭环:Grafana告警触发→查Trace定位慢Span→搜日志确认根因→修复→补监控。关键实践:日志必须结构化JSON并透传TraceID,否则微服务环境下日志散落各处根本没法串联。

追问与易错

追问方向:

  • “Metrics 和 Tracing 有什么区别?”→ Metrics 是聚合数据(知道”慢了”),Tracing 是个体数据(知道”谁慢了”)
  • “日志量太大怎么办?”→ 采样(只记录 10% 的 Trace)+ 日志分级 + 冷热分离
  • “你项目中怎么做的监控?”→ 按三层讲清楚即可:① 指标——应用暴露 /actuator/prometheus,Prometheus 抓取,Grafana 看 RED + JVM(GC、堆、线程池)+ 中间件指标,告警走 Alertmanager;② 链路——OTel/SkyWalking Agent 自动埋点,采样率按流量定(如 10%,错误请求全采);③ 日志——JSON 格式带 traceId,Filebeat 采到 ES。最后举一次”告警→查 Trace→查日志→定根因→补监控”的完整排障例子

易错点:

  • ❌ 只有 Metrics 没有 Tracing——知道系统慢但不知道慢在哪
  • ❌ 日志不带 TraceID——微服务环境下无法串联一次请求的完整日志
  • ❌ 所有日志都打 INFO——要么日志太少看不出问题,要么太多找不到重点