跳转至

601_Jaeger链路追踪

一句话概述:Jaeger 是 Uber 开源的分布式链路追踪系统(CNCF 毕业项目),用于监控微服务架构中请求的完整调用链路——一个请求经过了哪些服务、每个服务耗时多少、在哪个环节出了问题,是微服务性能排查的"X 光机"。

核心知识点表

概念白话解释
Trace链路,一个请求的完整调用过程(从入口到返回)
Span跨度,链路中的一个操作(如一次 HTTP 调用、一次数据库查询)
OpenTelemetryOTel,链路追踪的统一标准(Jaeger v2 原生支持)
OTLPOpenTelemetry Protocol,数据传输协议
Collector收集器,接收、处理和存储链路数据
Sampling采样,不是每个请求都记录,按比例采样以降低开销
Context Propagation上下文传播,在服务间传递 TraceID

安装配置

All-in-One 部署(开发测试)

# Docker 一键启动(内存存储)
docker run -d --name jaeger \
  -p 4317:4317 \                        # OTLP gRPC(推荐)
  -p 4318:4318 \                        # OTLP HTTP
  -p 16686:16686 \                      # Web UI
  -p 9411:9411 \                        # Zipkin 兼容端口
  jaegertracing/jaeger:latest           # Jaeger v2 最新版
# 访问 http://localhost:16686 查看 Web UI

# Jaeger v2 基于 OpenTelemetry Collector 构建
# 默认接收 OTLP 格式数据(gRPC:4317, HTTP:4318)

生产部署(Elasticsearch 后端)

# docker-compose.yml — Jaeger + Elasticsearch
services:
  elasticsearch:
    image: docker.elastic.co/elasticsearch/elasticsearch:8.17.0
    container_name: elasticsearch
    environment:
      - discovery.type=single-node       # 单节点模式
      - xpack.security.enabled=false     # 禁用安全(测试用)
      - "ES_JAVA_OPTS=-Xms1g -Xmx1g"   # JVM 内存
    ports:
      - "9200:9200"                      # ES API
    volumes:
      - es-data:/usr/share/elasticsearch/data

  jaeger:
    image: jaegertracing/jaeger:latest   # Jaeger v2
    container_name: jaeger
    ports:
      - "4317:4317"                      # OTLP gRPC
      - "4318:4318"                      # OTLP HTTP
      - "16686:16686"                    # Web UI
    environment:
      - JAEGER_DISABLED=false
    volumes:
      - ./jaeger-config.yaml:/etc/jaeger/config.yaml
    command: ["--config", "/etc/jaeger/config.yaml"]
    depends_on:
      - elasticsearch

volumes:
  es-data:
# jaeger-config.yaml — Jaeger v2 配置
# Jaeger v2 使用 OpenTelemetry Collector 配置格式
receivers:
  otlp:                                  # 接收 OTLP 数据
    protocols:
      grpc:
        endpoint: "0.0.0.0:4317"         # gRPC 端口
      http:
        endpoint: "0.0.0.0:4318"         # HTTP 端口

exporters:
  elasticsearch:                         # 导出到 Elasticsearch
    endpoints:
      - "http://elasticsearch:9200"      # ES 地址
    indices:
      spans:
        name: "jaeger-spans"             # Span 索引名
      services:
        name: "jaeger-services"          # 服务索引名

extensions:
  jaeger_query:                          # Jaeger 查询 UI
    storage:
      traces:
        elasticsearch:
          endpoints:
            - "http://elasticsearch:9200"

service:
  extensions: [jaeger_query]
  pipelines:
    traces:
      receivers: [otlp]
      exporters: [elasticsearch]

Kubernetes 部署

# 使用 Helm 安装 Jaeger Operator
helm repo add jaegertracing https://jaegertracing.github.io/helm-charts
helm install jaeger-operator jaegertracing/jaeger-operator \
  --namespace observability \
  --create-namespace

# 创建 Jaeger 实例
kubectl apply -f - <<EOF
apiVersion: jaegertracing.io/v1
kind: Jaeger
metadata:
  name: production
  namespace: observability
spec:
  strategy: production                   # 生产策略(组件分离)
  storage:
    type: elasticsearch                  # 使用 ES 存储
    options:
      es:
        server-urls: http://elasticsearch:9200
  collector:
    replicas: 2                          # 2 个 Collector 副本
  query:
    replicas: 2                          # 2 个 Query 副本
EOF

基本使用

应用接入(Python 示例)

# pip install opentelemetry-api opentelemetry-sdk opentelemetry-exporter-otlp
# pip install opentelemetry-instrumentation-flask opentelemetry-instrumentation-requests

from flask import Flask                   # Web 框架
from opentelemetry import trace           # 追踪 API
from opentelemetry.sdk.trace import TracerProvider              # 追踪提供者
from opentelemetry.sdk.trace.export import BatchSpanProcessor   # 批量导出
from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter  # OTLP 导出器
from opentelemetry.instrumentation.flask import FlaskInstrumentor    # Flask 自动埋点
from opentelemetry.instrumentation.requests import RequestsInstrumentor  # requests 自动埋点
from opentelemetry.sdk.resources import Resource                # 资源信息

# 配置 TracerProvider
resource = Resource.create({
    "service.name": "my-web-app",        # 服务名(在 Jaeger UI 中显示)
    "service.version": "1.0.0",          # 服务版本
    "deployment.environment": "production"  # 部署环境
})

provider = TracerProvider(resource=resource)
processor = BatchSpanProcessor(
    OTLPSpanExporter(endpoint="http://localhost:4317")  # Jaeger OTLP 地址
)
provider.add_span_processor(processor)
trace.set_tracer_provider(provider)

# 创建 Flask 应用
app = Flask(__name__)
FlaskInstrumentor().instrument_app(app)  # 自动追踪所有 HTTP 请求
RequestsInstrumentor().instrument()       # 自动追踪所有 HTTP 调用

# 手动创建自定义 Span
tracer = trace.get_tracer("my-web-app")  # 获取 Tracer

@app.route("/api/users")
def get_users():
    with tracer.start_as_current_span("fetch-users") as span:  # 创建 Span
        span.set_attribute("user.count", 42)   # 设置属性
        span.add_event("querying database")    # 添加事件
        # 业务逻辑...
        return {"users": [...]}

if __name__ == "__main__":
    app.run(port=8080)

应用接入(Node.js 示例)

// npm install @opentelemetry/api @opentelemetry/sdk-node
// npm install @opentelemetry/auto-instrumentations-node
// npm install @opentelemetry/exporter-trace-otlp-grpc

// tracing.js — 在应用入口前加载
const { NodeSDK } = require('@opentelemetry/sdk-node');
const { OTLPTraceExporter } = require('@opentelemetry/exporter-trace-otlp-grpc');
const { getNodeAutoInstrumentations } = require('@opentelemetry/auto-instrumentations-node');

const sdk = new NodeSDK({
  serviceName: 'my-node-app',            // 服务名
  traceExporter: new OTLPTraceExporter({
    url: 'http://localhost:4317',        // Jaeger OTLP gRPC 地址
  }),
  instrumentations: [
    getNodeAutoInstrumentations(),       // 自动埋点(HTTP、Express、MySQL 等)
  ],
});

sdk.start();                             // 启动 SDK

// 启动应用:node -r ./tracing.js app.js

Web UI 使用

# 访问 http://localhost:16686

# === 搜索链路 ===
# 1. 选择 Service(服务名)
# 2. 选择 Operation(操作名,如 GET /api/users)
# 3. 设置时间范围
# 4. 可选:设置标签过滤(如 http.status_code=500)
# 5. 点击 Find Traces

# === 查看链路详情 ===
# 点击具体 Trace → 看到完整调用链路
# 瀑布图显示:
# - 每个 Span 的名称和服务
# - 每个 Span 的耗时(柱状图)
# - Span 之间的父子关系
# - 每个 Span 的标签和日志

# === 对比链路 ===
# 选择两条 Trace → Compare → 对比正常和异常请求的差异

高级用法

采样策略

# 不是所有请求都需要追踪,采样可以降低开销

# 方法1:头部采样(在 SDK 中配置)
# 概率采样:10% 的请求被追踪
from opentelemetry.sdk.trace.sampling import TraceIdRatioBased
provider = TracerProvider(
    sampler=TraceIdRatioBased(0.1),      # 10% 采样率
    resource=resource
)

# 方法2:尾部采样(在 Collector 中配置)
# 只保留有错误或慢请求的链路
processors:
  tail_sampling:
    decision_wait: 10s                   # 等待 10 秒再决策
    policies:
      - name: errors                     # 保留所有错误链路
        type: status_code
        status_code: {status_codes: [ERROR]}
      - name: slow-requests              # 保留慢请求
        type: latency
        latency: {threshold_ms: 1000}    # 超过 1 秒的请求
      - name: percentage                 # 其余按 10% 采样
        type: probabilistic
        probabilistic: {sampling_percentage: 10}

与 Prometheus + Grafana 集成

# Jaeger 提供 Prometheus 指标:
# - jaeger_collector_spans_received_total → 收到的 Span 总数
# - jaeger_collector_traces_saved_total → 保存的 Trace 总数
# - jaeger_query_requests_total → 查询请求总数

# 在 Grafana 中同时查看:
# - Metrics(Prometheus)→ 系统指标和告警
# - Traces(Jaeger)→ 链路追踪
# - Logs(Loki)→ 日志
# 三者可以通过 TraceID 关联跳转

SPM(服务性能监控)

# Jaeger v2 内置 SPM 功能
# 自动计算每个服务的:
# - 请求速率(Requests/sec)
# - 错误率(Error Rate)
# - 延迟分布(P50/P95/P99)
# 类似于 Datadog APM 的 RED 指标
# 在 Jaeger UI → Monitor 标签页查看

常见报错

报错信息原因解决方案
connection refused :4317Jaeger 未启动或端口不通检查 Jaeger 状态和端口映射
traces not appearing数据未发送到 Jaeger检查 OTLP exporter 配置和网络
storage capacity exceeded存储空间不足清理旧数据或扩容存储
too many spansSpan 数据量过大配置采样策略降低数据量
context propagation failed上下文未正确传播检查 SDK 的自动埋点配置

速查表

# === 关键端口(Jaeger v2) ===
# 4317  → OTLP gRPC(推荐)
# 4318  → OTLP HTTP
# 16686 → Web UI
# 9411  → Zipkin 兼容

# === Docker 快速启动 ===
docker run -d -p 4317:4317 -p 16686:16686 jaegertracing/jaeger:latest

# === 常用 SDK 包 ===
# Python:  opentelemetry-sdk, opentelemetry-exporter-otlp
# Node.js: @opentelemetry/sdk-node, @opentelemetry/exporter-trace-otlp-grpc
# Java:    opentelemetry-sdk, opentelemetry-exporter-otlp
# Go:      go.opentelemetry.io/otel, go.opentelemetry.io/otel/exporters/otlp

# === 环境变量配置 ===
OTEL_SERVICE_NAME=my-service             # 服务名
OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4317  # OTLP 地址
OTEL_TRACES_SAMPLER=traceidratio         # 采样器
OTEL_TRACES_SAMPLER_ARG=0.1             # 采样率(10%)

# === 可观测性三支柱 ===
# Metrics → Prometheus(指标监控)
# Logs    → Loki(日志聚合)
# Traces  → Jaeger(链路追踪)
# 三者通过 TraceID 关联

同类对比

特性JaegerZipkinTempoSigNoz
CNCF毕业项目非(Grafana)
协议OTLP 原生Zipkin/OTLPOTLPOTLP
存储ES/Cassandra/内存ES/MySQL/内存对象存储ClickHouse
Web UI内置内置Grafana内置
存储成本
与 Grafana插件插件原生独立
学习曲线中等

选型建议:企业级链路追踪首选 Jaeger(CNCF 毕业、功能最全、v2 原生 OTLP);已用 Grafana 生态选 Tempo(存储成本最低、Grafana 原生集成);想要 All-in-One 可观测平台选 SigNoz(Metrics+Logs+Traces 一体)。