Jaeger 面试题
30 道题- 分类
- 可观测性
- 子分类
- trace
- 题目数
- 30 道
1 Jaeger 的核心架构由哪些组件组成?
答案:
Jaeger 是 Uber 开源的分布式追踪系统,CNCF 毕业项目,用于监控和排查微服务架构的请求延迟。
核心组件:
| 组件 | 职责 | 说明 |
|---|---|---|
| Agent | 客户端代理 | UDP 接收 Span,批量发送到 Collector |
| Collector | 数据收集器 | 接收 Span、验证、存储、队列处理 |
| Query | 查询服务 | API + UI 的查询后端 |
| Ingester | Kafka 消费 | 从 Kafka 读取 Span 写入存储 |
| Storage | 后端存储 | Cassandra / Elasticsearch / Badger |
| UI | Web 界面 | Trace 查询、搜索、依赖图 |
架构演进:
传统架构(Agent + Collector 直连):
App → Jaeger Agent (UDP) → Collector → Storage → Query → UI
生产架构(Kafka 缓冲):
App → Jaeger Agent (UDP) → Collector → Kafka → Ingester → Storage → Query → UI
All-in-One 模式(开发测试):
docker run -d --name jaeger \
-p 16686:16686 \
-p 4317:4317 \
-p 4318:4318 \
jaegertracing/all-in-one:latest
2 Jaeger 的数据模型:Span、Trace 和 Reference 的关系是什么?
答案:
Jaeger 的数据模型遵循 OpenTracing 规范,由 Span 构成 Trace,Span 之间通过 References 建立关系。
数据模型层次:
Trace (全局调用链)
│
├── Span (Root: HTTP GET /api)
│ ├── Tags: http.method=GET, http.status_code=200
│ ├── Logs: "db.query" {sql: "SELECT..."}
│ │
│ ├── ChildOf Reference
│ │ └── Span (Child: SELECT FROM users)
│ │
│ └── FollowsFrom Reference
│ └── Span (Async: send email)
│
└── Span (Root: 独立请求)
Span 核心字段:
| 字段 | 含义 | 示例 |
|---|---|---|
| traceID | Trace 唯一 ID | 0af7651916cd43dd |
| spanID | Span 唯一 ID | b7ad6b7169203331 |
| operationName | 操作名称 | HTTP GET /api/users |
| references | 引用关系 | ChildOf / FollowsFrom |
| startTime | 开始时间 (μs) | 1716700000000000 |
| duration | 持续时长 (μs) | 150000 (150ms) |
| tags | 键值对标签 | http.method=GET |
| logs | 时间戳事件 | 错误/异常记录 |
| process | 进程标识 | service-a, host-1 |
Reference 类型:
| 类型 | 语义 | 场景 |
|---|---|---|
| ChildOf | 父 Span 等待子 Span 完成 | 同步 RPC、DB 查询 |
| FollowsFrom | 父 Span 不等待子 Span | 异步消息、后台任务 |
Span 序列化(Thrift/Protobuf):
{
"traceID": "0af7651916cd43dd8448eb211c80319c",
"spanID": "b7ad6b7169203331",
"operationName": "HTTP GET /api/users",
"references": [
{"refType": "CHILD_OF", "traceID": "...", "spanID": "..."}
],
"startTime": 1716700000000000,
"duration": 150000,
"tags": [
{"key": "http.method", "vType": "STRING", "vStr": "GET"},
{"key": "http.status_code", "vType": "INT64", "vInt64": 200}
],
"logs": [
{"timestamp": 1716700000050000, "fields": [
{"key": "event", "vStr": "error"},
{"key": "message", "vStr": "connection refused"}
]}
],
"process": {"serviceName": "user-service", "tags": []}
}
3 Jaeger Agent 的工作原理是什么?与 OTel Collector 的关系?
答案:
Jaeger Agent 是与应用同机部署的守护进程,负责接收和转发 Span 数据。
Agent 工作流程:
graph TD
A["Application"]
B["Jaeger Client SDK"]
C["Jaeger Agent<br/>(本地守护进程)"]
D["缓冲 + 批量"]
E["Collector / Kafka"]
A --> B -->|"UDP (thrift) → localhost:6831"| C --> D -->|"gRPC"| E
Agent 配置:
# jaeger-agent.yaml
reporter:
collectorEndpoint: "http://jaeger-collector:14250"
# 或使用 Kafka
# kafka:
# bokerServers: kafka:9092
# 批量配置
batchSize: 1000
batchWorkers: 100
batchLinger: 1s
# 最大队列大小
queueSize: 10000
# 日志报告
logging:
options: []
# 代理端口
process:
# UDP 端口(接收客户端数据)
zipkinCompactPort: 5775
jaegerCompactPort: 6831
jaegerBinaryPort: 6832
# 管理端口
adminPort: 14269
Agent vs OTel Collector:
| 维度 | Jaeger Agent | OTel Collector |
|---|---|---|
| 语言 | Go | Go |
| 定位 | Jaeger 专属代理 | 通用遥测网关 |
| 协议 | Jaeger Thrift (UDP) | OTLP (gRPC/HTTP) |
| 部署 | Sidecar 模式 | DaemonSet/Gateway |
| 数据格式 | Jaeger 原生 | OTLP |
| 互操作性 | 仅 Jaeger | 多后端 |
Jaeger v1.35+ 推荐使用 OTel Collector 替代 Agent:
应用 → OTel SDK → OTel Collector → Jaeger (OTLP)
4 Jaeger Collector 的伸缩机制和队列配置是什么?
答案:
Jaeger Collector 是无状态组件,通过 Kafka 缓冲实现弹性伸缩和故障容忍。
Collector 架构:
graph TD
Entry[HTTP/gRPC 入口] --> Receiver[Collector 接收器]
Receiver --> Processor[Span Processor - 验证/清洗]
Processor --> Queue[内部队列 - 内存/磁盘]
Queue --> Direct[直连写入 Storage]
Queue --> Kafka[Kafka 写入 - 缓冲层]
Kafka --> Ingester[Ingester]
Ingester --> Storage2[Storage]
队列配置:
# jaeger-collector.yaml
collector:
# gRPC 端口
grpc:
hostPort: ":14250"
# HTTP 端口
http:
hostPort: ":14268"
# 内部队列
queue-size: 20000 # 队列最大大小
num-workers: 100 # 处理 worker 数
# Span 处理
max-span-age: "0s" # Span 最大年龄
max-msg-size: "4mib" # 消息大小限制
# 直连存储(无 Kafka)
storage:
type: elasticsearch # cassandra / elasticsearch / kafka
# Kafka 写入
kafka:
producer:
topic: jaeger-spans
borkers: kafka:9092
batch-size: 1000
batch-linger: 1s
Collector 伸缩:
Kubernetes Deployment (无状态):
replicas: N
水平扩展依据:
- Span 接收速率
- 队列积压深度
- 后端存储写入延迟
建议:
每个 Collector 处理 10k-50k Spans/s
通过 HPA 自动伸缩
使用 PDB 保证最小可用
背压机制:
队列满 → 阻塞接收 → 客户端重试
↓
客户端 SDK 内部的缓冲队列
↓
队列满 → 客户端丢弃 Span
5 Jaeger 支持的存储后端有哪些?各自的选型场景是什么?
答案:
Jaeger 支持 Cassandra、Elasticsearch 和 Badger 三种存储后端。
存储方案对比:
| 维度 | Cassandra | Elasticsearch | Badger |
|---|---|---|---|
| 类型 | NoSQL 列族 | 搜索引擎 | 嵌入式 KV |
| 写入性能 | 极高 | 高 | 中 |
| 查询性能 | 高(按 Key) | 极高(全文) | 中 |
| 存储成本 | 低(压缩好) | 高(索引) | 低 |
| 运维复杂度 | 高 | 中 | 低 |
| 持久化 | 是 | 是 | 是 |
| 集群模式 | 原生 | 原生 | 单节点 |
| 推荐场景 | 大规模 | 中大规模 | 开发/小规模 |
Elasticsearch 配置:
storage:
type: elasticsearch
elasticsearch:
hostPorts: "es-1:9200,es-2:9200,es-3:9200"
indexPrefix: "jaeger"
indexDateSeparator: "-"
username: "elastic"
password: "password"
# 索引配置
numberOfShards: 5
numberOfReplicas: 1
# 批量写入
bulk:
size: 5000000 # 5MB
workers: 10
flushInterval: 1s
# TTL
esSpanTTL: "72h"
esServiceCacheTTL: "12h"
esDependenciesTTL: "72h"
Cassandra 配置:
storage:
type: cassandra
cassandra:
hostPorts: "cassandra-1:9042,cassandra-2:9042"
keyspace: "jaeger_v1"
connectionsPerHost: 3
maxRetryAttempts: 3
timeout: 2s
# 表配置
spanTableCompaction:
class: "LeveledCompactionStrategy"
dependenciesTableCompaction:
class: "LeveledCompactionStrategy"
Badger 配置(单节点):
storage:
type: badger
badger:
directoryKey: "/data/badger/key"
directoryValue: "/data/badger/data"
ephemeral: false
6 Jaeger 的采样策略有哪些?如何配置自适应采样?
答案:
Jaeger 支持多种采样策略,从简单的概率采样到灵活的自适应远程采样。
采样策略类型:
| 策略 | 说明 | 配置方式 |
|---|---|---|
| Const | 全部采样/不采样 | sampler.type=const, sampler.param=1 |
| Probabilistic | 按概率随机采样 | sampler.type=probabilistic, sampler.param=0.1 |
| RateLimiting | 固定速率采样 | sampler.type=ratelimiting, sampler.param=10 |
| Remote | 从 Agent 拉取策略 | 默认策略,可动态更新 |
Remote 采样策略(推荐):
graph TD
A["Application"] -->|"HTTP"| JA["Jaeger Agent"]
JA -->|"每 60 秒<br/>拉取采样策略"| JA2["Agent<br/>策略拉取"]
JA2 -->|"gRPC"| C["Collector<br/>策略配置"]
C --> S["采样策略<br/>默认概率: 0.1<br/>端点特定策略:<br/>/api/health: 0<br/>/api/order: 1<br/>/api/pay: 0.5"]
采样策略配置(Collector 侧):
// 通过 Collector API 配置
POST /api/sampling
{
"service": "user-service",
"strategyType": "PROBABILISTIC",
"probabilisticSampling": {
"samplingRate": 0.1
}
}
// 端点级采样策略
{
"service": "order-service",
"strategyType": "RATE_LIMITING",
"rateLimitingSampling": {
"maxTracesPerSecond": 50
},
"operationSampling": {
"defaultSamplingProbability": 0.1,
"perOperationSampling": [
{
"operation": "GET /api/health",
"samplingProbability": 0
},
{
"operation": "POST /api/orders",
"samplingProbability": 1
}
]
}
}
Go 客户端配置:
import "github.com/jaegertracing/jaeger-client-go"
// Const 采样(全部采样)
sampler, _ := jaeger.NewConstSampler(true)
// 概率采样
sampler, _ := jaeger.NewProbabilisticSampler(0.1)
// 速率限制采样
sampler := jaeger.NewRateLimitingSampler(10) // 10 traces/s
// Remote 采样(推荐)
sampler, _ := jaeger.NewRemotelyControlledSampler(
"user-service",
jaeger.WithSamplingServerURL("http://jaeger-agent:5778/sampling"),
jaeger.WithMaxOperations(1000),
jaeger.WithSamplingRefreshInterval(time.Minute),
)
7 Jaeger UI 的 Trace 搜索和详情查看功能是什么?
答案:
Jaeger UI 提供 Trace 搜索、对比、详情和依赖图等核心功能。
搜索功能:
搜索条件:
- 服务名 (必选)
- 操作名 (可选)
- Tags: http.status_code=200
- 最短持续时间: 100ms
- 时间范围
- 限制返回条数
搜索结果列表:
- Trace ID
- 操作名
- 耗时 (最短/最长/平均)
- Span 数量
- 错误状态
- 时间
排序:By Most Recent / By Longest Duration
Trace 详情视图:
甘特图(Gantt Chart):
X 轴: 时间线
Y 轴: Span 列表(按服务分组)
宽度: Span 持续时间
颜色: 按服务不同
每个 Span 详情:
- Tags: 关键属性 (http、db、messaging)
- Process: 服务名、主机
- Logs: 时间戳事件列表
- References: 父 Span 引用
功能:
- 展开/折叠 Span 树
- 点击 Tags 跳转到搜索
- 对比多个 Trace
- 下载 Trace JSON
Trace 对比:
选择 2-10 个 Trace 对比
→ 并列显示甘特图
→ 高亮差异部分
→ 统计汇总(平均耗时、慢 Span)
用途:
对比正常请求和慢请求
对比新旧版本请求
对比不同路由的请求
依赖图(Dependency Graph):
自动生成服务调用拓扑
节点: 服务 (颜色表示健康状态)
边: 调用关系 (标注 QPS)
布局: 力导向图
来源: Spark 作业或 Collector 实时计算
8 Jaeger 的 Span 传播格式有哪些?如何实现跨服务上下文传递?
答案:
Jaeger 支持多种传播格式,包括 Jaeger 原生格式、Zipkin B3 和 W3C TraceContext。
支持的传播格式:
| 格式 | Header | 说明 | 状态 |
|---|---|---|---|
| Jaeger | uber-trace-id | Jaeger 原生 (Deprecated) | 传统 |
| Jaeger Thrift | jaeger-* | UDP 传输格式 | Agent 协议 |
| B3 | x-b3-* | Zipkin 兼容 | 兼容 |
| W3C TraceContext | traceparent, tracestate | 行业标准 | 推荐 |
W3C TraceContext(当前推荐):
Header: traceparent: 00-traceid-spanid-01
格式: 版本 - 32 位 traceid - 16 位 spanid - 标志
传播流程:
服务A → HTTP Header → 服务B
traceparent: 00-0af7651916cd43dd8448eb211c80319c-b7ad6b7169203331-01
Go SDK 配置:
import (
"github.com/jaegertracing/jaeger-client-go/config"
"github.com/opentracing/opentracing-go"
"github.com/uber/jaeger-lib/metrics/prometheus"
)
cfg := config.Configuration{
ServiceName: "user-service",
Sampler: &config.SamplerConfig{
Type: jaeger.SamplerTypeRemote,
},
Reporter: &config.ReporterConfig{
CollectorEndpoint: "http://jaeger-collector:14268/api/traces",
},
// Headers 配置
Headers: &config.HeadersConfig{
JaegerDebugHeader: "jaeger-debug-id",
JaegerBaggageHeader: "jaeger-baggage",
TraceContextHeaderName: "traceparent", // W3C
TraceBaggageHeaderPrefix: "tracestate",
},
}
tracer, closer, _ := cfg.NewTracer(
config.Metrics(prometheus.New()),
)
HTTP 传播(手动):
// 注入到出站请求
span := tracer.StartSpan("HTTP POST")
ext.SpanKindRPCClient.Set(span)
ext.HTTPMethod.Set(span, "POST")
tracer.Inject(span.Context(), opentracing.HTTPHeaders, r.Header)
// 从入站请求提取
spanCtx, _ := tracer.Extract(opentracing.HTTPHeaders, r.Header)
span := tracer.StartSpan("HTTP GET", ext.RPCServerOption(spanCtx))
9 Jaeger 如何与 Prometheus 集成实现统一的可观测性?
答案:
Jaeger 通过 Span Metrics 和 Exemplar 机制实现 Trace 与 Metrics 的关联。
集成方式:
方式一:Exemplar 关联
Jaeger UI → 点击示例 → 跳转到 Prometheus
Prometheus → 查看 Exemplar → 跳转到 Jaeger
方式二:Span 指标导出
Jaeger Collector → 计算 Metrics → Prometheus
方式三:统一仪表盘
Grafana → Jaeger + Prometheus 双数据源
Jaeger 导出 Metrics:
# Jaeger Collector 配置
collector:
# 启用 Prometheus Metrics
metricsBackend: prometheus
metricsHTTPPort: 14271
# 导出内置指标
# - jaeger_collector_spans_received_total
# - jaeger_collector_spans_saved_total
# - jaeger_collector_traces_received_total
# - jaeger_query_requests_total
# - jaeger_query_latency_seconds
Grafana 统一查询:
Jaeger 数据源:搜索 Trace
Prometheus 数据源:查询 Metrics
典型场景:
Prometheus 检测到高错误率
→ 查看 Exemplar 的 Trace ID
→ 在 Jaeger 中查看完整 Trace
→ 定位根因
Jaeger Query Prometheus 集成(v1.35+):
# jaeger-query.yaml
prometheus:
serverURL: "http://prometheus:9090"
query:
# 查询示例标签
tags:
- key: "service"
value: "XQOPEN.ServiceNameXQCLOSE"
# UI 配置
ui:
config:
metrics:
# 关联 Metrics 数据源
prometheus:
defaultDS: "Prometheus"
queries:
- name: "请求速率"
query: "rate(request_duration_seconds_count{service='$service'}[5m])"
- name: "错误率"
query: "rate(request_duration_seconds_count{status_code=~'5..'}[5m])"
10 Jaeger 的 gRPC 和 Thrift 协议传输的区别是什么?
答案:
Jaeger 支持 Thrift(UDP 传统)和 gRPC(现代推荐)两种传输协议。
协议对比:
| 维度 | Thrift (UDP) | gRPC |
|---|---|---|
| 传输层 | UDP | HTTP/2 |
| 编码 | Thrift Binary | Protobuf |
| 可靠性 | 丢失风险 | 可靠(TCP) |
| 性能 | 极高(无连接) | 高 |
| 批量 | 少数批量 | 高效批量 |
| 压缩 | 无 | 支持 gzip |
| 认证 | 无 | TLS/mTLS |
| 推荐 | 历史原因 | 当前标准 |
Thrift UDP 配置(传统 Agent 模式):
# jaeger-client
reporter:
# Agent UDP 配置
logSpans: false
localAgentHostPort: "localhost:6831"
flushInterval: 1000ms
queueSize: 10000
maxPacketSize: 65000
gRPC 配置(推荐):
# jaeger-client 直连 Collector
reporter:
collectorEndpoint: "http://jaeger-collector:14250"
# gRPC 配置
collectorUser: ""
collectorPassword: ""
httpHeaders:
Authorization: "Bearer token"
迁移建议:
旧架构:应用 Thrift UDP → Agent Thrift UDP → Collector
(每部署一个 Agent,UDP 有丢失风险)
新架构:应用 gRPC → OTel Collector → Jaeger
(可靠传输,统一 OTel 标准)
11 Jaeger 的服务依赖图(Service Dependency Graph)是如何生成的?
答案:
Jaeger 通过分析 Span 间的引用关系自动生成服务依赖图。Spark 作业或 Collector 实时计算两种方式。
依赖图生成原理:
Span A (Service A: HTTP Client)
↓ ChildOf Reference (http.url=http://service-b/api)
Span B (Service B: HTTP Server)
提取依赖关系:
Source: Service A
Target: Service B
Operation: GET /api
Call Count: 100
Error Rate: 1%
Avg Duration: 50ms
生成方式对比:
| 方式 | 数据源 | 延迟 | 大数据量 | 运维 |
|---|---|---|---|---|
| Spark 作业 | 存储 (ES/Cassandra) | 小时级 | 支持 | 需 Spark 集群 |
| Collector 实时 | 内存流处理 | 分钟级 | 有限 | 无需额外组件 |
Spark 作业配置:
# spark-dependencies.yaml
spark:
type: "spark"
dependencies:
# Spark 作业参数
sparkMaster: "spark://spark-master:7077"
# 处理间隔
scheduleInterval: "1h"
# 时间窗口
lookback: "1d"
依赖图 API:
GET /api/dependencies?endTs=1716700000&lookback=1h
响应:
{
"data": [
{
"parent": "user-service",
"child": "order-service",
"callCount": 1000,
"errorCount": 5
},
{
"parent": "order-service",
"child": "payment-service",
"callCount": 800,
"errorCount": 10
}
]
}
依赖图 UI 展示:
力导向图布局:
- 节点: Service(圆角矩形)
- 边: 调用方向(箭头)
- 节点颜色: 正常运行/错误/高延迟
- 边数字: 调用量
交互:
- 鼠标悬停 → 显示详细数据
- 点击节点 → 跳转到服务 Trace 列表
- 调整时间范围 → 动态更新
12 Jaeger Query 服务和 UI 部署的高可用方案是什么?
答案:
Jaeger Query 和 UI 是无状态组件,通过负载均衡和多副本实现高可用。
Query 高可用部署:
graph TD
LB[Load Balancer - Nginx/ALB] --> Q1[Query-1]
LB --> Q2[Query-2]
LB --> Q3[Query-3 - 无状态]
Q1 --> Storage[Storage - HA 存储]
Q2 --> Storage
Q3 --> Storage
K8s 部署:
apiVersion: apps/v1
kind: Deployment
metadata:
name: jaeger-query
spec:
replicas: 3
selector:
matchLabels:
app: jaeger-query
template:
metadata:
labels:
app: jaeger-query
spec:
containers:
- name: jaeger-query
image: jaegertracing/jaeger-query:latest
args:
- "--storage.type=elasticsearch"
- "--es.hostPorts=es-cluster:9200"
- "--es.indexPrefix=jaeger"
ports:
- containerPort: 16686 # UI + API
env:
- name: SPAN_STORAGE_TYPE
value: elasticsearch
resources:
limits:
memory: 1Gi
cpu: "1"
requests:
memory: 512Mi
cpu: 500m
readinessProbe:
httpGet:
path: /
port: 16686
apiVersion: v1
kind: Service
metadata:
name: jaeger-query
spec:
ports:
- port: 16686
targetPort: 16686
selector:
app: jaeger-query
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: jaeger-query-ingress
spec:
rules:
- host: jaeger.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: jaeger-query
port:
number: 16686
UI 配置:
# jaeger-query.yaml
ui:
config:
# 菜单链接
menu:
- label: "Grafana"
url: "https://grafana.example.com"
anchorTarget: "_blank"
# Track 深度限制
dependencies:
menuEnabled: true
menuLabel: "服务拓扑"
# 链路追踪配置
tracking:
gaID: ""
trackErrors: true
# 搜索配置
search:
maxLookback:
label: "2 天"
value: "2d"
maxDuration: 0
13 Jaeger 的 Adaptive Sampling(自适应采样)如何工作?
答案:
Jaeger 自适应采样根据服务流量自动调整采样率,在保持代表性的同时控制存储成本。
自适应采样原理:
Collector → 分析各端点的流量
│
计算每个端点的最佳采样率
│
高流量端点 → 低采样率
低流量端点 → 高采样率
错误端点 → 强制 100%
│
下发给 Agent (每 60 秒)
│
Agent 缓存策略 → 客户端执行
策略计算规则:
目标: 每个端点每秒采集 N 条 Trace (如 token=10)
计算:
traffic = 端点调用量 (traces/s)
rate = min(1, token / traffic)
效果:
1k/s 的端点: rate = min(1, 10/1000) = 1%
5/s 的端点: rate = min(1, 10/5) = 100%
0.5/s 的端点: rate = min(1, 10/0.5) = 100%
自适应采样配置:
# jaeger-collector.yaml
collector:
# 自适应采样配置
sampling:
# 策略存储
strategiesFile: "/etc/jaeger/sampling_strategies.json"
# 自动更新间隔
strategiesFileReloadInterval: 5m
# 每端点每秒目标采样数
defaultTargetPerSecond: 10
# 最小采样率
minSamplingRate: 0.001
自适应采样优势:
与传统固定概率采样对比:
固定 1% 采样:
1000/s 端点 → 10 条 (足够)
5/s 端点 → 0.05 条 (信息不足)
自适应采样:
1000/s 端点 → 10 条 (1%)
5/s 端点 → 5 条 (100%)
总存储 ≈ 固定采样,但低流量端点信息完整
14 Jaeger 与 OpenTelemetry 的关系和集成方式是什么?
答案:
Jaeger 从 v1.35 开始原生支持 OTLP 协议,可直接接收 OTel SDK 数据。
集成方式:
方式一:OTel SDK → Jaeger (OTLP)
App → OTel SDK → Jaeger Collector (gRPC:4317)
Jaeger v1.35+ 原生支持
方式二:OTel SDK → OTel Collector → Jaeger
App → OTel SDK → OTel Collector → Jaeger (OTLP/Jaeger gRPC)
方式三:Jaeger SDK → Jaeger Agent → Jaeger Collector
旧架构,已被 OTel 取代
Jaeger 原生 OTLP 接收(v1.35+ 推荐):
# jaeger-collector.yaml
collector:
# 直接接收 OTLP 数据
otlp:
grpc:
hostPort: ":4317"
http:
hostPort: ":4318"
# 仍然支持 Jaeger 原生协议
grpc:
hostPort: ":14250"
OTel Collector → Jaeger 输出:
receivers:
otlp:
protocols:
grpc:
endpoint: 0.0.0.0:4317
processors:
batch:
timeout: 1s
send_batch_size: 1024
exporters:
otlp:
endpoint: jaeger:4317
tls:
insecure: true
service:
pipelines:
traces:
receivers: [otlp]
processors: [batch]
exporters: [otlp]
迁移路径:
从 Jaeger SDK → OTel SDK 的迁移:
1. 添加 OTel SDK 依赖
2. 使用 OTel API 替代 Jaeger API
3. 配置 OTLP Exporter 指向 Jaeger
4. 逐步下线 Jaeger SDK
优势:
- 同一套 API 可同时发给 Jaeger 和其他后端
- 未来可切换后端无需修改代码
- 支持 Traces + Metrics + Logs 全套
15 Jaeger 的告警和监控体系如何搭建?
答案:
Jaeger 本身不提供告警引擎,通过 Prometheus + AlertManager + Grafana 组合实现告警。
监控指标暴露:
# Jaeger 组件 Prometheus 指标端口
collector:
metricsHTTPPort: 14271 # /metrics
query:
metricsHTTPPort: 16687 # /metrics
agent:
adminPort: 14269 # /metrics
关键告警指标:
| 指标 | 含义 | 告警阈值 |
|---|---|---|
jaeger_collector_spans_received_total | Span 接收数 | 低于预期 (服务异常) |
jaeger_collector_spans_saved_total | Span 存储数 | 低于接收数 (存储故障) |
jaeger_collector_queue_length | 队列长度 | > 阈值 (积压) |
jaeger_query_requests_total | 查询请求数 | 异常波动 |
jaeger_query_latency_seconds | 查询延迟 | > 5s |
Prometheus 告警规则:
groups:
- name: jaeger
rules:
- alert: JaegerCollectorDown
expr: up{job="jaeger-collector"} == 0
for: 1m
- alert: JaegerQueueBacklog
expr: jaeger_collector_queue_length > 10000
for: 5m
- alert: JaegerSpansNotStored
expr: rate(jaeger_collector_spans_received_total[5m]) - rate(jaeger_collector_spans_saved_total[5m]) > 100
for: 5m
- alert: JaegerHighTraceLatency
expr: histogram_quantile(0.99, rate(jaeger_query_latency_seconds_bucket[5m])) > 5
for: 5m
Grafana Dashboard:
{
"title": "Jaeger Overview",
"panels": [
{"title": "Span Ingestion Rate", "targets": [{"expr": "rate(jaeger_collector_spans_received_total[5m])"}]},
{"title": "Storage Savings Rate", "targets": [{"expr": "rate(jaeger_collector_spans_saved_total[5m])"}]},
{"title": "Queue Length", "targets": [{"expr": "jaeger_collector_queue_length"}]},
{"title": "Query Latency P99", "targets": [{"expr": "histogram_quantile(0.99, rate(jaeger_query_latency_seconds_bucket[5m]))"}]}
]
}
16 Jaeger 的 Kafka 作为缓冲层的架构是什么?
答案:
Kafka 作为 Jaeger Collector 和 Storage 之间的缓冲层,解耦数据生产和消费。
Kafka 缓冲架构:
graph TD
Agent[Agent] --> Collector[Collector]
Collector --> Kafka[Kafka]
Kafka --> Ingester[Ingester]
Ingester --> Storage[Storage]
Kafka --> D1[解耦生产/消费]
D1 --> D2[高吞吐写入 - 无背压问题]
D1 --> D3[异步消费 - 可回溯重试]
写入 Collector → Kafka:
# jaeger-collector.yaml
collector:
kafka:
producer:
topic: "jaeger-spans"
borkers: "kafka-1:9092,kafka-2:9092"
# 压缩
compression: "gzip"
# 批量配置
batch-size: 10000
batch-linger: 500ms
# 写入确认
required-acks: -1 # all
消费 Kafka → Storage(Ingester):
# jaeger-ingester.yaml
ingester:
kafka:
consumer:
topic: "jaeger-spans"
borkers: "kafka-1:9092,kafka-2:9092"
# 消费者组
group-id: "jaeger-ingester"
# Offset
auto-offset-reset: "earliest"
# 批量消费
fetch-min: 1000
fetch-max-wait: 1s
# 并发
num-workers: 100
# 存储写入
storage:
type: elasticsearch
elasticsearch:
hostPorts: "es-cluster:9200"
bulk:
size: 5000000
workers: 10
Kafka 缓冲优势:
| 优势 | 说明 |
|---|---|
| 解耦 | Collector 和 Storage 独立扩缩 |
| 缓冲 | 应对流量突发,Storage 不受冲击 |
| 重试 | Consumer 失败可回溯 Offset |
| 多消费 | 一份数据多个消费者(不同用途) |
| 跨 DC | Kafka MirrorMaker 跨 DC 复制 |
数据流保障:
Collector 写入 Kafka:
- 写入失败 → 返回背压到 Agent
- Kafka 集群故障 → Collector 队列积压
Ingester 消费 Kafka:
- 消费失败 → 自动重试
- 处理速度 < 写入速度 → 自动延迟
- 进程重启 → 从提交的 Offset 继续
17 Jaeger 的 Kubernetes 部署(Operator + Helm)方案是什么?
答案:
Jaeger 提供 Operator 和 Helm Chart 两种 K8s 部署方式。
Jaeger Operator(推荐):
# 安装 Operator
kubectl create namespace observability
kubectl create -f https://github.com/jaegertracing/jaeger-operator/releases/download/v1.57.0/jaeger-operator.yaml -n observability
# 创建 Jaeger 实例
CRD 配置:
apiVersion: jaegertracing.io/v1
kind: Jaeger
metadata:
name: jaeger-prod
spec:
strategy: production
storage:
type: elasticsearch
options:
es:
hostPorts: "es-cluster:9200"
indexPrefix: "jaeger"
indexDateSeparator: "-"
numberOfShards: 3
numberOfReplicas: 1
collector:
options:
collector:
queue-size: 20000
num-workers: 100
resources:
limits:
memory: 4Gi
cpu: "2"
requests:
memory: 2Gi
cpu: "1"
query:
options:
query:
max-clock-skew-adjustment: "0s"
resources:
limits:
memory: 1Gi
cpu: "1"
ingress:
enabled: true
annotations:
kubernetes.io/ingress.class: nginx
hosts:
- jaeger.example.com
agent:
strategy: DaemonSet
options:
agent:
reporter:
collector:
hostPort: "jaeger-prod-collector:14250"
ingester:
options:
ingester:
deadlockInterval: "0s"
resources:
limits:
memory: 2Gi
cpu: "1"
Helm 部署:
helm repo add jaegertracing https://jaegertracing.github.io/helm-charts
helm upgrade --install jaeger jaegertracing/jaeger \
--namespace observability \
--set provisionDataStore.cassandra=false \
--set storage.elasticsearch.host=es-cluster \
--set storage.elasticsearch.port=9200
18 Jaeger 的 Elasticsearch 索引管理(ILM)和 TTL 策略是什么?
答案:
Jaeger 在 ES 中按日期创建索引,通过 ES ILM 和 Jaeger TTL 配置管理数据生命周期。
Jaeger ES 索引命名:
jaeger-span-2026-05-26 # 每日 Span 索引
jaeger-service-2026-05-26 # 服务信息索引
jaeger-dependencies-2026-05-26 # 依赖图索引
ES ILM 策略:
PUT /_ilm/policy/jaeger-span-policy
{
"policy": {
"phases": {
"hot": {
"min_age": "0ms",
"actions": {
"rollover": {"max_age": "1d", "max_size": "50gb"}
}
},
"delete": {
"min_age": "7d",
"actions": {"delete": {}}
}
}
}
}
PUT /_index_template/jaeger-span
{
"index_patterns": ["jaeger-span-*"],
"template": {
"settings": {
"number_of_shards": 3,
"number_of_replicas": 1,
"index.lifecycle.name": "jaeger-span-policy",
"index.lifecycle.rollover_alias": "jaeger-span"
}
}
}
Jaeger TTL 配置:
# jaeger-collector 和 jaeger-query
storage:
elasticsearch:
esSpanTTL: "72h" # Span 数据保留 3 天
esServiceCacheTTL: "12h" # 服务缓存
esDependenciesTTL: "72h" # 依赖图数据保留
存储空间估算:
每个 Span 平均 2-5KB (含索引)
日处理量: 1 亿 Spans
每日 ES 存储: 1亿 × 3KB × 1.3(索引开销) × 2(副本) ≈ 780GB
TTL 7 天: 780GB × 7 ≈ 5.5TB
TTL 3 天: 780GB × 3 ≈ 2.3TB
19 Jaeger 的 Trace 对比和差异分析功能是什么?
答案:
Jaeger UI 支持多个 Trace 的并列对比,帮助定位性能差异和异常请求。
Trace 对比操作:
UI 操作流程:
1. 搜索列表勾选 2-10 个 Trace
2. 点击 "Compare Traces"
3. 并列显示甘特图
4. 统计汇总表格
对比维度:
- 总耗时对比
- 各服务耗时分布
- 错误 Span 标记
- Span 数量差异
对比视图:
甘特图并列(时间缩放同步):
Trace A: [======50ms=====][------30ms------][==20ms==]
Trace B: [==10ms=][------150ms------][==15ms==]
↑ 差异热点
统计对比表:
| Span Name | Trace A | Trace B | 差异 |
| HTTP GET /api | 50ms | 10ms | +40ms |
| ServiceB/Process | 30ms | 150ms | +120ms ✗ |
| DB Query users | 20ms | 15ms | +5ms |
使用场景:
1. 慢请求 vs 正常请求 → 定位耗时差异点
2. 错误请求 vs 正常请求 → 找出出错的服务
3. 新旧版本对比 → 验证性能优化效果
4. A/B 实验 → 不同路由的性能差异
20 Jaeger 的存储滚动升级和数据迁移方案是什么?
答案:
Jaeger 存储升级涉及 ES/Cassandra 的滚动升级和数据兼容性处理。
Elasticsearch 滚动升级:
# 1. 停止 Span 写入(可选)
kubectl scale deployment jaeger-collector --replicas=0
# 2. 滚动升级 ES 节点
# ES 7.x → 8.x 需注意兼容性
# 3. 重启 Jaeger Query 连接新 ES
kubectl rollout restart deployment jaeger-query
# 4. 恢复 Collector
kubectl scale deployment jaeger-collector --replicas=3
存储迁移(ES → ES):
# 使用 reindex 迁移数据
POST _reindex
{
"source": {"index": "jaeger-span-2026-05-25", "host": "old-es:9200"},
"dest": {"index": "jaeger-span-2026-05-25", "host": "new-es:9200"}
}
存储类型迁移(ES → Cassandra):
新存储配置需要启动新的 Collector 和 Query
旧数据保留在原存储中,可用于历史查询
新 Collector 写入新存储
两个 Query 实例分别连接新旧存储
过渡期后下线旧存储
升级注意事项:
1. ES 版本兼容性
- 建议大版本内升级
- 跨版本需逐步进行
2. 数据格式兼容
- Jaeger 新版本可能修改索引 mapping
- 需验证兼容性
3. 回滚计划
- 保留旧版本配置
- 数据备份
- 迁移路径可逆
21 Jaeger v1 和 v2 版本的核心差异是什么?
答案:
Jaeger v2 是架构层面的重大重构,将 Jaeger 组件整合为基于 OpenTelemetry Collectors 的统一平台。
架构差异:
Jaeger v1:
Agent (UDP) → Collector (队列) → Storage → Query → UI
(多组件,Thrift 协议)
Jaeger v2:
OTel Collector (OTLP) → Storage → OTel Collector (Query) → UI
(统一 Collector,OTLP 协议)
v1 到 v2 的变化:
| 维度 | Jaeger v1 | Jaeger v2 |
|---|---|---|
| 数据协议 | Jaeger Thrift | OpenTelemetry OTLP |
| 核心组件 | Agent + Collector + Query | OTel Collector |
| 采样 | 内置自适应 | OTel Collector 采样 |
| 存储 | ES/Cassandra/Badger | 存储插件 |
| UI | React | React (升级) |
| 部署 | 多二进制 | 统一 Collector |
| Agent | UDP 守护进程 | OTel Collector Agent |
v2 优势:
1. 统一 OTel 生态
- 复用 OTel Collector 的 Receiver/Processor/Exporter
- 与 Metrics/Logs 共享同一 Collector
2. 简化运维
- 更少的组件
- 统一的配置
- 相同的二进制
3. 更强的扩展性
- OTel Collector 插件体系
- 社区贡献的 Processor 可直接使用
4. 更好的兼容性
- OTLP 是所有信号的标准
- 减少协议转换开销
22 Jaeger 的 Hot Rod 示例应用演示了什么功能?
答案:
Hot Rod 是 Jaeger 官方示例应用,演示了分布式 Tracing 在微服务架构中的完整工作流程。
Hot Rod 架构:
Web 前端 (HTML/JS)
│
HTTP
│
Customer Service (Go) ──── HTTP ──── Route Service (Go)
│ │
内部逻辑 gRPC
│ │
MySQL (嵌入式) Redis (地理位置)
演示功能:
| 功能 | 说明 |
|---|---|
| Trace 搜索 | 按服务、操作、标签、时间搜索 |
| Trace 详情 | 甘特图 + Span 标签 + Logs |
| 多服务拓扑 | 4 个服务 + 2 个存储后端 |
| 跨语言 | Go + JavaScript |
| 不同协议 | HTTP + gRPC |
| 错误场景 | 部分请求超时/错误 |
| 采样配置 | 演示不同采样策略效果 |
部署方式:
# 使用 all-in-one 镜像自带 Hot Rod
docker run -d --name jaeger \
-p 16686:16686 \
-p 8080:8080 \
jaegertracing/all-in-one:latest
# 访问 Hot Rod 页面
# http://localhost:8080
# 访问 Jaeger UI
# http://localhost:16686
演示目的:
展示 Jaeger 在生产场景中的实际使用方式
验证 Trace 是否完整覆盖了所有服务调用
了解不同协议(HTTP/gRPC)的 Span 传播
观察采样策略对 Trace 数量的影响
23 Jaeger 的 Resource 和 Span Tags 的最佳实践是什么?
答案:
统一的标签命名和规范化实践有助于 Trace 数据的可搜索性和可分析性。
Resource Tags(标识数据来源):
| Tag | 示例 | 说明 |
|---|---|---|
service.name | user-service | 服务名称 |
service.version | 1.2.3 | 服务版本 |
service.instance.id | pod-abc123 | 实例唯一 ID |
host.name | node-1 | 主机名 |
deployment.environment | production | 部署环境 |
telemetry.sdk.name | opentelemetry | SDK 类型 |
telemetry.sdk.language | go | SDK 语言 |
Span Tags(请求上下文):
| 类别 | Tag | 示例 |
|---|---|---|
| HTTP | http.method, http.url, http.status_code | GET, /api/users, 200 |
| DB | db.type, db.instance, db.statement | sql, users, SELECT... |
| MQ | messaging.system, messaging.destination | kafka, orders |
| RPC | rpc.system, rpc.service, rpc.method | grpc, UserService, GetUser |
| Error | error, error.object | true, exception msg |
操作命名规范:
服务端 HTTP: {HTTP Method} {Route}
✅ "GET /api/users/{id}"
❌ "GET /api/users/123" (含具体 ID)
数据库: {DB Type} {Operation} {Table}
✅ "MySQL SELECT users"
✅ "Redis GET user:123"
消息队列: {Topic} {Operation}
✅ "Kafka orders CONSUME"
✅ "RabbitMQ orders PUBLISH"
标签使用原则:
| 原则 | 说明 | 反例 |
|---|---|---|
| 低基数 | 标签值有限枚举 | user_id 不可作为标签 |
| 可搜索 | 用于过滤查询 | body 内容不作为标签 |
| 标准化 | 遵循语义约定 | 自定义命名需文档化 |
| 适度 | 每个 Span 5-10 个标签 | 过多标签影响性能 |
24 Jaeger 的 gRPC 传播细节和 Deadline 传播是什么?
答案:
Jaeger 通过 gRPC Metadata 传播 Trace 上下文和 Deadline,实现跨服务的超时控制。
gRPC Trace 传播:
客户端 (service A) 服务端 (service B)
│ │
gRPC Call With Metadata │
├── traceparent: 00-abc123-def456-01 │
├── grpc-timeout: 5000ms │
│ │
Extract Metadata │
Create Child Span │
│ │
Handle Request (超时: 5s) │
gRPC Metadata 传播配置:
import (
"google.golang.org/grpc"
"github.com/opentracing-contrib/go-grpc"
)
// 服务端
server := grpc.NewServer(
grpc.UnaryInterceptor(otelgrpc.UnaryServerInterceptor()),
)
// 客户端
conn, _ := grpc.Dial("service-b:8080",
grpc.WithUnaryInterceptor(otelgrpc.UnaryClientInterceptor()),
grpc.WithBlock(),
)
Deadline 传播:
客户端 (Deadline 5s)
│
gRPC Metadata: grpc-timeout=5000m
│
服务端接收
│
如果 deadline 已过期 → 直接返回超时
否则 → 创建上下文
│
子调用继承剩余 deadline
客户端取消 → 传播 Cancel 通知
Deadline 传播的优势:
避免级联等待:
服务A (5s) → 服务B (继承 4.5s) → 服务C (继承 4s)
↓
如果 C 超过 4s → 取消
通知 B → 通知 A → 快速失败
25 Jaeger 的 Span 审计日志和异常追踪配置是什么?
答案:
Jaeger Span 的 Logs 字段用于记录审计事件和异常信息,实现错误根因定位。
异常记录方式:
import "github.com/opentracing/opentracing-go/log"
// 记录异常事件
span.LogFields(
log.String("event", "error"),
log.String("type", "DatabaseError"),
log.String("message", err.Error()),
log.String("stack", string(debug.Stack())),
)
// 记录关键审计事件
span.LogFields(
log.String("event", "audit"),
log.String("action", "user.login"),
log.String("user_id", userID),
log.String("ip", clientIP),
log.String("result", "success"),
)
Span Tags 标记错误:
import "github.com/opentracing/ext"
// 标记 Span 为错误
ext.Error.Set(span, true)
span.SetTag("error.message", err.Error())
span.SetTag("error.type", "business_error")
异常追踪最佳实践:
记录异常:
✓ 记录 event=error + message + stack
✓ 标记 Span 为 error=true
✓ 记录异常的因果关系
不记录:
✗ 重复日志(SDK 已有)
✗ 敏感信息(密码、Token)
✗ 巨量错误信息(截断处理)
26 Jaeger 的数据安全配置(TLS、认证、审计)是什么?
答案:
Jaeger 支持 TLS 加密、基本认证和审计日志等安全功能。
TLS 配置:
# Collector gRPC TLS
collector:
grpc:
hostPort: ":14250"
tls:
enabled: true
cert: "/certs/collector.crt"
key: "/certs/collector.key"
clientCa: "/certs/ca.crt" # 客户端认证(mTLS)
# HTTP TLS
http:
tls:
enabled: true
cert: "/certs/collector.crt"
key: "/certs/collector.key"
Agent 侧 TLS:
reporter:
collectorEndpoint: "https://jaeger-collector:14268/api/traces"
tls:
enabled: true
cert: "/certs/agent.crt"
key: "/certs/agent.key"
serverName: "jaeger-collector"
基本认证:
# Collector HTTP
collector:
http:
# 基本认证
basicAuth:
enabled: true
username: "jaeger"
password: "password"
# Query HTTP
query:
http:
basicAuth:
enabled: true
username: "admin"
password: "admin"
ES 存储认证:
storage:
elasticsearch:
username: "elastic"
password: "${ES_PASSWORD}"
# TLS
tls:
enabled: true
ca: "/certs/es-ca.crt"
skipHostVerify: false
27 Jaeger 的组件监控指标和健康检查机制是什么?
答案:
Jaeger 各组件通过 Prometheus 格式指标和 HTTP 健康检查端点暴露运行状态。
健康检查端点:
| 组件 | 端点 | 说明 |
|---|---|---|
| Collector | / | 存活检查 |
| Query | / | 存活检查 |
| Query | /api/services | 就绪检查(服务列表) |
| Agent | N/A | 无健康检查 |
K8s 探针配置:
containers:
- name: jaeger-collector
livenessProbe:
httpGet:
path: /
port: 14269
initialDelaySeconds: 10
periodSeconds: 10
readinessProbe:
httpGet:
path: /
port: 14269
initialDelaySeconds: 5
periodSeconds: 5
Prometheus 指标:
| 层级 | 指标 | 含义 |
|---|---|---|
| Collector | jaeger_collector_spans_received_total | Span 接收数 |
jaeger_collector_spans_saved_total | Span 存储数 | |
jaeger_collector_queue_length | 队列长度 | |
jaeger_collector_in_queue_latency_seconds | 队列延迟 | |
| Query | jaeger_query_requests_total | 查询请求数 |
jaeger_query_latency_seconds_bucket | 查询延迟分布 | |
| Agent | jaeger_agent_thrift_udp_buffer_size | UDP 缓冲大小 |
| Ingester | jaeger_ingester_items_processed_total | 处理数 |
Grafana Dashboard 面板:
Collector 面板:
- Span 接收/存储速率 (rate)
- 队列积压 (gauge)
- 队列延迟 (histogram)
Query 面板:
- QPS (rate)
- P99 查询延迟 (histogram_quantile)
- 服务/操作用户分布
Ingester 面板:
- Kafka 消费速率 (rate)
- 处理延迟 (histogram)
- Offset Lag (gauge)
28 Jaeger 的 Agent UDP 数据丢失原因和解决方法是什么?
答案:
Jaeger Agent 通过 UDP 接收 Span,UDP 的无连接特性可能导致数据丢失。
数据丢失原因:
| 原因 | 说明 | 标识 |
|---|---|---|
| UDP 缓冲区满 | socket receive buffer 溢出 | jaeger_agent_thrift_udp_buffer_size |
| Agent 处理慢 | Agent 批量发送速度 < 接收速度 | 队列积压 |
| 网络丢包 | UDP 无重传 | 网络层统计 |
| Agent 重启 | 内存中未发送数据 | 进程重启 |
| 客户端队列满 | SDK 内部队列溢出 | 客户端丢弃 |
监控数据丢失:
// Agent Metrics
{
"jaeger_agent_thrift_udp_buffer_size": 32768,
"jaeger_agent_thrift_udp_read_packets": 100000,
"jaeger_agent_thrift_udp_read_failed": 50, // 读取失败
"jaeger_agent_thrift_processors_batch_size": 1000
}
// Collector Metrics
{
"jaeger_collector_spans_received_total": 100000,
"jaeger_collector_spans_saved_total": 99000, // 高于 1% 差距
}
解决方法:
1. 增大 UDP 接收缓冲区
sysctl -w net.core.rmem_max=26214400
sysctl -w net.core.rmem_default=26214400
2. 使用 gRPC 替代 UDP(推荐)
直连 Collector,可靠传输
3. 增加 Agent 批量处理能力
reporter.batchSize: 10000
reporter.batchWorkers: 100
4. 使用 Kafka 缓冲层
Agent → Collector → Kafka → Ingester
UDP vs gRPC 选择:
Agent UDP (传统):
优势:极低延迟,零资源消耗
劣势:不可靠,数据丢失
适用:低吞吐量,可容忍丢失
gRPC 直连 (推荐):
优势:可靠传输,批量高效
劣势:TCP 连接开销
适用:生产环境
29 Jaeger 的 Span 结构优化方法是什么?
答案:
优化 Span 结构可降低存储成本、提升处理性能和查询速度。
Span 大小控制:
| 优化手段 | 效果 | 做法 |
|---|---|---|
| Tags 最小化 | 30-50% | 只保留可查询的必要标签 |
| Logs 截断 | 10-20% | 限制 Logs 数量和大小 |
| 命名简化 | 5-10% | 短操作名、避免重复前缀 |
| Tag 值截断 | 10-30% | 限制字符串标签长度 |
| 批量发送 | 网络优化 | 增大 BatchSize |
Tags 优化示例:
// ❌ 过多标签
span.SetTag("http.method", "GET")
span.SetTag("http.url", "http://api.example.com/api/users?page=1&limit=10")
span.SetTag("http.host", "api.example.com")
span.SetTag("http.path", "/api/users")
span.SetTag("http.query", "page=1&limit=10")
span.SetTag("http.scheme", "https")
span.SetTag("http.target", "/api/users")
span.SetTag("http.flavor", "1.1")
span.SetTag("http.user_agent", "Mozilla/5.0...")
span.SetTag("http.content_length", "1234")
// ✅ 最小必要标签
span.SetTag("http.method", "GET")
span.SetTag("http.url", "/api/users")
span.SetTag("http.status_code", 200)
Span 数量控制:
// 减少非必要 Span
// 内联简单方法调用(不创建 Span)
func processRequest() {
// 不在此处创建 Internal Span
validate()
process()
save()
}
// 只在关键边界创建 Span
func handleRequest() { // Entry Span
result := callServiceB() // Exit Span
return result
}
30 Jaeger 与 Zipkin 的核心区别是什么?
答案:
Jaeger 和 Zipkin 都是开源分布式 Tracing 系统,在架构设计和功能定位上存在差异。
综合对比:
| 维度 | Jaeger | Zipkin |
|---|---|---|
| 社区归属 | CNCF (毕业) | OpenZipkin (社区) |
| 创始 | Uber | |
| 语言 | Go | Java (Scala) |
| 数据模型 | OpenTracing → OTel | Zipkin 原生 → OTel |
| 协议 | Thrift/gRPC/OTLP | Thrift/HTTP/Kafka |
| SDK | Jaeger SDK / OTel | Brave / OTel |
| 采样 | 自适应采样 | 概率/速率采样 |
| UI | 功能丰富 | 基础 |
| 依赖图 | Spark / 实时 | Spark |
| 存储 | ES / Cassandra / Badger | ES / Cassandra / MySQL |
| 告警 | 无(需集成) | 无(需集成) |
Jaeger 特有功能:
1. 自适应采样
- 动态调整采样率
- 低流量端点高采样
2. 远程采样策略
- 中央下发采样配置
- 实时调整
3. Trace 对比
- 并列甘特图
- 差异分析
4. Hot Rod 演示
- 完整示例应用
- 教学演示
Zipkin 特有功能:
1. Brave 客户端完善
- Java/Spring 生态成熟
- Sleuth → Spring Cloud 集成
2. MySQL 存储支持
- 小团队场景
- 无需额外存储组件
3. 轻量级架构
- 组件少
- 易于上手
选型建议:
| 场景 | 推荐 | 原因 |
|---|---|---|
| Go 微服务 | Jaeger | Go 实现、兼容性好 |
| Java / Spring | Zipkin (Brave) | Spring Cloud Sleuth 原生 |
| 需要自适应采样 | Jaeger | 核心优势 |
| 轻量需求 | Zipkin | 架构简单 |
| CNCF 标准化 | Jaeger | CNCF 毕业项目 |
| 已有 OTel | 二者均可 | 通过 OTel 统一输出 |