跳到主要内容

Jaeger 数据模型

介绍

Jaeger是一个开源的分布式追踪系统,用于监控和排查微服务架构中的性能问题。理解Jaeger的数据模型是使用该工具的基础。本文将详细介绍Jaeger的核心数据模型,包括SpanTrace等关键概念,并通过实际案例展示它们如何工作。

核心概念

1. Span

Span是Jaeger数据模型中的基本单元,代表一个独立的工作单元。例如,一个HTTP请求或数据库查询都可以是一个Span。每个Span包含以下关键信息:

  • 操作名称(Operation Name):描述Span执行的操作,例如GET /api/users
  • 开始时间和持续时间:记录Span的开始时间和执行时长。
  • 标签(Tags):键值对形式的元数据,用于描述Span的属性,例如http.status_code=200
  • 日志(Logs):记录Span执行过程中的事件或错误信息。

示例代码

以下是一个用Go语言创建Span的示例:

go
import (
"context"
"github.com/opentracing/opentracing-go"
"github.com/uber/jaeger-client-go"
)

func main() {
tracer := opentracing.GlobalTracer()
span := tracer.StartSpan("example_operation")
defer span.Finish()

span.SetTag("http.method", "GET")
span.LogKV("event", "started")
}

2. Trace

Trace是由多个Span组成的有向无环图(DAG),表示一个完整的请求链路。Trace通过Trace ID唯一标识,而Span之间通过Parent-Span关系关联。

父子关系

  • Root SpanTrace中的第一个Span,没有父Span
  • Child Span:由其他Span创建的Span,继承父SpanTrace ID

3. Context Propagation

Span的上下文(SpanContext)包含Trace IDSpan ID,用于在服务之间传递追踪信息。Jaeger支持以下传播方式:

  • HTTP Headers:通过uber-trace-id等头部字段传递。
  • gRPC Metadata:通过gRPC的元数据传递。

实际案例

假设有一个用户服务调用订单服务的场景:

  1. 用户服务接收HTTP请求,创建Root Span
  2. 用户服务调用订单服务的API,生成Child Span并注入HTTP头部。
  3. 订单服务从HTTP头部提取SpanContext,继续记录Span

代码片段

用户服务调用订单服务时注入SpanContext

go
func callOrderService(ctx context.Context) {
span, ctx := opentracing.StartSpanFromContext(ctx, "call_order_service")
defer span.Finish()

req, _ := http.NewRequest("GET", "http://orders/api/orders", nil)
opentracing.GlobalTracer().Inject(
span.Context(),
opentracing.HTTPHeaders,
opentracing.HTTPHeadersCarrier(req.Header),
)
http.DefaultClient.Do(req)
}

总结

Jaeger的数据模型围绕SpanTrace构建,通过上下文传播实现分布式追踪。关键点包括:

  • Span是基本单元,包含操作、标签和日志。
  • TraceSpan的集合,表示完整请求链路。
  • 上下文传播确保跨服务的追踪连续性。

附加资源

  1. Jaeger官方文档
  2. 练习:尝试在本地部署Jaeger并记录一个简单的微服务调用链路。
  3. 扩展阅读:OpenTracing标准规范。
提示

使用Jaeger时,确保为Span设置有意义的操作名称和标签,便于后续分析和排查问题。