vault backup: 2026-05-05 20:20:15
This commit is contained in:
@@ -0,0 +1,166 @@
|
||||
---
|
||||
tags: [microservice, tracing, opentelemetry, context-propagation]
|
||||
create time: 2026-05-05
|
||||
---
|
||||
|
||||
# 链路追踪
|
||||
|
||||
## 概述
|
||||
|
||||
Tracing 回答的问题是:**请求在哪一步慢了 / 失败了?**——通过完整的调用链定位瓶颈和故障。
|
||||
|
||||
一次请求在多个服务中的完整调用路径:
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
RID["Request<br/>trace_id: abc-123"]
|
||||
|
||||
subgraph SPANS["调用链 (Trace)"]
|
||||
direction TB
|
||||
S1["Span #1<br/>API Gateway<br/>5ms"]
|
||||
S2["Span #2<br/>Order Service<br/>70ms"]
|
||||
S3["Span #3<br/>Payment RPC<br/>160ms"]
|
||||
S4["Span #4<br/>Inventory RPC<br/>70ms"]
|
||||
|
||||
S1 --> S2 --> S3
|
||||
S2 --> S4
|
||||
end
|
||||
|
||||
RID --> S1
|
||||
style S3 fill:#ff9999
|
||||
|
||||
note["Span #3 耗时最长 → Payment 是瓶颈"]
|
||||
S3 -.-> note
|
||||
```
|
||||
|
||||
## Trace/Span 核心概念
|
||||
|
||||
| 概念 | 说明 |
|
||||
|------|------|
|
||||
| **Trace** | 一次请求的完整调用链,全局唯一 `trace_id` |
|
||||
| **Span** | 调用链中的一个执行单元,有独立的 `span_id` |
|
||||
| **Parent-Child** | Span 树状结构,子 Span 继承父 Span 的 trace_id |
|
||||
| **Tags / Attributes** | 键值对标注(HTTP method、status code) |
|
||||
| **Logs** | Span 级别的时间戳事件(如 "DB query started") |
|
||||
| **Sampling** | 按比例采样,降低存储开销 |
|
||||
|
||||
### OpenTelemetry W3C Trace Context 标准
|
||||
|
||||
```json
|
||||
// HTTP Header
|
||||
{
|
||||
"traceparent": "00-{trace_id}-{span_id}-01",
|
||||
"tracestate": "vendor=value"
|
||||
}
|
||||
```
|
||||
|
||||
格式解析:`version(2字节) - trace_id(32字节) - span_id(16字节) - flags(2字节)`
|
||||
|
||||
```
|
||||
示例: 00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01
|
||||
│ └─── trace_id ───┘ └─ span_id ─┘ └flags─┘
|
||||
```
|
||||
|
||||
## 上下文传播详解
|
||||
|
||||
`trace_id` 必须从上游传递到下游。不同通信场景有不同的传播方式:
|
||||
|
||||
### HTTP 传播
|
||||
|
||||
```go
|
||||
func Middleware(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
// 1. 提取入站 trace context
|
||||
ctx := propagator.Extract(r.Context(), headerReader{r.Header})
|
||||
|
||||
// 2. 创建新的 Span
|
||||
ctx, span := tracer.Start(ctx, "handleRequest")
|
||||
defer span.End()
|
||||
|
||||
// 3. 将 trace context 注入出站请求
|
||||
r = r.WithContext(ctx)
|
||||
propagator.Inject(ctx, headerWriter{r.Header})
|
||||
|
||||
next.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
```
|
||||
|
||||
### MQ 消息头传播
|
||||
|
||||
```go
|
||||
// 生产者 - 手动注入 trace context
|
||||
msg.Properties.Set("trace_id", extractTraceID(ctx))
|
||||
msg.Properties.Set("span_id", extractSpanID(ctx))
|
||||
|
||||
// 消费者 - 恢复 trace context
|
||||
traceID := msg.Properties.Get("trace_id")
|
||||
span, _ := tracer.Start(traceContext, "consumeMessage",
|
||||
trace.WithAttributes(attribute.String("mq.message.id", traceID)))
|
||||
```
|
||||
|
||||
## 采样策略
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
AllReq["全部请求"] --> Sampler{"采样决策"}
|
||||
|
||||
Sampler -->|"100%"| Core["核心链路全量采集"]
|
||||
Sampler -->|"5~10%"| Normal["普通路径随机采样"]
|
||||
Sampler -->|"100%"| Error["错误链路优先保留"]
|
||||
Sampler -->|"0%"| Health["健康检查/内部心跳"]
|
||||
|
||||
Core --> Storage["Trace 存储"]
|
||||
Normal --> Storage
|
||||
Error --> Storage
|
||||
Health --> Drop["丢弃"]
|
||||
```
|
||||
|
||||
| 环境 | 采样率 | 说明 |
|
||||
|------|--------|------|
|
||||
| 开发 / 测试 | 100% | 方便调试,无存储压力 |
|
||||
| 生产 - 核心链路 | 100% | 下单、支付等关键路径 |
|
||||
| 生产 - 普通路径 | 5~10% | 平衡成本和覆盖率 |
|
||||
| 生产 - 错误链路 | 100% | 出错时优先保留 |
|
||||
|
||||
> [!tip] 基于错误的智能采样
|
||||
>
|
||||
> 高级做法:**正常路径低采样,一旦检测到 HTTP 5xx 或 DB 超时,立即提升当前请求的采样率**。这样既省了存储,又能在出问题时有足够的数据回溯。
|
||||
|
||||
## 主流方案对比
|
||||
|
||||
| 方案 | 存储后端 | 侵入程度 | 中文支持 | 推荐理由 |
|
||||
|------|---------|---------|---------|---------|
|
||||
| **OpenTelemetry** | 任意 Jaeger/Prometheus/Loki | SDK + Auto-instrumentation | 良好 | CNCF 行业标准,未来趋势 |
|
||||
| **Jaeger** | Cassandra / Elasticsearch | Agent / SDK | 社区支持 | Uber 开源,UI 优秀 |
|
||||
| **SkyWalking** | MySQL / ES | 零侵入 Agent | ⭐ 完善 | 国产首选,开箱即用 |
|
||||
|
||||
## 渐进式落地路线
|
||||
|
||||
> [!tip] 不要试图一步到位——先从 Tracing 开始,ROI 最高。
|
||||
>
|
||||
> 1. **第一步**:接入 Tracing(OpenTelemetry),覆盖核心链路(下单、支付),rate=100%
|
||||
> 2. **第二步**:加 Metrics(Prometheus + Grafana),建立基础监控面板
|
||||
> 3. **第三步**:集中 Logging(Loki / ELK),日志携带 trace_id 与 Tracing 关联
|
||||
> 4. **第四步**:全量上 OpenTelemetry Collector,统一管理三件套
|
||||
|
||||
## 性能影响评估
|
||||
|
||||
| 指标 | 预期影响 |
|
||||
|------|---------|
|
||||
| CPU 增加 | < 3%(异步批量上报) |
|
||||
| 内存增加 | ~10MB(Span buffer) |
|
||||
| 网络带宽 | 每条 Trace 约 2~5KB(取决于 Span 数量) |
|
||||
| 延迟增加 | < 0.1ms(SDK 内处理不阻塞业务) |
|
||||
|
||||
> [!note] 关键实践
|
||||
> - 使用 **BatchProcessor** 异步上报,不阻塞业务线程
|
||||
> - Span 不要嵌套过深,一个 HTTP 调用或 DB 查询对应一个 Span
|
||||
> - 给 Span 设置丰富的 Attributes,方便查询和过滤
|
||||
> - 错误 Span 标记 `isError=true`,便于快速定位问题链路
|
||||
|
||||
## 关联笔记
|
||||
|
||||
- [[04-可观测性/Metrics监控/README]] — Tracing 与 Metrics 互补
|
||||
- [[04-可观测性/日志系统/README]] — trace_id 串联日志和追踪
|
||||
- [[04-可观测性/告警管理/README]] — 基于 Trace 数据的异常检测告警
|
||||
Reference in New Issue
Block a user