分布式追踪核心概念
分布式追踪核心概念
什么是分布式追踪
在微服务架构中,一个用户请求可能经过十几个甚至上百个服务。分布式追踪(Distributed Tracing)用于跟踪和分析请求在各个服务间的完整调用链路。
为什么需要分布式追踪
传统单体应用:
用户请求 → 应用服务器 → 数据库
↓
日志文件(容易定位问题)
微服务架构:
用户请求
↓
API Gateway (10ms)
├→ 用户服务 (50ms)
├→ 订单服务 (2000ms) ← 性能瓶颈!
│ ├→ 库存服务 (100ms)
│ └→ 支付服务 (1800ms) ← 真正的问题!
├→ 推荐服务 (30ms)
└→ 通知服务 (20ms)
问题:
- ❌ 用户反馈"页面很慢",但不知道哪个服务慢
- ❌ 查看日志需要跨多个服务、多个实例
- ❌ 无法了解服务间的依赖关系
- ❌ 难以定位级联故障的根因
分布式追踪的价值:
- ✅ 可视化调用链路:一目了然看到完整请求路径
- ✅ 定位性能瓶颈:快速找到慢的服务和方法
- ✅ 分析依赖关系:了解服务拓扑和调用关系
- ✅ 故障诊断:快速定位错误发生的位置
核心概念
1. Trace(追踪)
Trace 表示一次完整的请求调用链,包含多个 Span。
Trace ID: abc123456789
Duration: 2190ms
Services: 5
Spans: 12
用户请求 /order/create
├─ API Gateway
├─ 订单服务
│ ├─ 数据库查询
│ └─ 库存检查
├─ 支付服务
│ └─ 第三方支付接口
└─ 通知服务
属性:
- Trace ID:全局唯一标识符
- Duration:总耗时
- Start Time:开始时间
- Services:涉及的服务数量
- Status:成功/失败
2. Span(跨度)
Span 是 Trace 中的一个操作单元,代表一个服务中的一段处理过程。
Span:
Trace ID: abc123456789
Span ID: span-001
Parent Span ID: null
Service: order-service
Operation: POST /api/orders
Start Time: 2024-01-09 10:00:00.000
Duration: 200ms
Status: OK
Tags:
http.method: POST
http.url: /api/orders
http.status_code: 200
user.id: 12345
Logs:
- timestamp: 10:00:00.050
event: "db.query.start"
message: "SELECT * FROM products"
- timestamp: 10:00:00.150
event: "db.query.end"
rows: 5
Span 属性:
- Span ID:Span 的唯一标识
- Parent Span ID:父 Span ID(构建调用树)
- Operation Name:操作名称
- Start/End Time:开始和结束时间
- Duration:耗时
- Tags:键值对元数据
- Logs:时间点事件
3. Tags(标签)
Tags 是 Span 的元数据,用于查询和过滤。
常用标签:
# HTTP 相关
http.method: GET
http.url: /api/users/123
http.status_code: 200
# 数据库相关
db.type: mysql
db.instance: users_db
db.statement: SELECT * FROM users WHERE id=?
# 消息队列
message_bus.destination: order_queue
message_bus.message_id: msg-123
# 错误相关
error: true
error.kind: DatabaseException
error.message: "Connection timeout"
# 业务相关
user.id: 12345
order.id: ord-98765
payment.method: credit_card
4. Logs(日志)
Logs 是 Span 内的时间点事件,记录关键操作。
{
"timestamp": "2024-01-09T10:00:00.050Z",
"event": "cache.miss",
"fields": {
"key": "user:12345",
"reason": "key_not_found"
}
}
与传统日志的区别:
| 维度 | 传统日志 | Tracing Logs |
|---|---|---|
| 关联性 | 独立的日志行 | 关联到 Span |
| 上下文 | 有限 | 完整的 Trace 上下文 |
| 查询 | 文本搜索 | 结构化查询 |
| 聚合 | 困难 | 自动聚合 |
5. Context Propagation(上下文传播)
上下文传播是分布式追踪的核心机制,通过 HTTP Header、消息队列 Header 等传递 Trace 信息。
HTTP Header 传播
Service A → Service B
Request Headers:
X-B3-TraceId: abc123456789
X-B3-SpanId: span-001
X-B3-ParentSpanId: span-000
X-B3-Sampled: 1
常见格式:
- B3 Format(Zipkin):
X-B3-TraceId,X-B3-SpanId - W3C Trace Context:
traceparent,tracestate - Jaeger Format:
uber-trace-id
代码示例
// Service A 发起请求
func callServiceB(ctx context.Context) {
// 1. 从上下文提取 Trace 信息
span := opentracing.SpanFromContext(ctx)
// 2. 创建 HTTP 请求
req, _ := http.NewRequest("GET", "http://service-b/api", nil)
// 3. 注入 Trace 信息到 Header
opentracing.GlobalTracer().Inject(
span.Context(),
opentracing.HTTPHeaders,
opentracing.HTTPHeadersCarrier(req.Header),
)
// 4. 发送请求
resp, _ := http.DefaultClient.Do(req)
}
// Service B 接收请求
func handleRequest(w http.ResponseWriter, r *http.Request) {
// 1. 从 Header 提取 Trace 信息
spanCtx, _ := opentracing.GlobalTracer().Extract(
opentracing.HTTPHeaders,
opentracing.HTTPHeadersCarrier(r.Header),
)
// 2. 创建新的 Span(作为子 Span)
span := opentracing.StartSpan(
"handle_request",
opentracing.ChildOf(spanCtx),
)
defer span.Finish()
// 3. 处理业务逻辑
processRequest(r)
}
追踪系统架构
标准架构
┌─────────────────────────────────────────────┐
│ Application Layer │
│ ┌─────────────────────────────────────┐ │
│ │ Application Code │ │
│ │ + Tracing Library (SDK) │ │
│ └──────────────┬──────────────────────┘ │
└────────────────┼────────────────────────────┘
│ 发送 Spans
▼
┌─────────────────────────────────────────────┐
│ Collection Layer │
│ ┌──────────────┐ ┌──────────────┐ │
│ │ Agent/Sidecar│ │ Collector │ │
│ │ (可选) │ │ (聚合、验证) │ │
│ └──────┬───────┘ └──────┬───────┘ │
└─────────┼──────────────────┼─────────────────┘
│ │
▼ ▼
┌─────────────────────────────────────────────┐
│ Storage Layer │
│ ┌──────────────────────────────────────┐ │
│ │ Storage Backend │ │
│ │ - ElasticSearch │ │
│ │ - Cassandra │ │
│ │ - Memory (开发) │ │
│ └──────────────┬───────────────────────┘ │
└─────────────────┼───────────────────────────┘
│
▼
┌─────────────────────────────────────────────┐
│ Query & UI Layer │
│ ┌──────────────────────────────────────┐ │
│ │ Query Service + Web UI │ │
│ │ - 搜索 Traces │ │
│ │ - 可视化调用链 │ │
│ │ - 性能分析 │ │
│ └──────────────────────────────────────┘ │
└─────────────────────────────────────────────┘
采样策略
为了降低性能开销,通常只采样部分请求。
1. 固定比例采样
// 10% 采样率
sampler := jaeger.NewConstSampler(0.1)
2. 速率限制采样
// 每秒最多 100 个 Traces
sampler := jaeger.NewRateLimitingSampler(100)
3. 自适应采样
// 根据负载动态调整
sampler := jaeger.NewAdaptiveSampler(
jaeger.SamplingStrategyResponse{
OperationSampling: &jaeger.PerOperationSamplingStrategies{
DefaultSamplingProbability: 0.1,
PerOperationStrategies: []jaeger.OperationSamplingStrategy{
{
Operation: "POST /api/orders",
ProbabilisticSampling: &jaeger.ProbabilisticSamplingStrategy{
SamplingRate: 1.0, // 重要接口 100% 采样
},
},
},
},
},
)
4. 错误优先采样
// 所有错误请求都采样
if span.Error() {
span.SetTag(ext.SamplingPriority, 1) // 强制采样
}
关键指标
1. 延迟(Latency)
P50: 100ms (中位数)
P90: 250ms (90% 请求在此之内)
P95: 400ms (95% 请求在此之内)
P99: 800ms (99% 请求在此之内)
Max: 2000ms (最大延迟)
2. 错误率(Error Rate)
Total Requests: 10,000
Failed Requests: 50
Error Rate: 0.5%
3. 吞吐量(Throughput)
Requests Per Second (RPS): 500
Traces Per Second (TPS): 450 (采样率 90%)
4. 服务依赖
服务拓扑图:
API Gateway
├→ User Service (100% 依赖)
├→ Order Service (80% 依赖)
│ ├→ Inventory Service
│ └→ Payment Service
└→ Notification Service (50% 依赖)
与日志、监控的关系
可观测性三大支柱
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ Metrics │ │ Logging │ │ Tracing │
│ (指标) │ │ (日志) │ │ (追踪) │
└──────┬──────┘ └──────┬──────┘ └──────┬──────┘
│ │ │
└────────────────┴────────────────┘
│
完整的可观测性平台
各自的作用
| 维度 | Metrics | Logging | Tracing |
|---|---|---|---|
| 回答问题 | 系统健康吗? | 发生了什么? | 为什么慢? |
| 数据类型 | 数值 | 文本事件 | 调用图 |
| 存储成本 | 低 | 高 | 中 |
| 查询速度 | 快 | 慢 | 中 |
| 聚合 | 容易 | 困难 | 中等 |
联动使用
# 1. Metrics 发现问题
Alert: API响应时间 P99 > 1s
# 2. Tracing 定位具体慢的请求
Trace ID: abc123
Duration: 2.5s
问题服务: Payment Service
# 3. Logging 查看详细错误
Payment Service Logs:
[ERROR] Database connection timeout
Connection pool exhausted
OpenTelemetry 标准
OpenTelemetry 是 CNCF 的可观测性标准,统一了 Tracing、Metrics、Logging。
核心组件
┌─────────────────────────────────────┐
│ OpenTelemetry SDK │
│ - Trace API │
│ - Metrics API │
│ - Logs API │
└──────────────┬──────────────────────┘
│
▼
┌─────────────────────────────────────┐
│ OpenTelemetry Collector │
│ - 接收 │
│ - 处理 │
│ - 导出 │
└──────────────┬──────────────────────┘
│
┌──────┴──────┬──────────┐
▼ ▼ ▼
┌────────┐ ┌────────┐ ┌────────┐
│ Jaeger │ │Prometheus│ │ ELK │
└────────┘ └────────┘ └────────┘
优势
✅ 厂商中立:不绑定特定实现
✅ 统一 API:一套代码支持多个后端
✅ 标准化:W3C Trace Context 标准
✅ 功能全面:Trace + Metrics + Logs
总结
核心概念回顾
- Trace:完整的请求调用链
- Span:单个服务的处理单元
- Context Propagation:跨服务传递 Trace 信息
- Sampling:降低性能开销
- Tags & Logs:丰富上下文信息
何时使用分布式追踪
适合场景:
✅ 微服务架构(> 5 个服务)
✅ 性能问题频繁
✅ 服务依赖复杂
✅ 需要故障定位
不太需要:
❌ 单体应用
❌ 服务数量少(< 3 个)
❌ 性能稳定
❌ 简单的调用链
实施建议
第一阶段:
- 选择 Jaeger/Zipkin
- 在关键服务埋点
- 使用低采样率(1-10%)
第二阶段:
- 全服务覆盖
- 自定义 Tags
- 集成告警
第三阶段:
- 迁移到 OpenTelemetry
- 统一 Metrics + Logs + Tracing
- 建立完整可观测性平台
下一节将详细介绍如何在 Kubernetes 中部署 Jaeger。