云上系统的可观测性:从日志、指标到链路追踪的三段演进
写在前面
很多团队第一次提到可观测性时,交付物往往是一块监控大屏:几十个面板、五颜六色的曲线,以及一条在凌晨三点依旧会响的告警。半年后再回头看,面板上大部分曲线再没人点开过,告警被熟练地静音,故障定位仍然靠人在群里问一句你那边日志里有报错吗。
问题不在于工具买得不够多,而在于可观测能力本身是有顺序的。一个云上系统从能跑走到能解释自己为什么这么跑,通常要依次跨过三段:结构化日志、指标体系、链路追踪。跳过任何一段,后面那段都会打折。
第一阶段:先把日志变成可查询的数据
起步阶段最典型的形态,是每个模块各自打印:有人记时间戳,有人不记;有人输出中文描述,有人直接甩一个异常栈;同一件事在三个服务里有三种写法。这种日志能看,但没法查——一旦要回答过去一小时哪个接口变慢了,就只能靠 grep 和运气。
这一步的改造成本极低,收益却最大,核心是三件事:
- 结构化。把 message 拆成字段,至少固定这几个:时间(统一 UTC 或统一带时区的 ISO8601)、请求 ID、服务名、耗时、状态码、错误码。文本描述留在 message 里,但不要让关键字段只存在于文本里。
- 一次请求一个 ID。入口生成 request id 并向下透传,所有日志都带上它。没有这个字段,后面所有跟服务的排查都是在拼图。
- 区分错误和业务事件。用户下单成功不是错误,不该出现在 error 级别里;反过来,一个被 catch 后吞掉的异常也不该只是 info。级别一旦失真,基于级别的告警就全部失效。
一行合格的日志大概长这样:
{"ts":"2026-03-11T08:42:07.113Z","level":"warn","svc":"order-api","rid":"7f3c9a21","path":"/v1/orders","dur_ms":1240,"code":"UPSTREAM_SLOW","msg":"payment rpc exceeded soft timeout"}
它读起来不如一句人话顺,但它可以被聚合、被过滤、被告警规则引用——这才是可查询的含义。
第二阶段:指标体系,以及告警的信噪比
日志解决具体这一次发生了什么,指标解决整体现在怎么样。多数团队会从资源指标开始:CPU、内存、磁盘、网络。这些当然要看,但它们通常是最晚才给出信号的一层——CPU 打满往往是结果,不是原因。
更有用的是应用层的黄金四指标:延迟、流量、错误率、饱和度。对内的服务再补上依赖方的同类指标,基本就够覆盖大部分事故了。注意延迟一定要看分位数:P99 从 200ms 涨到 1.5s,均值可能纹丝不动,但用户已经全部卡在转圈。
有了指标,下一步的坑是告警阈值。常见的失败方式有两种:一是阈值全部定得很紧,于是每天几十条告警,团队训练出了先看是不是又抖一下的条件反射,真正的事故被淹在噪音里;二是全部定得很松,于是第一次响的时候已经是客户在群里反馈了。比较可操作的原则是:只对需要有人立刻做点什么的現象告警,其余一律进面板和周报。告警消息本身也要带上上下文——哪个服务、哪个版本、最近一次变更是什么、对应的看板链接,否则值班同学的第一件事仍然是翻找。
第三阶段:链路追踪把碎片串成时间线
到了微服务阶段,一次用户操作可能穿过网关、鉴权、业务服务、缓存、数据库、消息队列。日志和指标都还在,但慢在哪一跳开始变得难以回答。链路追踪做的事情很朴素:把带 request id 的日志和指标,按调用关系还原成一条时间线。
它的价值在两类问题上特别明显。一类是长尾延迟:一条 trace 里能直接看到某个下游的 P99 拖慢了整条链路,而不必逐个服务去猜。另一类是隐藏的扇出:一次页面渲染对某个数据库发了四十次查询,在指标上只是 QPS 高一点,在 trace 上则是一眼就能看见的串行小柱子。
需要坦白的是成本。全量采集的开销不小,常见做法是按比例采样,再对错误请求和慢请求强制保留。这个策略要提前设计,否则最需要 trace 的时候恰好没有 trace。
落地顺序上的一个建议
如果只能做一件事,先做请求 ID 和结构化日志。它不依赖任何平台,改的是代码习惯,而且是后两段的先决条件:没有稳定的关联字段,指标无法下钻,链路也无法拼接。反过来,先上跟踪系统、日志依旧各行其是,最后往往得到一套很漂亮的、但没人能从中定位问题的界面。
可观测性这个词容易被误解成一种可以采购的能力。实际上它更像工程纪律的副产品:字段规范有没有人守,告警有没有人事后复盘误报,新服务接进来时默认带不带 trace。工具会换,账单会算,这些习惯才是留下来的部分。
- 点赞
- 收藏
- 关注作者
评论(0)