分布式追踪把一次跨多个服务的请求,变成一条可以阅读的时间线。HelloWorld指南会从“什么是span和trace”讲起,展示如何在服务里创建span、传播上下文、把数据导出到收集器并在后端可视化,同时讨论采样、性能影响与常见陷阱,给出可落地的配置与调优建议,并带示例。

先把概念讲清楚:分布式追踪的核心是什么
想像你点了一个外卖,订单通过下单服务、支付服务、库存服务、配送服务几次传递。分布式追踪就是在每个环节贴上一个时间标签和说明,把这些片段拼成一条完整的故事线,方便你看到哪一段慢、哪一步出错。
几个必须懂的名词
- Trace:一次完整请求的全路径,由若干span组成。
- Span:Trace中的一个单元,通常对应一次函数调用、一次HTTP请求或一次数据库操作,包含开始时间、结束时间、属性和事件。
- Parent/Child:span之间的父子关系,用来组织调用链。
- Context Propagation:把trace id和span id从一个服务传到另一个服务的方式(常见格式:W3C Trace Context)。
- Sampling:决定保留多少追踪数据以节省成本的策略。
HelloWorld:从零到能看见第一条trace
下面按步骤来做,越简单越实用,目标是在本地运行两个服务(A 调用 B),看到一个从 A 到 B 的 trace。
准备工作(环境)
- 选择语言和 SDK:推荐使用 OpenTelemetry(跨语言且活跃)。
- 准备一个后端:本地可以用 Jaeger 或 Zipkin,也可以用 OpenTelemetry Collector 配合后端。
- 确保服务可以互相通信(HTTP/gRPC),并能把 trace header 传递下去。
实施步骤(概念化,方便记忆)
- 1. 初始化 Tracer:在服务启动时创建 TracerProvider 和导出器(exporter)。
- 2. 在关键路径建 span:比如入口 HTTP handler 创建根 span,调用下游前创建子 span。
- 3. 传播上下文:把 traceparent 或其他 header 带到下游请求头里。
- 4. 导出:把采样后的 span 发送到 Collector 或后端。
- 5. 在后端查看:用 Jaeger 的 UI 或 Zipkin 查看 trace。确认 parent-child 关系和时间线。
小贴士:如何在代码里想清楚 span 添写什么
- span 名称用“动词+资源”形式,如 HTTP GET /orders。
- 把必要的属性(attributes)写清楚:方法、URL、状态码、db.statement(脱敏后)等。
- 把异常用事件记录在 span 里,而不是只记录日志。
关键点详解(你会常犯的错误和如何避免)
上下文没有正确传播
最常见的问题:请求从 A 到 B,trace 信息丢失。排查方法:在发出 HTTP 请求时打印/检查是否携带 trace header。确保所有中间库(HTTP 客户端、消息中间件)都支持或允许传递 header。
采样策略不合理
简单的“全量”会把系统拖垮,过高的采样率会产生成本问题,过低会丢失关键问题。常用方案:
- 固定采样(如 1%)用于长期监控。
- 动态采样(基于错误或高延迟放大采样)。
- 基于规则的采样(例如对关键用户或交易进行保留)。
性能影响被高估或低估
分布式追踪的成本主要来自网络发送、序列化与存储。实践中:
- 使用批量导出减少网络请求次数。
- 非阻塞发送(异步)防止阻塞主请求路径。
- 尽量避免在高频短耗操作里创建大量细粒度 span(评估必要性)。
OpenTelemetry 常用落地配置(要点速览)
下面是一个简化思路,具体参数随 SDK 语言和版本不同而略有差异。
- 启用资源(service.name、service.version)。
- 配置采样器(ParentBased + TraceIdRatioBased 常见)。
- 设置批量导出器(exporter)与上报间隔。
- 启用自动注入 HTTP/gRPC/DB instrumentation(减少手工工作)。
示例:span 字段表
| 字段 | 作用 |
| trace_id | 标识一次完整请求 |
| span_id | 标识一个 span |
| parent_id | 父 span 的 id(若有) |
| name | 可读名字,如 HTTP GET /api |
| start/end 时间 | 用于计算耗时和可视化时间线 |
| attributes / events | 存放 key-value 信息和关键事件 |
如何把追踪和日志、指标结合起来
追踪告诉你“哪里慢了”,日志和指标补充“为什么慢”。实践建议:
- 在 trace 上写入 trace_id 到日志(或使用自动注入),实现可跳转。
- 在指标里打标签(tag)以便按服务/endpoint 聚合延迟分布。
- 把错误率高的 trace 做为采样放大对象,便于事后分析。
进阶话题:消息队列、异步任务与 Baggage
异步系统里上下文传播更复杂,常见策略:
- 把 trace header 放到消息属性(例如 Kafka message headers),消费方读取并继续创建子 span。
- 慎用 baggage(会随每次请求传输,可能增大网络负担),只放小量关键元数据。
- 对延迟敏感的任务,使用同步 span 或在任务入队时创建标记事件以便追溯。
常见排查流程(像在调真实服务那样)
- 先看整体:是全链路都慢还是某个服务慢?
- 定位单个 trace:看耗时最多的 span 和发生错误的 span。
- 检查上下文是否断开(parent missing)以确认传播是否失败。
- 对高延迟或高错误的路由,开启更高采样或抓取原始日志以复盘。
常见工具 / 名词参考(便于查文档)
- OpenTelemetry(OTel)— SDK 与标准。
- Jaeger / Zipkin — 常见的可视化后端。
- OpenTelemetry Collector — 用于聚合、处理、导出 trace 的中间层。
写到这里我还想补一点:开始不要一上来就追求“完美”和“全覆盖”。先在关键业务路径上做起,保证 trace 的连续性和基本属性的规范,逐步扩展自动化与采样策略。实践中你会发现,分布式追踪更像做侦探工作,数据给出线索,工具帮你把线索串起来。祝你很快看到第一条从入口到数据库的完整时间线,那种“找到问题根源”的感觉,真是挺爽的。