Jaeger —— 基于 OpenTelemetry Collector 的分布式链路追踪平台

运维监控软件手册 05-APM与链路追踪 26.4 KB 原文

Jaeger —— 基于 OpenTelemetry Collector 的分布式链路追踪平台

分类:05 APM与链路追踪 适用:微服务 / 云原生架构的端到端链路追踪、慢调用与根因定位;从本机调试到大规模生产集群 一句话:CNCF 毕业项目,v2 起以 OpenTelemetry Collector 为内核,OTLP 收 span、可插拔存储、UI 查 Trace 官方:https://www.jaegertracing.io/ | https://github.com/jaegertracing/jaeger 授权:Apache License 2.0(开源免费、可商用)

版本说明(重要):Jaeger v2 于 2024-11-12 发布,是基于 OpenTelemetry Collector 框架重构的新架构;Jaeger v1 已于 2025-12-31 EOL,不再更新(v1 的 jaeger-collector / jaeger-query / jaeger-agent / jaeger-ingester 镜像均已标记 Deprecated,最后版本 1.76)。v2 用单二进制 jaeger 通过不同角色运行。本文一律写「以官方最新稳定版为准」,不锁定 tag 与版本号。

1. 它解决什么问题

痛点 做法
一次请求跨十几个服务,慢在哪一步说不清 Trace/Span 瀑布图 + 时间线,按耗时、错误、标签检索
各语言自研埋点、格式互不兼容 统一 OpenTelemetry SDK / OTLP,vendor-neutral,兼容 Zipkin、Jaeger Thrift 旧格式
全量采集压力与成本太高 头部采样(概率/限速/远程)、尾部采样(按错误/延迟/标签)、自适应采样
采集与查询要分开扩缩容 / 存储选型受限 / 链路与指标割裂 v2 单二进制多角色 collector/query/ingester/all-in-one;Memory/Badger/Cassandra/ES/OpenSearch/Kafka 缓冲/Remote gRPC/ClickHouse(实验);SPM 把 Trace 转 RED 指标配 Prometheus/Grafana

不适合:需要开箱即用的 Metrics/Log/告警一体化平台(用 SkyWalking 或 Prometheus 全家桶);只做主机/容器指标(用 Prometheus 系);需要商业支持与托管服务。Jaeger 自身不存储指标、不做告警,见第 6 章。

2. 核心概念与架构

术语 含义
Trace / Span / SpanContext 一次请求 = 一条 Trace(TraceID),由多个 Span 组成(operationName、起止时间、tags/logs、父子引用);Context 随跨进程调用透传 TraceID/SpanID/采样标记/baggage,标准为 W3C traceparent,兼容 B3、Jaeger uber-trace-id
OTLP / Collector pipeline v2 主推上报协议:gRPC :4317、HTTP :4318(/v1/traces,Protobuf/JSON),只收 tracing;配置风格 receivers → processors → exporters,由 service.pipelines.traces 串起,另有 connectors/extensions
Jaeger 组件 / 角色 扩展 jaeger_storage(注册后端)、jaeger_query(UI/查询 API)、remote_sampling;exporter jaeger_storage_exporter;processor adaptive_sampling。角色:all-in-one/collector/query/ingester/agent(agent 官方建议直接用标准 OTel Collector)
采样 / Storage 头部 probabilistic(概率)、ratelimiting(限速)、远程静态策略/自适应;尾部 tail_sampling(Trace 收齐后按错误/延迟判定)。主存储短 TTL + archive 长保留;Remote Storage API v2 接自定义 gRPC 后端
 应用(OTel SDK)      OTLP        ┌── Jaeger v2(OTel Collector 内核)──┐       存储
┌─────────────┐  4317 gRPC /   │ receivers: otlp / jaeger / zipkin │    ┌──────────────┐
│ Java/Go/    │───4318 HTTP───►│ processors: batch/tail_sampling   │    │ memory/badger│
│ Python/Node │  /v1/traces    │ exporters: jaeger_storage_exporter│───►│ Cassandra    │
└──────┬──────┘                │ extensions: jaeger_storage/query  │    │ ES/OpenSearch│
       │ 采样拉取 5778/sampling │             remote_sampling       │    │ Kafka(缓冲)  │
       ▼                       └───────────────┬──────────────────┘    └──────┬───────┘
┌─────────────┐                               ▼ 读(:16685 gRPC/:16686 HTTP)  │
│ 静态/自适应 │            ┌──────────────────────┐      ┌──────────────────────┐
│ 采样策略    │◄───────────│ Jaeger UI :16686     │      │ SPM → Prometheus →  │
└─────────────┘            │ /api/*、/api/v3/*    │      │ Grafana/Alertmanager│
                           └──────────────────────┘      └──────────────────────┘

Context 传播要点:SDK 在入口从 traceparent 提取父 SpanContext,出口注入 header;任一跳未透传(网关、MQ、线程池切换)就会断链。OTLP 是 v2 的原生入口,旧 Jaeger Thrift / Zipkin 接收器仅为向后兼容(标记 Deprecated)。jaeger_storage 之所以是扩展而非 exporter,是因为 query 端也要读同一份后端配置。

Collector pipeline 与采样

环节 可选组件 说明
receivers otlp(4317/4318)、jaeger(14250/14268/6831/6832)、zipkin(9411)、kafka 多协议并存,生产建议统一收敛到 otlp
processors batch、probabilistic_sampler、tail_sampling、adaptive_sampling、attributes/resource batch 必配;尾部采样需同组 Collector 保证同一 Trace 落同一实例
exporters / extensions jaeger_storage_exporter/kafka/otlp;jaeger_storage/jaeger_query/remote_sampling/health_check 写存储 / Kafka 削峰 / 转发;扩展经 service.extensions 启用
采样策略 客户端 OTEL_TRACES_SAMPLER、服务端静态 sampling-strategies.json、自适应、尾部 客户端与服务端采样率不一致会产生「半条链路」,见第 11 章

后端存储(官方 Storage 文档)

后端 适用 注意
Memory / Badger 开发测试 / 单机中小规模 Memory 重启即丢(max_traces 限条数)⚠️ 禁生产;Badger 本地嵌入式不能水平扩展
Cassandra / Elasticsearch / OpenSearch 分布式生产 官方对大规模生产推荐 OpenSearch;ES/OpenSearch 索引模板与版本需配套
Kafka 中间缓冲(非最终存储) collector 用 kafka exporter、ingester 用 kafka receiver,防存储抖动丢数据
ClickHouse / Remote Storage gRPC API v2 实验 / 自定义后端 ClickHouse 需 feature gate;自定义后端实现 TraceReader/DependencyReader/TraceService

3. 安装与部署

3.1 环境准备

项 要求
运行时 / 依赖 v2 为 Go 单二进制,无需 JVM;all-in-one + memory 零外部依赖;生产需外部存储(ES/OpenSearch/Cassandra/Badger 卷)
写端口 :4317 OTLP gRPC、:4318 OTLP HTTP /v1/traces、:9411 Zipkin、:14250 legacy gRPC、:14268 legacy Thrift、:6831/6832 UDP Thrift
读 / 运维端口 :16686 UI + /api/* + /api/v3/*、:16685 gRPC QueryService、:5778/5779 远程采样、:13133 health_check、:8888 自监控(后两者以实际启用扩展/配置为准)
内核 / 权限 / 时钟 Linux 常规权限、无需 privileged;UDP 6831/6832 需 host 网络或显式映射;容器挂只读配置与 Badger 数据卷;全节点 NTP,max_clock_skew_adjust 默认 30s

3.2 多种安装方式

# 版本、镜像 tag 一律以官方最新稳定版为准
export JAEGER_VER=<以官方最新稳定版为准>
# A. 二进制(GitHub Releases 提供 Linux/macOS/Windows 资产,见第 14 章)
curl -fsSL -o jaeger.tar.gz <官方 Releases 资产 URL>
tar -xzf jaeger.tar.gz && ./jaeger --help
# B. Docker all-in-one(官方 Getting Started,内存存储,仅调试)
docker run -d --name jaeger -p 16686:16686 -p 4317:4317 -p 4318:4318 -p 5778:5778 -p 9411:9411 \
  cr.jaegertracing.io/jaegertracing/jaeger:${JAEGER_VER}
# C. Docker + 自定义配置
docker run -d --name jaeger -p 16686:16686 -p 4317:4317 -p 4318:4318 \
  -v /path/to/config.yaml:/jaeger/config.yaml \
  cr.jaegertracing.io/jaegertracing/jaeger:${JAEGER_VER} --config /jaeger/config.yaml
# D. 二进制 + systemd(生产托管)
cat >/etc/systemd/system/jaeger.service <<'EOF'
[Service]
Type=simple
User=jaeger
ExecStart=/opt/jaeger/jaeger --config /etc/jaeger/config.yaml
Restart=on-failure
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload && systemctl enable --now jaeger
# E. HotROD 演示应用
docker run -d --name hotrod -p 8080:8080 -e OTEL_EXPORTER_OTLP_ENDPOINT=http://<JAEGER_HOST>:4318 \
  cr.jaegertracing.io/jaegertracing/example-hotrod:${JAEGER_VER}

Docker Compose(all-in-one + OpenSearch 简化示例)

services:
  jaeger:
    image: cr.jaegertracing.io/jaegertracing/jaeger:${JAEGER_VER}
    command: ["--config", "/jaeger/config.yaml"]
    volumes: ["./config.yaml:/jaeger/config.yaml:ro"]
    ports: ["16686:16686", "4317:4317", "4318:4318", "5778:5778"]
    depends_on: [opensearch]
  opensearch:
    image: opensearchproject/opensearch:<以官方兼容版本为准>
    environment: { discovery.type: single-node, OPENSEARCH_JAVA_OPTS: "-Xms1g -Xmx1g" }
    ports: ["9200:9200"]

⚠️ K8s 场景:v2 是单二进制,直接用 Deployment + ConfigMap 挂载 config.yaml 即可(collector / query 拆成两个 Deployment)。Jaeger Operator 历史上管理 v1 CRD,v1 已 EOL,Operator 对 v2 的支持情况以官方文档为准;不要照搬旧博客里的 jaeger-operator + v1 Jaeger CR 清单。镜像仓库注意已从 Docker Hub 迁到 cr.jaegertracing.io/jaegertracing/。

3.3 首次启动与验证

curl -sS -o /dev/null -w 'UI HTTP %{http_code}\n' http://localhost:16686/           # 预期 200
curl -sS http://localhost:16686/api/services                                        # 预期 {"data":[],"total":0,...,"errors":null}
curl -sS -X POST http://localhost:4318/v1/traces -H 'Content-Type: application/json' -d @trace.json  # 预期 200
curl -sS http://localhost:13133/  # health_check(若启用)预期 200;docker logs jaeger 看启动日志
# 打开 http://localhost:16686 → Search → 选 Service → Find Traces,看到刚上报的 span

4. 配置文件详解

4.1 配置路径与覆盖机制

项 说明
指定配置 / 内置配置 jaeger --config config.yaml(v2 只认配置文件,不识别 v1 的 SPAN_STORAGE_TYPE 等变量);all-in-one 用二进制内置 all-in-one.yaml,官方 cmd/jaeger/ 下有 config-{storage}.yaml、config-query.yaml 示例
环境变量展开 / 命令行覆盖 YAML 内用 ${env:VAR:-default}(如 endpoint: "${env:JAEGER_LISTEN_HOST:-localhost}:4317"),OTel Go SDK 变量自动识别;--set=receivers.otlp.protocols.grpc.endpoint=0.0.0.0:4317 覆盖内置配置
自定义发行版 用 OpenTelemetry Collector Builder(ocb)增删组件后自行编译

4.2 关键项说明表

配置键 默认值 / 示例 说明
receivers.otlp.protocols.grpc/http.endpoint localhost:4317 / localhost:4318 OTLP gRPC / HTTP /v1/traces;容器需 0.0.0.0
processors.batch.timeout / send_batch_size 5s / 512 批量发送,降低写放大
exporters.jaeger_storage_exporter.trace_storage / queue.num_consumers / queue_size <backend 名> / 10 / 100 指向 jaeger_storage.backends 注册名;发送并发与队列
extensions.jaeger_storage.backends.<name>.<type> memory.max_traces: 100000 类型:memory/badger/cassandra/elasticsearch/opensearch/grpc;字段以官方 config-{storage}.yaml 为准
extensions.jaeger_query.storage.traces / http.endpoint / grpc.endpoint <backend 名> / 0.0.0.0:16686 / 0.0.0.0:16685 query 读同一后端名;UI/REST 与 gRPC QueryService
extensions.jaeger_query.base_path / max_clock_skew_adjust / remote_sampling.file.path / adaptive.sampling_store / / 30s / 静态策略文件 / 后端名 反代前缀、时钟偏差校正(0s 关闭)、远程采样(http/grpc 默认 5778/5779)
service.extensions / service.pipelines.traces / service.telemetry [jaeger_storage, jaeger_query] / [otlp]→[batch]→[jaeger_storage_exporter] / :8888、info 必须显式列出,否则扩展不生效;Collector 自身指标与日志

4.3 完整可运行最小示例:config.yaml(all-in-one + memory)

# config.yaml —— OTLP 接收 + 内存存储 + UI + 远程采样
receivers:
  otlp:
    protocols:
      grpc: { endpoint: 0.0.0.0:4317 }
      http: { endpoint: 0.0.0.0:4318 }
processors:
  batch: { timeout: 5s, send_batch_size: 512 }
exporters:
  jaeger_storage_exporter:
    trace_storage: some_trace_storage
    queue: { num_consumers: 10, queue_size: 100 }
extensions:
  jaeger_storage:
    backends: { some_trace_storage: { memory: { max_traces: 100000 } } }
  jaeger_query:
    storage: { traces: some_trace_storage }
    http: { endpoint: 0.0.0.0:16686 }
    grpc: { endpoint: 0.0.0.0:16685 }
  remote_sampling:
    file: { path: /etc/jaeger/sampling-strategies.json }
    http: {}
    grpc: {}
service:
  extensions: [jaeger_storage, jaeger_query, remote_sampling]
  pipelines:
    traces: { receivers: [otlp], processors: [batch], exporters: [jaeger_storage_exporter] }
  telemetry:
    logs: { level: info }

生产把 memory 换成 opensearch/elasticsearch/cassandra(字段以官方 config-{storage}.yaml 为准),collector 与 query 拆两个 Deployment 共用同一后端配置。示例见 https://github.com/jaegertracing/jaeger/tree/main/cmd/jaeger 。

4.4 采样配置与存储后端示例

# (a) 尾部采样:保留错误/慢调用,其余 10% 概率(processors 片段,合并进主配置)
processors:
  tail_sampling:
    decision_wait: 10s
    num_traces: 100
    policies:
      - { name: errors, type: status_code, status_code: { status_codes: [ERROR] } }
      - { name: slow, type: latency, latency: { threshold_ms: 500 } }
      - { name: baseline, type: probabilistic, probabilistic: { sampling_percentage: 10 } }
  batch: { timeout: 5s }
# service.pipelines.traces.processors: [tail_sampling, batch]
# (b) 自适应采样(extensions 片段)
extensions:
  remote_sampling:
    adaptive: { sampling_store: some_trace_storage, initial_sampling_probability: 0.1 }
# (c) 归档存储(extensions 片段):主存储短 TTL,archive 手动保存长保留
extensions:
  jaeger_storage:
    backends: { primary_store: { memory: { max_traces: 100000 } }, archive_store: { memory: { max_traces: 100000 } } }
  jaeger_query:
    storage: { traces: primary_store, traces_archive: archive_store }
// (d) 静态远程采样策略 sampling-strategies.json
{ "default_strategy": { "type": "probabilistic", "param": 0.1 }, "service_strategies": [ { "service": "checkout", "type": "ratelimiting", "param": 100 } ] }

probabilistic/ratelimiting 字段以官方 Sampling 文档为准;客户端 OTEL_TRACES_SAMPLER 与服务端策略二选一,避免双重采样。

5. 核心使用方法

5.1 启动与查询命令集(编号 120 + 5.2 UI 2123,共 ≥23 条)

# --- 服务管理 ---
# 1) 二进制前台启动                     2) 查看帮助
jaeger --config /etc/jaeger/config.yaml
jaeger --help
# 3) 覆盖内置 all-in-one 的监听地址
jaeger --set=receivers.otlp.protocols.grpc.endpoint=0.0.0.0:4317
# 4) Docker 挂载自定义配置(all-in-one 见 3.2 B)
docker run -d -v $PWD/config.yaml:/jaeger/config.yaml \
  cr.jaegertracing.io/jaegertracing/jaeger:${JAEGER_VER} --config /jaeger/config.yaml
# --- 查询 REST API(:16686,/api/* 为 internal;程序化推荐 :16685 gRPC api_v3)---
# 5) 服务列表                          6) 操作名
curl -sS http://<JAEGER>:16686/api/services
curl -sS 'http://<JAEGER>:16686/api/operations?service=checkout'
# 7) 检索 Trace(微秒级 start/end、limit、minDuration、tags)
curl -sS 'http://<JAEGER>:16686/api/traces?service=checkout&start=1730000000000000&end=1730003600000000&limit=20&minDuration=500ms&tags={"http.status_code":"500"}'
# 8) 取单条 Trace                      9) 服务依赖图(endTs/lookback 毫秒)
curl -sS http://<JAEGER>:16686/api/traces/<trace-id-hex-string>
curl -sS 'http://<JAEGER>:16686/api/dependencies?endTs=1730003600000&lookback=3600000'
# 10) 远程采样策略                     11) 稳定 JSON API(路径以官方 OpenAPI 为准)
curl -sS 'http://<JAEGER>:5778/sampling?service=checkout'
curl -sS 'http://<JAEGER>:16686/api/v3/traces?query.service_name=checkout'
# 12) UI / 健康检查
curl -sS -o /dev/null -w '%{http_code}\n' http://<JAEGER>:16686/ && curl -sS http://<JAEGER>:13133/
# 13) gRPC 反射列出查询服务
grpc_cli ls <JAEGER>:16685
# --- OTLP 直投(调试用)---
# 14) HTTP JSON 上报一条 span(traceId 32 位 hex、spanId 16 位 hex、时间 Unix 纳秒字符串)
curl -sS -X POST http://<JAEGER>:4318/v1/traces -H 'Content-Type: application/json' \
  -d '{"resourceSpans":[{"scopeSpans":[{"spans":[{"traceId":"5B8EFFF798038103D269B633813FC60C","spanId":"EEE19B7EC3C1B174","name":"GET /checkout","kind":2,"startTimeUnixNano":"1730000000000000000","endTimeUnixNano":"1730000000120000000","status":{"code":2}}]}]}]}'
# --- 客户端 OTel SDK 接入(无需 Jaeger 专用 client)---
# 15) 通用环境变量(SDK 自动配置)
export OTEL_SERVICE_NAME=checkout OTEL_EXPORTER_OTLP_ENDPOINT=http://<JAEGER>:4318
export OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf OTEL_PROPAGATORS=tracecontext,baggage
export OTEL_TRACES_SAMPLER=parentbased_traceidratio OTEL_TRACES_SAMPLER_ARG=0.1
# 16) Java:OTel Java Agent(版本以 OpenTelemetry 官方最新稳定版为准)
java -javaagent:/opt/opentelemetry-javaagent.jar -Dotel.service.name=checkout \
     -Dotel.exporter.otlp.endpoint=http://<JAEGER>:4318 -jar checkout.jar
# 17) Python / 18) Node.js 自动插桩
pip install opentelemetry-distro opentelemetry-exporter-otlp && opentelemetry-bootstrap -a install
opentelemetry-instrument python app.py
node --require @opentelemetry/auto-instrumentations-node/register app.js
# 19) Go:标准 OTel SDK 读 15) 环境变量(代码见第 7 章)
# 20) 采样策略校验 / 自监控 / 索引清理 / HotROD 演示
cat /etc/jaeger/sampling-strategies.json | jq .
curl -sS http://<JAEGER>:8888/metrics | grep otelcol_
docker run --rm cr.jaegertracing.io/jaegertracing/jaeger-es-index-cleaner:${JAEGER_VER} <ES_URL>
docker run --rm -p 8080:8080 cr.jaegertracing.io/jaegertracing/example-hotrod:${JAEGER_VER}

5.2 Web UI 路径(21~24)与关键 API

# 目标 路径或端点
21 检索链路 Search → Service/Operation/Tags/Min-Max Duration/Lookback → Find Traces
22 看瀑布图 / 对比 Trace 点 Trace → 时间线、Span tags/logs;Trace Comparison 并排视图
23 依赖图 / SPM Dependencies(DAG)、Monitor 页(需配 SPM + Prometheus)
端点 端口 说明
POST /v1/traces 4318 OTLP HTTP(Protobuf/JSON),主推写入口
GET /api/traces?service=&minDuration=&tags= / /api/traces/{traceID} 16686 internal JSON,UI 自用,不保证兼容
GET /api/services / /api/operations / /api/dependencies 16686 元数据与依赖图
GET /api/v3/*(稳定)/ gRPC jaeger.api_v3.QueryService 16686 / 16685 程序化查询推荐
GET /sampling?service= 5778 远程采样策略

6. 告警与通知

Jaeger 自身没有告警引擎。生产做法:Collector service.telemetry.metrics(或 SPM 的 spanmetrics connector)→ Prometheus 抓取 → Alertmanager 通知;RED 指标走 SPM + Grafana。以下规则基于 OTel Collector 内部指标(真实存在:otelcol_receiver_accepted_spans、otelcol_exporter_send_failed_spans、otelcol_processor_dropped_spans),SPM 指标名以实际 /metrics 暴露为准。

# prometheus/rules.yml —— 管线健康告警(OTel Collector 内部指标,真实存在)
groups:
  - name: jaeger-pipeline
    rules:
      - { alert: JaegerReceiverNoSpans, expr: 'sum(rate(otelcol_receiver_accepted_spans{receiver="otlp"}[5m])) == 0', for: 10m, labels: {severity: warning} }
      - { alert: JaegerExportFailures, expr: 'sum(rate(otelcol_exporter_send_failed_spans[5m])) > 0', for: 5m, labels: {severity: critical} }
      - { alert: JaegerSpanDropped, expr: 'sum(rate(otelcol_processor_dropped_spans[5m])) > 0', for: 5m, labels: {severity: warning} }
# alertmanager.yml —— 多通道通知 + 噪声抑制
route:
  group_by: [alertname, service]
  group_wait: 30s
  group_interval: 5m
  repeat_interval: 4h
  receiver: webhook-default
  routes:
    - { matchers: ['severity="critical"'], receiver: wechat-p0 }
receivers:
  - name: webhook-default
    webhook_configs:
      - url: http://<告警网关_HOST>:<PORT>/jaeger/alarm      # 网关转发钉钉/飞书/邮件
  - name: wechat-p0
    webhook_configs:
      - url: https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=<企业微信机器人key>
  - name: email-p2
    email_configs:
      - { to: <值班邮箱>, from: <发件邮箱>, smarthost: '<SMTP_HOST>:587', auth_username: <账号>, auth_password: <密码> }
inhibit_rules:                        # P0 触发时压掉同源 P2
  - { source_matchers: ['severity="critical"'], target_matchers: ['severity="warning"'], equal: [alertname, service] }
# 钉钉由告警网关按 Alertmanager JSON 渲染后转发
curl -sS -X POST 'https://<钉钉机器人Webhook URL>' -H 'Content-Type: application/json' -d '{"msgtype":"text","text":{"content":"Jaeger 告警:<alerts>"}}'

降噪:for 持续时长、group_by 聚合、repeat_interval 重发间隔、inhibit_rules 抑制、按 service/severity 分级路由;SPM 的 RED 告警(错误率、P99)另配 recording rule,指标名以 spanmetrics connector 的 namespace 为准。

7. 实战场景

7.1 接入一个 Java 服务(OTel Agent)

  • 目标/步骤:不改业务代码让 checkout 出 Trace → 起 all-in-one → 挂 OTel Java Agent → 造流量。
docker run -d --name jaeger -p 16686:16686 -p 4317:4317 -p 4318:4318 cr.jaegertracing.io/jaegertracing/jaeger:${JAEGER_VER}
export OTEL_SERVICE_NAME=checkout OTEL_EXPORTER_OTLP_ENDPOINT=http://<JAEGER_HOST>:4318
export OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf OTEL_PROPAGATORS=tracecontext,baggage
java -javaagent:/opt/opentelemetry-javaagent.jar -jar /app/checkout.jar
curl -sS http://localhost:8080/api/checkout/1
  • 验证:/api/services 出现 checkout;UI Search 有瀑布图。回滚:去掉 -javaagent 与 OTEL_* 重启应用;⚠️ 容器级全局环境变量回滚时一并清理。

7.2 定位一次慢调用

  • 目标/步骤:下单偶发 >800ms → 按耗时检索 → 看瀑布图 → 比对正常/异常 Trace → 加 SPM 告警。
curl -sS 'http://<JAEGER>:16686/api/traces?service=checkout&limit=50&minDuration=800ms&lookback=1h'
curl -sS http://<JAEGER>:16686/api/traces/<trace-id> | jq '.data[0].spans[] | {operationName,duration,tags}'
curl -sS 'http://<JAEGER>:16686/api/dependencies?endTs=<毫秒时间戳>&lookback=3600000'
# UI:Search → Min Duration=800ms → 点 Trace 找最长 Span(DB/RPC);补 SPM P99 告警(第 6 章)
  • 验证:单个 Span 占总耗时 >70% 且 DB/RPC tag 明确、依赖图边吻合。回滚:删除 rules.yml 对应 group 并热重载 Prometheus;⚠️ 勿改 Jaeger 采集配置。

7.3 接入一个 Go 服务(OTel SDK)

  • 目标/步骤:用标准 OTel SDK 上报 OTLP,不依赖 Jaeger 私有客户端;引入 otel + otlptracehttp,环境变量初始化,出口注入 traceparent。
// main.go 片段,依赖版本以 OpenTelemetry 官方最新稳定版为准
package main
import (
  "context"
  "go.opentelemetry.io/otel"
  "go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp"
  "go.opentelemetry.io/otel/sdk/trace"
)
func main() {
  exp, _ := otlptracehttp.New(context.Background())   // 读 OTEL_EXPORTER_OTLP_ENDPOINT 等环境变量
  tp := trace.NewTracerProvider(trace.WithBatcher(exp))
  otel.SetTracerProvider(tp)
  defer tp.Shutdown(context.Background())
  _, span := otel.Tracer("order-go").Start(context.Background(), "POST /orders")
  defer span.End()   // 出口用 otelhttp/httptrace 注入 traceparent,保证跨服务不断链
}
export OTEL_SERVICE_NAME=order-go OTEL_EXPORTER_OTLP_ENDPOINT=http://<JAEGER_HOST>:4318
export OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf OTEL_PROPAGATORS=tracecontext,baggage
go mod tidy && go run .
  • 验证:/api/services 出现 order-go,依赖图出现与 checkout 的调用边。回滚:去掉 OTel 初始化或清空 OTEL_* 重启;⚠️ 同集群其他 SDK 依赖这些变量时注意隔离。

7.4 Tail Sampling 保留错误与慢链路

  • 目标/步骤:流量大只留有价值 Trace → config.yaml 加 tail_sampling(4.4)→ 客户端 OTEL_TRACES_SAMPLER=always_on → 重启 Collector。
  • 验证::8888/metrics 的 otelcol_processor_dropped_spans 上升,仍能查到 ERROR 与 >500ms Trace。回滚:processors 改回 [batch] 重启;⚠️ 多副本尾部采样须按 TraceID 一致性路由,否则决策不准。

8. 日常运维与故障排查

systemctl status jaeger && journalctl -u jaeger -f          # 服务管理 / 二进制日志
docker logs -f jaeger 2>&1 | grep -iE 'error|dropped|ready' # 容器日志
curl -sS http://<JAEGER>:13133/                            # health_check 扩展
curl -sS http://<JAEGER>:8888/metrics | grep otelcol_       # 自监控指标
curl -sS http://<JAEGER>:16686/api/services                 # 查询面可用性
现象 原因 处置
应用上报后 UI 查不到 OTLP endpoint 写成 localhost / 端口未映射 / 服务名过滤错 容器内用 0.0.0.0 监听、应用指向可达地址;确认 4317/4318 已 -p 映射;curl 直投验证
connection refused :4317 collector 未起或只监听 localhost 检查 receivers.otlp.protocols.*.endpoint;用 --set 覆盖为 0.0.0.0
配置了扩展但不生效 service.extensions 未列出 / pipeline 未引用 exporter 补 extensions: [jaeger_storage, jaeger_query];确认 service.pipelines.traces.exporters
查询报 storage not found jaeger_query.storage.traces 与 jaeger_storage.backends 名字不一致 两处用同一 backend 名
重启后 Trace 全丢 / 高压下丢 span memory 临时存储 / 队列满、存储写慢 换持久化后端;调 queue_size、num_consumers、batch;接 Kafka 缓冲;⚠️ memory 禁生产
链路断裂只剩半条 / 时间线错乱 双重采样、Context 未透传 / 时钟漂移 采样二选一、透传 traceparent;全节点 NTP、调 max_clock_skew_adjust
ES 索引暴涨 未配 TTL / 索引清理器 用 jaeger-es-index-cleaner 或 ILM 定期清旧索引

9. 性能、容量与高可用

维度 建议
探针开销 / 采样率 / 容量估算 OTel SDK 开销随 Span/属性数增长,控制 attributes 并压测校准;低流量全采、高流量头部 1%~10% + 尾部保错误/慢调用。日容量 ≈ 日均 Span 数 × 单 Span 压缩后字节 × 副本数 × 保留天数 ÷ 采样率,先用 7 天试运行实测日增磁盘再外推
Collector 集群 / 读写分离 / 缓冲 collector 无状态可水平扩 + 前置 LB;拆 collector 与 query 两个 Deployment;queue 平滑短时峰值,持续峰值用 Kafka 中间缓冲(collector→kafka exporter、ingester→kafka receiver);尾部采样多副本需按 TraceID 一致性路由
自监控 / 存储 HA service.telemetry.metrics → :8888/metrics 抓 otelcol_receiver_accepted_spans/_send_failed_spans/_dropped_spans 与队列长度(第 6 章告警);大规模官方推荐 OpenSearch 多节点 + 副本,定期索引清理

10. 安全加固、备份与升级

项 做法
认证鉴权 / TLS / 暴露面 UI/API 默认无认证,置于 Ingress/反代后加 SSO/Basic Auth/ACL,或按 OTel Collector 配 TLS/auth 扩展(字段以所用版本为准);对外 HTTPS、内网 OTLP 可 mTLS。只对外暴露 UI :16686,其余端口与 :9200 仅内网可达(NetworkPolicy/安全组),⚠️ 勿把 /api/* 暴露公网
最小权限 / 敏感数据 非 root 运行、配置只读挂载、ES 账号只授所需索引;Span tag 可能含用户信息,用 attributes/redaction 处理器脱敏,控制 baggage 传播内容
数据保留与备份 / 版本兼容 主存储短 TTL、archive 手动归档,ES/OpenSearch 用 ILM/快照并定期演练恢复,配置与规则入 Git;v1 → v2 是架构级迁移,v2 不识别 SPAN_STORAGE_TYPE/COLLECTOR_*,须改写为 OTel Collector YAML,客户端统一用 OTel SDK/OTLP
升级与回滚 备份 → 预发验证 YAML 与 schema → 滚动升 collector → 升 query → 验证查询;保留上一版二进制/镜像 tag。⚠️ 存储 schema(尤其 ES 索引)通常不可自动降级,回滚前先做快照

11. 常见坑

# 现象 原因 解决
1 ⚠️ 照旧博客用 jaegertracing/all-in-one / jaeger-collector 镜像拉不到或无更新 v1 已 2025-12-31 EOL,镜像迁到 cr.jaegertracing.io/ 改用 cr.jaegertracing.io/jaegertracing/jaeger:<版本> 单二进制
2 ⚠️ 用 SPAN_STORAGE_TYPE=elasticsearch 等变量配 v2 完全无效 v2 只认 --config 的 OTel Collector YAML 改 YAML;需要变量用 ${env:VAR:-default} 展开
3 应用上报 200 但 UI 无数据 / 启动报 extension not found 只监听 localhost、端口未映射 / service.extensions 漏列 endpoint 改 0.0.0.0、检查 -p;显式列出扩展并让 pipeline 引用同名 backend
4 ⚠️ 生产用 memory,重启 Trace 全丢 / ES 磁盘打满 memory 临时存储 / 无 TTL 与索引清理 换 OpenSearch/ES/Cassandra/Badger;配 ILM 与 jaeger-es-index-cleaner
5 链路只剩半条 / 时间线错乱 双重采样、Context 未透传 / 时钟漂移 采样二选一、透传 traceparent;全节点 NTP、调 max_clock_skew_adjust
6 程序化调用 /api/traces 升级后字段变了 /api/* 是 internal、非稳定契约 改用 :16685 gRPC api_v3 或 /api/v3/*
7 ⚠️ 把 :16686 或 :9200 暴露公网 / 配了 tail_sampling 仍丢错误 Trace 默认无认证可被拖库 / decision_wait 过短或策略写错 内网隔离 + 代理鉴权;增大 decision_wait、num_traces,核对 policies
8 v1 Operator 的 Jaeger CR 用不了 Operator 面向 v1 架构 v2 用 Deployment + ConfigMap;Operator 支持情况以官方文档为准

12. 速查表

项目 值 / 命令
分类 / 授权 05 APM与链路追踪 / Apache License 2.0
官网 / 仓库 https://www.jaegertracing.io/ | https://github.com/jaegertracing/jaeger
镜像仓库 cr.jaegertracing.io/jaegertracing/jaeger:<版本>(v1 镜像已废弃)
启动 jaeger --config config.yaml / jaeger --set=<key>=<value>
OTLP 写入 :4317 gRPC、:4318 HTTP POST /v1/traces
UI / 查询 :16686、/api/services、/api/traces、/api/dependencies
稳定查询 :16685 gRPC api_v3 / :16686/api/v3/*
远程采样 :5778 GET /sampling?service=、:5779 gRPC
兼容写端口 :9411 Zipkin、:14250 legacy gRPC、:14268 legacy Thrift、:6831/6832 UDP
健康检查 / 自监控 :13133(health_check)、:8888/metrics(otelcol_*)
主配置 / 关键组件 --config config.yaml(示例 cmd/jaeger/config-{storage}.yaml);jaeger_storage/jaeger_query/remote_sampling/jaeger_storage_exporter/batch/tail_sampling
存储后端 memory / badger / cassandra / elasticsearch / opensearch / kafka / grpc(remote) / clickhouse(实验)
客户端接入 OTEL_EXPORTER_OTLP_ENDPOINT/OTEL_SERVICE_NAME/OTEL_TRACES_SAMPLER/OTEL_PROPAGATORS
采样策略文件 /etc/jaeger/sampling-strategies.json(default_strategy + service_strategies)
日志 / 服务管理 journalctl -u jaeger -f、docker logs jaeger、systemctl status jaeger
演示应用 / 要点 example-hotrod:<版本> UI http://localhost:8080;v1 EOL(2025-12-31)、v2 基于 OTel Collector、无内置告警

13. 选型建议与同类对比

维度 SkyWalking Jaeger Zipkin Pinpoint
定位 一体化 APM(Trace+Metrics+Log+Profile+Alarm) 专注链路追踪(v2 基于 OTel Collector) 轻量链路追踪 一体化 APM(偏 Java)
埋点 / 数据模型 / 存储 无侵入 Agent + eBPF + OTLP / 自有 + Zipkin、OTLP / BanyanDB/ES/OpenSearch/MySQL/PG 标准 OTel SDK/OTLP / OTLP 原生 + 兼容 Thrift、Zipkin / Memory/Badger/Cassandra/ES/OpenSearch/Kafka/Remote 引 Brave 库 / Zipkin v2、B3 / ES/MySQL/Cassandra/内存 Java 字节码增强 / 自有 / HBase 为主
指标告警 / 运维 / 治理 内置 MAL/MQE + 告警引擎 / 中高(OAP 集群)/ ASF 顶级、国产主导 无内置告警,需 Prometheus+SPM / 中(单二进制、无 JVM)/ CNCF 毕业、OTel 最贴合 无 / 低 / 老牌轻量 内置有限 / 高(HBase)/ 韩国起源、Java 强

何时选 Jaeger:已标准化 OpenTelemetry、只要链路追踪与根因定位、希望后端可插拔且读写分离、不想引入 APM 全家桶;CNCF/OTel 生态优先。 何时不选:需要 Trace/Metrics/Log/告警一体(选 SkyWalking);需要无侵入多语言探针(选 SkyWalking/Pinpoint);小团队只要最快上手且数据量小(Zipkin 更轻);需要商业托管支持。 与 SkyWalking 组合:应用统一 OTel SDK 上报,OTLP 同时送 Jaeger(纯 Trace 归档/OTel 原生)与 SkyWalking(APM 与告警),避免双探针。

14. 参考链接

Jaeger —— 基于 OpenTelemetry Collector 的分布式链路追踪平台 - 知识库 - 起航社区