你有没有过这样的经历:线上某个接口开始变慢,用户投诉不断,你打开监控面板——CPU 正常、内存正常、数据库连接数正常,日志里刷了十几万行 INFO,却偏偏找不到那条请求到底卡在哪一步。单体时代,一次调用就是一条直线,翻日志还能勉强推断;可当系统拆成几十个微服务、一次下单要穿过七八个服务、还要经过网关、队列和缓存之后,”谁把这条请求拖慢了”就变成了一道解不开的谜题。这篇文章想聊的,就是怎么用分布式链路追踪(Distributed Tracing)把这条谜题变成一道有解的题。

一、为什么日志和指标救不了你
可观测性这个词现在被提得很多,但很多团队其实只做了半套:日志(Logging)和指标(Metrics)各攒了一大堆,真正出问题时依然抓瞎。原因不复杂——它们各自回答的是不同层面的问题,谁都没法单独回答”这一次请求”的经历。
指标擅长回答”系统整体怎么样”。比如 QPS、P99 延迟、错误率,它们是聚合后的数字,能告诉你”事情变糟了”,但几乎不告诉你”糟在谁身上”。你看到 P99 从 200ms 涨到 2s,接下来只能靠猜:是数据库?是下游某个服务?还是网关?指标本身没有携带请求的上下文,它是把成千上万次请求碾碎后剩下的统计粉末。
日志擅长回答”某个点发生了什么”。它记录得足够细,但问题是分散的:一次请求的痕迹被切碎在七八个服务的日志文件里,每个服务用的 trace 字段格式还各不相同,时间戳的机器时钟偏差从几毫秒到几百毫秒不等。你想把一次调用串起来,得先有一根能穿透所有服务的”线”,再靠人工捞日志——这在服务数量超过三五个之后就彻底失效了。
于是问题就卡在这里:指标告诉你”哪里疼”,日志告诉你”哪里红”,但没有人告诉你”这次请求走过的完整路径长什么样”。而这,恰恰是链路追踪存在的唯一理由——它不是给日志和指标再加一层装饰,而是给一次请求发一张全程通用的身份证,让它无论穿过多少个服务,都能被完整地认出来。
二、链路追踪的三层实现,别一步跨太大
很多团队一听链路追踪就直奔 OpenTelemetry、Jaeger、SkyWalking 全家桶,结果埋点埋了三个月,一半服务还接不进来。其实这件事可以拆成三层来做,每一层都有独立价值,不必一步到位。
第一层:统一上下文传递。这是最便宜也最有用的一层。核心只有一件事——让 trace ID 和 span ID 跟着请求走完全程。HTTP 调用走 header,消息队列走消息属性,RPC 框架走隐式的 context。只要把这一层做扎实,你立刻就能做到一件事:在日志里按 trace ID 搜索,一次捞出这次请求在所有服务里留下的全部日志。很多团队的排障效率,光是这一层就能提升一大截,成本却极低——不需要任何后端系统,不需要采样策略,只需要一个统一的日志字段。
第二层:本地采样与埋点。当请求路径需要被”画出来”而不只是”搜出来”时,就得在每个关键节点记录 span:进入时间、离开时间、状态、关键属性。这一层要克制。不要试图记录每一个函数调用,那会让系统本身成为瓶颈;而是聚焦在跨服务边界、外部依赖(数据库、缓存、第三方 API)和业务关键步骤上。同时采样策略要提前想好:全量采集在高流量下会压垮存储,通常采用头部采样(按比例)加尾部采样(错误请求和慢请求全留)的组合,既控制成本,又不放过真正重要的样本。
第三层:统一收集与关联分析。前两层产生的数据都是碎片,第三层才把它们拼成完整视图——一个 Trace 后端接收、存储并可视化这些 span,让你能一眼看到”这次请求在哪个服务花了 1.8 秒”,还能把 Trace 与同一请求的日志、与这段时间的指标关联起来。到这一层,排障才真正从”翻日志猜”变成”看瀑布图定位”。三层不是必须依次做完才能见效,而是每一层单独上线都有收益,这是它和”重写监控体系”最大的区别。

三、落地时最容易踩的三个坑
知道了该怎么做,还得知道哪里容易翻车。链路追踪落地最常见的三个坑,几乎每个团队都会遇到至少一个。
坑一:把采样率当拍脑袋的配置。采样率定高了,存储成本爆炸;定低了,关键请求刚好没被采到,出问题时还是一样瞎。稳妥的做法是分层采样:入口按 1%~5% 的比例常规采样,保证面上的统计;对错误响应的请求做”错误全采”;对超过阈值的慢请求做”慢请求全采”;再额外保留一部分高优业务的全量。这样既控住了成本,又保证真正有价值的样本不会被概率筛掉。关键是要在代码里显式实现这套策略,而不是让默认配置替你做决定。
坑二:span 埋得太深、太密。有人觉得埋点越多越好,把每个方法都包一层,结果一个请求产生上千个 span,Trace 后端处理不过来,工程师看瀑布图时被淹没在无意义的分支里。埋点要有取舍:跨进程调用必埋,外部 IO 必埋,业务的关键状态变化值得埋,内部的小函数循环则是噪音。原则很简单——你希望自己在排障时看到哪些信息,就埋哪些。
坑三:trace 与日志、指标彼此割裂。这是最隐蔽的坑。链路追踪上线后,如果没有把 trace ID 写进日志、没有把 trace 里的耗时导出成指标,那它就只是又一个孤立系统。真正有用的做法是三者的双向关联:从慢 Trace 上一键跳到同一 trace ID 的全部日志,从异常指标下钻到代表这次异常的样本 Trace。这层关联做不做,决定了链路追踪是”一个漂亮的玩具”还是”排障的武器”。

结语
分布式链路追踪从来不是”装上就万事大吉”的组件,它更像是一次关于系统认知的升级——你不再把系统看成一堆各自为战的指标和日志,而是看成一条条可以被完整还原的请求之旅。第一层统一上下文让请求有了身份证,第二层采样埋点让旅程被记录下来,第三层收集关联让无数碎片拼成全貌,三者各司其职,缺一环就少一分洞察。
值得提醒的是,链路追踪解决的是”看得见”的问题,而”看得见”只是起点。真正决定系统稳定性的,是你看到慢 Trace 之后能不能定位到根因、能不能推动修复、能不能让它不再复现。工具帮你缩短从”出问题”到”看懂问题”的距离,而缩短从”看懂问题”到”解决问题”的距离,还得靠人和流程。
如果你的系统正被”不知道慢在哪”困扰,不妨从最便宜的第一层开始:先让 trace ID 跟着所有请求走完全程。这一步可能只花你一天,却能让后面所有的排障故事,都变得不那么像一场赌博。