微服务可观测性的三大支柱
三大支柱不是「全都要」的清单,而是要按业务场景裁剪。本文用一次完整的链路故障排查过程,说明什么时候看指标、什么时候翻日志、什么时候拉 trace。
为什么有「三大支柱」这回事
「Metrics、Logs、Traces」这个提法来自 Peter Bourgon 和 Cindy Sridharan 在 2017 年前后整理的论文。它解决了一个具体问题:在分布式系统下,「发生了什么」和「为什么发生」需要不同维度的信号。
- Metrics:高度聚合、低成本、能跨时间维度看趋势。
- Logs:原始、详细、不可丢失。
- Traces:结构化、跨服务、解释「调用路径」。
三者各自不同维度,没有冲突,能互补。
Metrics:数字信号
指标是「系统状态的量化值」。常见类型:
| 类型 | 例子 | 使用 |
|---|---|---|
| Counter | 请求数 | 累计计数 |
| Gauge | 当前连接数 | 瞬时值 |
| Histogram | 延迟 | 分位数 |
| Summary | P99 | 客户端聚合 |
指标最适合回答「系统现在 OK 吗」「过去 30 分钟涨了多少」。它不能告诉你「这次失败为什么」。
Logs:原始信号
日志记录「这个时刻发生了什么」。日志的好处是「保留了上下文」。代价是:写入压力大、查询慢、不容易聚合。我们一年处理 200 TB 日志,查询延迟通常 5–30 秒。
日志不是越详细越好。它们应该被设计成「能回答某个具体问题」的颗粒度。
Traces:关系信号
我在另一篇关于 Trace 的文章里专门讲过。但这里想强调:trace 不是「日志的替代」,而是一种新的视角。它最擅长的不是「日志很长」,而是「告诉你这些日志属于同一次请求」。这是故障定位时的「金钥匙」。
三大支柱的取舍矩阵
不同场景对它们的依赖差异很大。我的默认推荐:
- 告警 → 指标(Counter / Histogram)
- 事故还原 → Trace + Log
- 容量规划 → Metric + Service Mesh 数据
- 慢请求归因 → Trace 优先 + Metric 分组
- 代码层 bug → Log(带 trace_id)
一次真实的「分布式排查」
下面是某次事故的复盘。看我们是如何用这三个支柱把问题定位到行级的:
- 告警:调用 B 服务的 P99 突增到 1.8s(Metric Histogram)。
- 看 trace:根据告警时间窗拉取 trace,定位到 B 服务的 status update 节点耗时 1.5s。
- 看 metric:B 服务慢节点的 DB latency 平稳,排除数据库;B 服务的 Redis 调用计数上升。
- 拉日志:在 trace_id 关联的日志中,发现大量
SET key value EX 600 NX失败。 - 根因:该段代码在 NX 失败时进入重试循环,循环次数被某种边界条件放大。
- 修复:加幂等 + 上限 + 重试间隔避让。
可以看到:metric 给出异常、trace 给出路径、log 给出原因。三者缺一不可。
它们之间的「关联键」
三大支柱想要有效联动,必须有「关联键」。最常用的是 trace_id。具体做法:
- 请求进入网关时生成 trace_id。
- 所有调用都透传 trace_id,包括 MQ、HTTP、DB。
- 日志里打
trace_id=...。 - 指标里打
trace_count维度(按 trace_id 维度聚合指标)。
成本与采样
三大支柱的建设成本差异很大:
| 支柱 | 成本 | 优化关键 |
|---|---|---|
| Metric | 低 | 采样率、标签维度 |
| Log | 高 | 落盘策略、冷热分层 |
| Trace | 中高 | 采样策略、属性数量 |
对成本敏感的小团队,可以从「Metric 全量 + Log 抽样 + Trace 头部 1%」起步,再逐步扩展。
把 OpenTelemetry 当成「统一胶水」
未来 2–3 年最值得投入的是 OpenTelemetry。它不是后端,但是自动从代码侧采集三大信号并把它们送到各自的后端。我们的系统迁移到 OTel SDK 后,三大支柱的接入成本下降了一半。
几条非技术但很关键的事
- 三大支柱选型一定不要被「指标数量」「日志总量」迷惑,要看它们的「查询体验」。
- 让任何一次事故复盘都能查到对应的 trace_id。
- 把数据保留策略写成配置:Metric 180 天,Log 7 天原始 + 90 天归档,Trace 7 天原始。
三大支柱不是工程师的负担,而是工程师对系统的「认知工具」。做好它们,再复杂的系统也讲得清楚。
按团队规模选择技术栈
不同规模的团队对三大支柱的选型差异很大。经验是:
| 团队规模 | Metric | Log | Trace |
|---|---|---|---|
| 小(<10 人) | Prometheus | 轻量 Loki | Jaeger |
| 中(10–50) | Prometheus + Thanos | ELK | Jaeger + OTel |
| 大(>50) | Mimir / Cortex | OpenSearch | OTel + 商业方案 |
选型不是「越新越好」,而是「与团队人力匹配」。
把它们放在一张「故障定位剧本」里
我把事故定位流程标准化为 5 步:
- 看 Metric,确认异常范围和严重度。
- 拉 Trace,找异常调用路径。
- 对每个 Span 看相关 Metric 看细节。
- 查 Log(按 trace_id 索引),找到出错上下文。
- 把结论整理为 Runbook 的一节。
这是 PDCA 在故障响应里的具体落地:先观察,再定位,最后改进。每完成一次,这套剧本都会更稳定,团队的判断也会更快。