2. Jaeger 基础回顾:Jaeger 架构与核心概念

在深入事故响应与变更窗口故障定位之前,必须牢固掌握 Jaeger 的架构组件与核心数据模型。本章将系统回顾 Jaeger 的四大核心组件(Agent、Collector、Query、UI)以及分布式追踪的两大基石:Span 与 Trace。这些知识是后续章节中分析调用链、定位性能瓶颈和根因分析的基础。

2.1 Jaeger 整体架构

Jaeger 采用模块化、可水平扩展的架构设计,主要分为客户端库(Instrumentation)、数据采集层(Agent & Collector)、存储后端(Storage Backend)以及查询与可视化层(Query & UI)。下图展示了 Jaeger 的标准部署架构与数据流。

Jaeger 标准部署架构与数据流 应用服务 A (携带 Jaeger Client) 应用服务 B (携带 Jaeger Client) Jaeger Agent (DaemonSet / Sidecar) Jaeger Collector (无状态集群) 存储后端 (Cassandra/ES/Badger) Jaeger Query (查询服务) Jaeger UI (Web 控制台) 用户访问 架构说明 1. 应用服务通过 UDP 将 Span 发送到本地 Agent(推荐 Sidecar 模式)。 2. Agent 将 Span 批量压缩后通过 gRPC 发送给 Collector 集群。 3. Collector 验证、索引并写入存储后端(生产环境推荐 Elasticsearch 或 Cassandra)。 4. Query 服务从存储中检索 Trace 数据,并通过 API 提供给 UI 展示。 5. 所有组件均可水平扩展,Collector 和 Query 为无状态服务。

2.2 核心组件详解

Jaeger 的每个组件在数据采集、处理、存储和查询链路中承担特定职责。下表总结了各组件的功能定位与关键配置。

组件 功能定位 部署模式 关键端口/协议
Jaeger Agent 本地代理,接收应用发出的 Span,批量压缩后转发给 Collector DaemonSet(K8s)或 Sidecar UDP 6831/6832(Thrift Compact/Binary)
Jaeger Collector 接收 Agent 或应用直连的 Span,验证、索引并写入存储 无状态集群,水平扩展 gRPC 14250、HTTP 14268
Jaeger Query 提供 Trace 检索 API,服务于 UI 和外部系统 无状态集群,水平扩展 HTTP 16686(API + UI)
Jaeger UI Web 控制台,提供 Trace 搜索、详情查看、依赖分析 内嵌于 Query 或独立部署 HTTP 16686
Storage Backend 持久化存储 Span 数据 Cassandra / Elasticsearch / Badger(测试) 依后端而定
生产环境建议: 在 Kubernetes 环境中,Agent 通常以 DaemonSet 方式部署在每个节点上,或作为 Sidecar 注入到业务 Pod 中。Collector 和 Query 应配置为无状态 Deployment,并利用 HPA 进行自动扩缩容。

2.3 Span:分布式追踪的基本单元

Span 是 Jaeger 中最基本的数据单元,代表分布式系统中一个逻辑工作单元(如一次 RPC 调用、一个数据库查询、一个消息队列发送)。每个 Span 记录以下关键信息:

  • 操作名称(Operation Name):描述该 Span 代表的操作,例如 HTTP POST /api/order。
  • 开始时间与持续时间:精确到微秒的时间戳和耗时。
  • Span 上下文(Span Context):包含 Trace ID、Span ID、Baggage 等,用于跨进程传递追踪信息。
  • 标签(Tags):键值对形式的元数据,用于描述 Span 的属性(如 HTTP 状态码、错误信息、数据库语句)。
  • 日志(Logs):时间戳 + 键值对,用于记录 Span 生命周期内的关键事件(如异常堆栈、缓存命中/未命中)。
  • 引用关系(References):Span 之间的父子关系或跟随关系。
// 示例:一个典型的 Span 结构(JSON 表示)
{
  "traceID": "abc123def456",
  "spanID": "span001",
  "operationName": "HTTP GET /api/users",
  "startTime": 1710000000123456,
  "duration": 150000,  // 微秒,即 150ms
  "tags": [
    {"key": "http.method", "vStr": "GET"},
    {"key": "http.status_code", "vType": "int64", "vInt64": 200},
    {"key": "error", "vBool": false}
  ],
  "logs": [
    {
      "timestamp": 1710000000123500,
      "fields": [
        {"key": "event", "vStr": "cache_miss"},
        {"key": "cache.key", "vStr": "user:123"}
      ]
    }
  ],
  "references": [
    {"refType": "CHILD_OF", "traceID": "abc123def456", "spanID": "parentSpan001"}
  ]
}

2.4 Trace:端到端请求的完整视图

Trace 是由一组具有相同 Trace ID 的 Span 构成的树状结构,完整记录了一个请求从入口到出口经过的所有服务与操作。Trace 的核心特征包括:

  • 全局唯一 Trace ID:贯穿整个请求生命周期,用于关联所有 Span。
  • Span 层级关系:通过 CHILD_OF 和 FOLLOWS_FROM 引用关系构建调用树。
  • 时间轴视图:在 UI 中以瀑布图(Waterfall)形式展示,直观呈现各 Span 的耗时与并行关系。
  • 服务依赖图:基于 Trace 数据自动生成服务间调用拓扑。
Trace 与 Span 层级关系(调用树 + 时间轴) 时间轴 → Root Span: /api/checkout (Trace ID: abc123) 200ms Child Span: auth.verifyToken 80ms Child Span: order.createOrder 120ms Grandchild Span: inventory.checkStock 60ms Grandchild Span: payment.charge 40ms 说明:每个矩形代表一个 Span,宽度表示持续时间。Root Span 是整个 Trace 的入口,Child/Grandchild Span 表示嵌套调用。

2.5 Span 与 Trace 的关键属性对比

属性 Span Trace
定义 单个操作单元 一组具有相同 Trace ID 的 Span 集合
标识 Span ID(唯一) Trace ID(全局唯一)
结构 包含 Tags、Logs、References 树状结构,由 Span 的引用关系构成
粒度 细粒度(一次函数调用、一次 DB 查询) 粗粒度(一次用户请求、一次事务)
UI 展示 瀑布图中的单个条 完整的瀑布图 + 服务依赖图
故障定位价值 定位具体哪个操作耗时高或出错 定位故障发生在哪个服务、哪个环节
事故响应关键点: 在变更窗口故障定位中,我们通常先通过 Trace ID 找到异常请求的完整调用链,然后逐层检查 Span 的 Tags(如 error=true、http.status_code=500)和 Logs(如异常堆栈),快速缩小故障范围。Span 的持续时间是判断性能瓶颈的直接指标。

2.6 采样策略简介

在生产环境中,为控制存储成本,Jaeger 默认不会采集所有 Trace。理解采样策略对于事故响应至关重要——如果故障 Trace 未被采样,将无法进行事后分析。常见的采样策略包括:

  • 头部采样(Head-based Sampling):在 Trace 开始时决定是否采样,策略简单但无法针对特定错误路径。
  • 尾部采样(Tail-based Sampling):在 Trace 结束后根据结果(如是否包含错误)决定是否保留,更适合故障定位场景。
  • 概率采样(Probabilistic Sampling):按固定百分比采样,适用于流量均匀的场景。
  • 速率限制采样(Rate Limiting Sampling):每秒最多采集 N 个 Span,防止突发流量导致存储过载。
注意: 在变更窗口等高敏感时段,建议临时提高采样率或启用尾部采样,确保关键故障 Trace 不会被遗漏。同时,确保 Agent 和 Collector 的资源配置能够应对采样率提升带来的压力。