可观测性的三大支柱

前面讲监控那篇,我们搭了 Prometheus 指标和 ELK 日志的骨架。但一个微服务请求要经过网关、订单、库存、支付好几跳,用户说「我下单慢了」,你到底该去看哪个服务的指标、查哪台机器的日志?这就是「可观测性」要回答的问题——它不只是装几个监控面板,而是让你能对一个你事先没预料到的问题,也能查清楚。

业界把可观测性拆成三大支柱,三者各司其职、互为补充:

指标告诉你「出事了」,日志告诉你「当时发生了什么」,链路追踪告诉你「是在哪一跳慢的」。缺任何一个,排障都是盲人摸象。
三大支柱一句话
  • Metrics 指标数值化的时间线:QPS、延迟分位数、错误率,最省存储、最适合看趋势和告警。
  • Logging 日志离散的文本事件:出错那次请求的上下文,用来还原现场。
  • Trace 链路一次请求跨服务的完整调用树,用来定位慢在哪一跳、错误在哪一跳。
全链路可观测配图:一条发光追踪曲线流过一排圆柱形服务节点、旁边悬浮仪表盘和柱状图的蓝色扁平科技插画
一次请求像一条发光的线穿过所有服务节点,每一跳的耗时和状态都被记录下来。

Metrics:用指标看趋势

指标是最轻量的观测手段——它只是一个个带时间戳的数字,存得起、算得快、能画趋势。指标分四种类型,选对类型是写好监控的前提:

类型记什么典型例子
Counter 计数器只增不减的累计值请求总数、错误总数
Gauge 仪表盘可上可下的瞬时值当前内存占用、在线人数
Histogram 直方图把观测值分桶统计分布请求延迟(算 P95、P99)
Summary 摘要客户端侧直接算好分位数少数高精度延迟统计

最容易犯的错有两个:一是只看平均值。平均延迟 200ms 很好看,但 P99 可能已经飙到 3 秒——大多数用户走得很快,少数用户卡死,平均值会把这种尾部问题完全藏起来。二是把 Gauge 当 Counter 用,拿瞬时值直接告警。告警永远要落在比率和分位数上:错误率 = 错误数 ÷ 总请求数,延迟看 P95/P99,而不是「现在 QPS 比昨天低了」。

Logging:结构化日志定位现场

指标告诉你「错误率涨了」,但用户具体遇到了什么、那次请求传了什么参数,得翻日志。日志能不能用,关键在结构化:不要打一行自由文本,而是每条日志都带上固定的字段。

// 反例:一行自由文本,没法按字段过滤
log.Info("订单123支付失败了,用户456")

// 正例:结构化字段,谁都能检索
log.Info("pay failed",
  "order_id", "123",
  "user_id", "456",
  "amount", 199.00,
  "trace_id", "abc-xyz",
  "err", "timeout")

这里最关键的字段是 trace_id——一次请求串起来的唯一标识,后面讲 Trace 时它就是那根线。把它塞进每一条日志,你在日志系统里搜一个 trace_id,就能把这次请求跨所有服务打的日志按时间顺序全捞出来。日志的另一条纪律是级别要克制:Info 记正常关键路径,Warn 记可疑但已恢复,Error 记真正需要关注的失败。全是 Error 等于没有 Error,告警很快就会被淹没。

Trace:把一次请求串起来

当一个请求经过网关、订单、库存、支付四个服务,慢了 3 秒。指标面板上每个服务的延迟都正常——那慢在哪一跳?日志里你也不知道该查谁。链路追踪(Tracing)就是给这次请求画一棵树:从进入网关开始,每跨一次服务、每查一次数据库,都记一个 Span(一段耗时),并打上同一个 trace_id 串起来。

Trace abc-xyz 总耗时 3.2s
├─ Span 网关转发        0.02s
├─ Span 订单服务        0.10s
│   └─ Span 订单库查询   0.08s
├─ Span 库存服务        2.90s   ← 瓶颈在这
│   └─ Span 库存库查询   2.85s
└─ Span 支付服务        0.15s

一眼就能看出是库存服务的数据库查询吃掉了 2.85 秒。落地工具上,OpenTelemetry 已经成为事实标准的埋点规范——它把指标、日志、 trace 三种数据用同一套 SDK 打出来,再统一送到后端(Jaeger、Tempo、或云厂商的链路服务)。接入顺序建议:先接 OpenTelemetry SDK 把 trace_id 在服务间传起来,再让日志带上它,最后补指标。三者用同一个 trace_id 打通,才叫「全链路」,否则只是三套互不相干的数据。