OpenTelemetry 面试题
35 道题- 分类
- 可观测性
- 子分类
- trace
- 题目数
- 35 道
1 OpenTelemetry(OTel)的核心架构由哪些组件构成?
答案:
OpenTelemetry 是 CNCF 的 observability 框架标准,提供统一的 API、SDK 和工具用于生成、采集和导出遥测数据。
核心组件:
| 组件 | 职责 | 说明 |
|---|---|---|
| API | 接口定义 | Traces/Metrics/Logs/Baggage 的抽象接口 |
| SDK | 默认实现 | 采样、处理、导出管道的默认行为 |
| OTLP | 传输协议 | gRPC/HTTP 的跨语言数据交换格式 |
| Collector | 数据网关 | 接收、处理、转发遥测数据 |
| Instrumentation | 自动埋点 | 各语言/框架的自动检测库 |
| Exporter | 数据导出 | 发送到后端(Jaeger/Prometheus/OTLP) |
| Resource | 资源标识 | 服务/主机/容器的元数据标识 |
数据流:
Application → Instrumentation → API → SDK → Exporter → Backend
↓
OTel Collector
↓
Jaeger/Prometheus/OTLP
2 OpenTelemetry 的三种信号(Signal)是什么?它们之间的关系是什么?
答案:
OpenTelemetry 定义 Traces、Metrics 和 Logs 三种可观测性信号,通过 Context Propagation 实现关联。
三种信号:
| 信号 | 描述 | 示例 | 数据模型 |
|---|---|---|---|
| Traces | 请求路径记录 | Span 链:前端→API→DB | Span + SpanContext |
| Metrics | 聚合度量指标 | 请求数、延迟 P99 | Instrument + DataPoint |
| Logs | 离散事件记录 | 错误日志、审计事件 | LogRecord |
信号关联机制:
Trace Context (trace_id/span_id)
↓
关联 Metrics: Exemplar
↓ 携带 trace_id → 关联到具体请求
关联 Logs: span_id → 日志上下文注入
↓
统一查询:"查看该请求的 Trace、Metrics 和 Logs"
Context Propagation:
服务A → HTTP Header (traceparent) → 服务B
│ │
trace_id: abc trace_id: abc
span_id: 123 parent_span_id: 123
span_id: 456
3 OpenTelemetry 的 Trace 数据模型中 Span、SpanContext 和 Trace 的关系是什么?
答案:
Trace 由一个或多个 Span 组成,Span 通过 SpanContext 建立父子关系形成调用链。
数据模型层次:
Trace (跟踪)
├── Span (SpanContext: trace_id=abc, span_id=123)
│ ├── Span (SpanContext: trace_id=abc, span_id=456, parent=123)
│ │ └── Span (SpanContext: trace_id=abc, span_id=789, parent=456)
│ └── Span (SpanContext: trace_id=abc, span_id=aaa, parent=123)
└── Span (SpanContext: trace_id=abc, span_id=bbb)
Span 属性:
| 属性 | 说明 | 示例 |
|---|---|---|
| trace_id | Trace 全局唯一 ID | 16 字节 hex |
| span_id | Span 唯一 ID | 8 字节 hex |
| parent_span_id | 父 Span ID | 空表示 Root Span |
| name | Span 名称 | “HTTP GET /api/users” |
| kind | Span 类型 | Client/Server/Internal/Producer/Consumer |
| start_time | 开始时间 | Unix 纳秒 |
| end_time | 结束时间 | Unix 纳秒 |
| status | 状态码 | Unset/Ok/Error |
| attributes | 键值对属性 | http.method: GET |
| events | 时间戳事件 | "exception" + stack trace |
| links | 关联其他 Trace | 跨 Trace 关联 |
W3C TraceContext 标准:
Traceparent Header: 版本-trace_id-span_id-trace_flags
示例:00-0af7651916cd43dd8448eb211c80319c-b7ad6b7169203331-01
4 OpenTelemetry Collector 的架构和组件是什么?
答案:
OTel Collector 是一个与厂商无关的数据接收、处理和导出网关,支持 Traces/Metrics/Logs。
Collector 架构:
Receivers → Processors → Exporters
│ │ │
OTLP/ Batch/Sam OTLP/
Jaeger/ ple/Attr Prometheus/
Prometheus 修改 Jaeger/
Splunk/
自定义后端
核心组件:
| 组件 | 功能 | 内置实现 |
|---|---|---|
| Receiver | 数据接收 | otlp/jaeger/prometheus/zipkin/kafka |
| Processor | 数据处理 | batch/memory_limiter/attributes/span/filter/sample |
| Exporter | 数据导出 | otlp/prometheus/jaeger/logging/debug |
| Connector | 信号转换 | span_metrics/traces_metrics |
| Extension | 扩展功能 | health_check/pprof/ballast |
配置示例:
receivers:
otlp:
protocols:
grpc:
endpoint: 0.0.0.0:4317
http:
endpoint: 0.0.0.0:4318
processors:
batch:
timeout: 1s
send_batch_size: 1024
memory_limiter:
check_interval: 1s
limit_mib: 512
exporters:
otlp:
endpoint: jaeger:4317
tls:
insecure: true
prometheus:
endpoint: 0.0.0.0:8889
service:
pipelines:
traces:
receivers: [otlp]
processors: [memory_limiter, batch]
exporters: [otlp]
metrics:
receivers: [otlp]
processors: [batch]
exporters: [prometheus]
部署模式:
| 模式 | 说明 | 场景 |
|---|---|---|
| Agent | 应用同机部署 | 资源受限边缘 |
| Gateway | 独立集群 | 中央处理/路由 |
| Agent + Gateway | 分层 | K8s DaemonSet + 聚合层 |
5 OTel Collector 的 Agent 模式和 Gateway 模式有什么区别?如何选择?
答案:
Agent 模式将 Collector 部署在应用侧(sidecar/DaemonSet),Gateway 模式部署为独立集群。
部署模式对比:
| 维度 | Agent 模式 | Gateway 模式 |
|---|---|---|
| 部署位置 | 应用同节点 | 独立集群 |
| 数据流 | App → Agent → Backend | App → Agent → Gateway → Backend |
| 资源消耗 | 分散在各节点 | 集群集中 |
| 处理能力 | 有限(节点资源约束) | 强 |
| 配置管理 | 分散配置 | 集中管理 |
| 故障影响 | 影响单节点 | 影响全局(需 HA) |
| 延迟 | 低 | 中(增加一跳) |
K8s 场景 Agent 模式:
# DaemonSet + Sidecar 模式
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: otel-agent
spec:
selector:
matchLabels:
app: otel-agent
template:
metadata:
labels:
app: otel-agent
spec:
containers:
- name: otel-agent
image: otel/opentelemetry-collector-contrib:latest
args:
- --config=/etc/otel/config.yaml
ports:
- containerPort: 4317 # OTLP gRPC
- containerPort: 4318 # OTLP HTTP
resources:
limits:
memory: 256Mi
cpu: 500m
选择建议:
| 场景 | 推荐模式 | 原因 |
|---|---|---|
| K8s 小集群 | Agent 直出 | 简化架构 |
| 大规模 K8s | Agent + Gateway | 卸载处理压力 |
| 多后端路由 | Gateway | 中央路由策略 |
| 批处理/采样 | Gateway 集中 | 统一控制 |
| 边缘/资源受限 | Agent 轻量 | 最小化资源 |
6 OpenTelemetry 的采样策略有哪些?Head Sampling 和 Tail Sampling 的区别?
答案:
采样用于控制 Trace 数据量,减少存储成本的同时保留关键请求的完整链路。
采样策略对比:
| 维度 | Head Sampling | Tail Sampling |
|---|---|---|
| 决策时机 | Span 创建时 | 完整 Trace 接收后 |
| 决策依据 | 本地信息 | 全局信息 |
| 支持策略 | 概率/速率 | 基于错误/延迟/标签 |
| 实现位置 | SDK | Collector |
| 完整性 | 可能丢失部分 Span | 保证完整 Trace |
Head Sampling(SDK 侧):
// Go SDK ParentBased 采样:保留完整父子链
exporter, _ := otlptracegrpc.New(ctx)
tp := sdktrace.NewTracerProvider(
sdktrace.WithSampler(
sdktrace.ParentBased(sdktrace.TraceIDRatioBased(0.1)),
),
sdktrace.WithBatcher(exporter),
)
Tail Sampling(Collector 侧):
processors:
tail_sampling:
decision_wait: 30s
num_traces: 100000
expected_new_traces_per_sec: 1000
policies:
# 保留所有错误请求
- name: errors-policy
type: status_code
status_code:
status_codes:
- ERROR
# 保留高延迟请求
- name: slow-policy
type: latency
latency:
threshold_ms: 5000
# 按概率采样
- name: probabilistic-policy
type: probabilistic
probabilistic:
sampling_percentage: 10
exporters:
otlp:
endpoint: jaeger:4317
采样策略选择:
| 策略 | 场景 | 存储节省 | 信息完整性 |
|---|---|---|---|
| 概率采样(10%) | 高吞吐量 | 90% | 随机 |
| 错误采样(100%) | 故障排查 | 0%(错误) | 完整 |
| 延迟采样(P99+) | 性能优化 | 99% | p50+p99 |
| 标签采样 | 特定业务 | 自定义 | 按条件 |
| 速率限制 | 突发控制 | 动态 | 有限 |
7 OTel SDK 中 SpanProcessor 和 Exporter 的区别和工作流程是什么?
答案:
SpanProcessor 是 SDK 内部的 Span 处理链,Exporter 是数据导出组件,两者构成 Span 的生命周期管理。
组件关系:
SDK TracerProvider
↓
SpanProcessor Chain
├── BatchSpanProcessor
│ ├── Buffer → Export → Exporter → Backend
│ └── 定时批量发送
└── SimpleSpanProcessor
└── Span → 立即 Exporter → Backend
Span 生命周期:
Start → [Processor.OnStart] → End → [Processor.OnEnd] → Queue → Export
SpanProcessor 类型:
| Processor | 行为 | 场景 |
|---|---|---|
| Simple | Span 结束时立即导出 | 测试/调试 |
| Batch | 缓冲后批量导出 | 生产环境 |
BatchSpanProcessor 配置:
bsp := sdktrace.NewBatchSpanProcessor(
exporter,
sdktrace.WithBatchTimeout(5*time.Second), // 5s 批量一次
sdktrace.WithMaxExportBatchSize(512), // 每批最大 512 Span
sdktrace.WithMaxQueueSize(2048), // 最大队列 2048
sdktrace.WithExportTimeout(30*time.Second), // 导出超时 30s
)
自定义 SpanProcessor:
type MetricSpanProcessor struct {
next sdktrace.SpanProcessor
}
func (p *MetricSpanProcessor) OnStart(parent context.Context, s sdktrace.ReadWriteSpan) {
// Span 开始时处理
p.next.OnStart(parent, s)
}
func (p *MetricSpanProcessor) OnEnd(s sdktrace.ReadOnlySpan) {
// Span 结束时处理(转换为 Metrics)
duration := s.EndTime().Sub(s.StartTime())
requestDuration.WithLabelValues(
s.Attributes()["http.method"],
s.Attributes()["http.status_code"],
).Observe(duration.Seconds())
p.next.OnEnd(s)
}
func (p *MetricSpanProcessor) Shutdown(ctx context.Context) error {
return p.next.Shutdown(ctx)
}
8 OpenTelemetry 的 Context Propagation 机制是如何工作的?
答案:
Context Propagation 是 OTel 实现跨服务 Trace 串联的核心机制,通过在进程间传递 SpanContext 建立调用链。
传播流程:
服务A 服务B
│ │
│── HTTP Request ──────────→│
│ Headers: │
│ traceparent: 00-abc-123 │ Extractor
│ tracestate: vendor=val │ ↓
│ │ SpanContext
│ 创建 Span │ │
│ trace_id: abc │ 新建 Span
│ span_id: 123 │ trace_id: abc
│ │ parent: 123
│ │ span_id: 456
│ │
│←────────── Response ─────│
W3C TraceContext 标准:
| Header | 格式 | 示例 |
|---|---|---|
traceparent | 版本-trace_id-span_id-flags | 00-0af7651916cd43dd8448eb211c80319c-b7ad6b7169203331-01 |
tracestate | vendor=value | dd=t.sample:1 |
Propagator 实现:
// Go SDK Propagation
import (
"go.opentelemetry.io/otel/propagation"
)
// 组合多个 Propagator
tp := propagation.NewCompositeTextMapPropagator(
propagation.TraceContext{}, // W3C TraceContext
propagation.Baggage{}, // W3C Baggage
)
// 注入到出口请求
func inject(ctx context.Context, req *http.Request) {
tp.Inject(ctx, propagation.HeaderCarrier(req.Header))
}
// 从入口请求提取
func extract(ctx context.Context, req *http.Request) context.Context {
return tp.Extract(ctx, propagation.HeaderCarrier(req.Header))
}
支持的传播协议:
| 协议 | 说明 | OTel 优先级 |
|---|---|---|
| W3C TraceContext | 事实标准 | 最高 |
| B3 | Zipkin 格式 | 兼容 |
| Jaeger | Jaeger 原生格式 | 兼容 |
| AWS X-Ray | AWS 格式 | 兼容 |
9 OpenTelemetry 如何集成 Prometheus?
答案:
OTel 通过 Collector Prometheus Exporter 和 SDK Prometheus Exporter 两种方式集成 Prometheus。
方式一:Collector Prometheus Exporter
# collector 配置
receivers:
otlp:
protocols:
grpc:
endpoint: 0.0.0.0:4317
processors:
batch:
timeout: 1s
send_batch_size: 1000
exporters:
prometheus:
endpoint: 0.0.0.0:8889
namespace: otel
const_labels:
env: production
resource_to_telemetry_conversion:
enabled: true
service:
pipelines:
metrics:
receivers: [otlp]
processors: [batch]
exporters: [prometheus]
方式二:Go SDK Prometheus Exporter
import (
"go.opentelemetry.io/otel/exporters/prometheus"
"go.opentelemetry.io/otel/sdk/metric"
)
func initMetrics() {
exporter, err := prometheus.New()
provider := metric.NewMeterProvider(
metric.WithReader(exporter),
)
otel.SetMeterProvider(provider)
}
Prometheus Scrape:
# prometheus.yml
scrape_configs:
- job_name: otel-collector
scrape_interval: 15s
static_configs:
- targets:
- otel-collector:8889
- job_name: otel-sdk-app
scrape_interval: 15s
static_configs:
- targets:
- app:9464
10 OpenTelemetry 的资源(Resource)和属性(Attribute)的规范是什么?
答案:
Resource 描述产生数据的实体(服务/主机/容器),Attribute 是 Span/Metric/Log 的键值对元数据。
Resource 语义约定:
| 属性 | 示例 | 说明 |
|---|---|---|
service.name | user-service | 服务名称 |
service.namespace | production | 服务命名空间 |
service.version | 1.2.3 | 服务版本 |
service.instance.id | pod-abc123 | 实例唯一 ID |
host.name | node-1 | 主机名 |
host.type | c5.xlarge | 实例类型 |
cloud.provider | aws | 云厂商 |
cloud.region | ap-southeast-1 | 区域 |
deployment.environment | production | 部署环境 |
Attribute 语义约定(Span Attributes):
// HTTP 请求
span.SetAttributes(
attribute.String("http.method", "GET"),
attribute.String("http.url", "/api/users"),
attribute.Int("http.status_code", 200),
attribute.Int("http.request_content_length", 1024),
)
// 数据库查询
span.SetAttributes(
attribute.String("db.system", "postgresql"),
attribute.String("db.name", "users"),
attribute.String("db.statement", "SELECT * FROM users"),
)
// 消息队列
span.SetAttributes(
attribute.String("messaging.system", "kafka"),
attribute.String("messaging.destination", "orders"),
attribute.String("messaging.operation", "process"),
)
Resource 设置:
import "go.opentelemetry.io/otel/sdk/resource"
res, _ := resource.New(ctx,
resource.WithAttributes(
semconv.ServiceNameKey.String("user-service"),
semconv.DeploymentEnvironmentKey.String("production"),
),
resource.WithTelemetrySDK(),
resource.WithHost(),
resource.WithContainer(),
resource.WithProcess(),
)
11 OpenTelemetry 的自动埋点(Auto-Instrumentation)是如何工作的?
答案:
OTel 自动埋点通过拦截框架的关键方法(HTTP、gRPC、DB),自动创建 Span 并注入 Context Propagation。
工作原理:
应用入口
│
Detected Framework (e.g., net/http, Gin, Express)
│
Instrumentation 拦截关键方法
│
API → SDK → Span 创建/结束/注入 Context
│
自动注入 traceparent header
│
导出到 Collector/Backend
Go 自动埋点:
// 导入自动埋点包
import (
"go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
)
// 自动包装 HTTP Handler
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// 自动创建 Span
// 自动注入 Context Propagation
handleRequest(w, r)
})
wrapped := otelhttp.NewHandler(handler, "api.router")
http.Handle("/api/", wrapped)
Java 自动埋点(通过 Java Agent):
# JVM 参数方式
java -javaagent:opentelemetry-javaagent.jar \
-Dotel.service.name=user-service \
-Dotel.traces.exporter=otlp \
-Dotel.metrics.exporter=otlp \
-Dotel.exporter.otlp.endpoint=http://otel-collector:4317 \
-jar app.jar
支持的框架自动埋点:
| 语言 | 支持框架 |
|---|---|
| Java | Spring Boot, Tomcat, gRPC, Kafka, JDBC, Redis |
| Python | Django, Flask, FastAPI, Requests, SQLAlchemy |
| Go | net/http, Gin, gRPC, database/sql |
| Node.js | Express, Fastify, MongoDB, Redis, gRPC |
| .NET | ASP.NET Core, HttpClient, Entity Framework |
| Ruby | Rails, Sinatra, Rack, Sidekiq |
12 OTel 如何实现 Metrics 的采集?Counter、Gauge、Histogram 的区别?
答案:
OTel Metrics API 定义多种 Instrument 类型,用于不同场景的度量指标采集。
Instrument 类型:
| 类型 | 行为 | 场景 | 示例 |
|---|---|---|---|
| Counter | 单调递增 | 请求计数、错误计数 | api_requests_total |
| UpDownCounter | 可增减 | 队列长度、活跃连接 | active_connections |
| Histogram | 值分布 | 延迟 P50/P95/P99 | request_duration_seconds |
| Gauge | 任意值 | CPU 温度、内存使用 | memory_usage_bytes |
| Asynchronous Counter | 回调方式 | 由外部系统递增 | process_cpu_seconds_total |
代码示例:
import (
"go.opentelemetry.io/otel/metric"
"go.opentelemetry.io/otel/attribute"
)
meter := meterProvider.Meter("api-server")
// Counter:单调递增
requestCounter, _ := meter.Int64Counter(
"api.requests.total",
metric.WithDescription("Total API requests"),
)
// Histogram:值分布
latencyHistogram, _ := meter.Float64Histogram(
"api.request.duration",
metric.WithDescription("Request latency"),
metric.WithUnit("ms"),
)
// UpDownCounter:可增减
activeConnections, _ := meter.Int64UpDownCounter(
"api.active_connections",
metric.WithDescription("Active connections"),
)
// 使用
requestCounter.Add(ctx, 1, attribute.String("method", "GET"))
latencyHistogram.Record(ctx, 150.0, attribute.String("status", "200"))
activeConnections.Add(ctx, 1)
activeConnections.Add(ctx, -1)
13 OpenTelemetry 的 Baggage API 的作用是什么?与 Context Propagation 的关系?
答案:
Baggage 是 W3C Baggage 标准实现的跨服务 Context 数据传递机制,用于在 Trace 链中传递业务上下文。
Baggage 机制:
服务A 服务B 服务C
│ │ │
│── baggage: →│ │
│ user_id=123, │── baggage: →│
│ session_id=abc │ user_id=123, │
│ │ session_id=abc │
│ │ │
│ │ 读取 Baggage │
│ │ → 注入 Span │
│ │ Attributes │
│ │ → 影响采样决策 │
使用场景:
| 场景 | Baggage 内容 | 用途 |
|---|---|---|
| A/B 测试 | experiment_id=blue | 各服务统一实验分组 |
| 用户上下文 | user_id=123, tier=premium | 服务间传递用户等级 |
| 请求链路 | request_id=req-456 | 日志关联 Trace |
| 优先级 | priority=high | 影响采样/限流策略 |
代码示例:
import (
"go.opentelemetry.io/otel/baggage"
"go.opentelemetry.io/otel/attribute"
)
// 设置 Baggage
member1, _ := baggage.NewMember("user_id", "123")
member2, _ := baggage.NewMember("experiment", "blue-v2")
bag, _ := baggage.New(member1, member2)
ctx = baggage.ContextWithBaggage(ctx, bag)
// 注入到 Span Attributes
span := trace.SpanFromContext(ctx)
for _, m := range baggage.FromContext(ctx).Members() {
span.SetAttributes(attribute.String("baggage."+m.Key(), m.Value()))
}
// 在接收端提取
bag := baggage.FromContext(ctx)
userID := bag.Member("user_id").Value()
W3C Baggage Header:
baggage: user_id=123,experiment=blue-v2,priority=high
与 Trace 的关系:
TraceContext: 跟踪谁调用了谁(调用拓扑)
Baggage: 调用链中传递的业务数据(用户/实验/优先级)
TraceContext 是基础设施
Baggage 是业务数据通道
14 OTel Collector 的 Batch Processor 和 Memory Limiter Processor 的作用是什么?
答案:
Batch Processor 提高数据批量导出效率,Memory Limiter Processor 防止 Collector OOM。
Batch Processor:
processors:
batch:
# 批量超时时间
timeout: 1s
# 每批最大 Span/Metric/Log 数
send_batch_size: 8192
# 队列最大容量
send_batch_max_size: 10000
batch/compressed:
timeout: 5s
send_batch_size: 512
# 压缩
metadata_keys:
- "compression"
Memory Limiter Processor:
processors:
memory_limiter:
check_interval: 1s
# 硬限制:超过时拒绝数据
limit_mib: 512
# 软限制:超过时开始降级
spike_limit_mib: 100
# 或使用百分比
# limit_percentage: 70
# spike_limit_percentage: 15
组合使用:
receivers:
otlp:
protocols:
grpc:
endpoint: 0.0.0.0:4317
processors:
memory_limiter:
check_interval: 1s
limit_mib: 512
spike_limit_mib: 100
batch:
timeout: 1s
send_batch_size: 8192
exporters:
otlp:
endpoint: jaeger:4317
service:
pipelines:
traces:
receivers: [otlp]
processors: [memory_limiter, batch]
exporters: [otlp]
Memory Limiter 降级行为:
正常状态:
Memory < limit_mib → 正常处理
降级状态:
Memory > limit_mib - spike_limit_mib
→ 拒绝新数据(返回 ResourceExhausted)
→ 等待 check_interval 后重新检查
恢复:
Memory 下降至安全水位
→ 恢复正常处理
15 OpenTelemetry 的 Logs Bridge API 和 Logs SDK 的区别是什么?
答案:
Logs Bridge API 用于将现有日志框架(log4j/zap/slog)接入 OTel,Logs SDK 处理日志的批量导出和关联。
架构层次:
```mermaid
graph TD
A["日志应用程序代码"] --> B["现有日志框架<br/>log4j/zap/slog"]
B --> C["OTel Logs Bridge API<br/>(从现有框架桥接到 OTel)"]
C --> D["OTel Logs SDK<br/>(聚合、采样、关联、导出)"]
D --> E["Exporter"]
E --> F["OTLP"]
F --> G["Collector"]
G --> H["后端"]
**关键概念:**
| 概念 | 说明 |
|------|------|
| **LogRecord** | 日志记录的数据模型 |
| **LogRecordProcessor** | 日志处理链(类比 SpanProcessor) |
| **LoggerProvider** | Logger 工厂 |
| **Logger** | 日志记录器 |
| **Bridge API** | 桥接外部日志库 |
**Go 集成示例:**
```go
import (
"go.opentelemetry.io/otel/log"
"go.opentelemetry.io/otel/sdk/log"
"go.opentelemetry.io/otel/exporters/otlp/otlplog"
)
// 创建 Logger Provider
exporter, _ := otlplog.New(ctx)
processor := log.NewBatchProcessor(exporter)
provider := log.NewLoggerProvider(
log.WithProcessor(processor),
log.WithResource(res),
)
// 关联 Trace Context
ctx := context.WithValue(context.Background(), "trace_id", span.SpanContext().TraceID().String())
logger := provider.Logger("app-logger")
logger.Emit(log.Record{
Timestamp: time.Now(),
Severity: log.SeverityError,
Body: log.StringValue("Database connection failed"),
TraceID: span.SpanContext().TraceID(),
SpanID: span.SpanContext().SpanID(),
})
自动 Trace 关联:
// 日志自动注入 trace_id/span_id
// 通过 Context Propagation 实现
func logWithTrace(logger log.Logger, ctx context.Context, msg string) {
span := trace.SpanFromContext(ctx)
sc := span.SpanContext()
logger.Emit(log.Record{
Body: log.StringValue(msg),
TraceID: sc.TraceID(),
SpanID: sc.SpanID(),
})
}
16 OpenTelemetry 的 Exporter 有哪些常用类型?如何配置 OTLP Exporter?
答案:
OTel Exporter 负责将遥测数据发送到后端系统,支持多种数据格式和传输协议。
常用 Exporter 类型:
| Exporter | 后端 | 协议 | 适用信号 |
|---|---|---|---|
| OTLP | OTel Collector 或兼容后端 | gRPC / HTTP | Traces + Metrics + Logs |
| Jaeger | Jaeger | gRPC / HTTP | Traces |
| Prometheus | Prometheus | HTTP Pull | Metrics |
| Logging | 控制台输出 | stdout | 调试 |
| ZPages | 内部服务 | HTTP | 调试 |
OTLP Exporter 配置:
// Go SDK OTLP Exporter
import (
"go.opentelemetry.io/otel/exporters/otlp/otlptrace"
"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc"
"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp"
)
// gRPC 方式
exporter, _ := otlptracegrpc.New(ctx,
otlptracegrpc.WithEndpoint("otel-collector:4317"),
otlptracegrpc.WithInsecure(),
otlptracegrpc.WithTimeout(10*time.Second),
)
// HTTP 方式
exporter, _ := otlptracehttp.New(ctx,
otlptracehttp.WithEndpoint("otel-collector:4318"),
otlptracehttp.WithInsecure(),
otlptracehttp.WithTimeout(10*time.Second),
otlptracehttp.WithCompression(otlptracehttp.GzipCompression),
)
Collector 侧 OTLP Receiver:
receivers:
otlp:
protocols:
grpc:
endpoint: 0.0.0.0:4317
max_recv_msg_size_mib: 10
http:
endpoint: 0.0.0.0:4318
cors:
allowed_origins:
- http://localhost:3000
exporters:
otlp:
endpoint: jaeger:4317
tls:
insecure: true
service:
pipelines:
traces:
receivers: [otlp]
processors: [batch]
exporters: [otlp, logging]
环境变量配置:
export OTEL_EXPORTER_OTLP_ENDPOINT=http://otel-collector:4318
export OTEL_EXPORTER_OTLP_PROTOCOL=grpc
export OTEL_EXPORTER_OTLP_TIMEOUT=10s
export OTEL_EXPORTER_OTLP_HEADERS="api-key=abc123"
export OTEL_EXPORTER_OTLP_COMPRESSION=gzip
export OTEL_TRACES_EXPORTER=otlp
export OTEL_METRICS_EXPORTER=otlp
export OTEL_LOGS_EXPORTER=otlp
17 OpenTelemetry 的 SDK 配置中 TracerProvider 和 MeterProvider 的关系是什么?
答案:
TracerProvider 和 MeterProvider 分别是 Trace 和 Metrics 的入口工厂,共享 Resource 和 Exporter 配置。
架构关系:
OTel SDK
├── TracerProvider
│ └── Tracer → Span
├── MeterProvider
│ └── Meter → Instrument
└── LoggerProvider
└── Logger → LogRecord
所有 Provider 共享 Resource 标识
配置示例:
import (
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/sdk/resource"
sdktrace "go.opentelemetry.io/otel/sdk/trace"
sdkmetric "go.opentelemetry.io/otel/sdk/metric"
"go.opentelemetry.io/otel/exporters/otlp/otlptrace"
"go.opentelemetry.io/otel/exporters/otlp/otlpmetric"
)
// 公共 Resource
res := resource.NewWithAttributes(
semconv.ServiceName("user-service"),
semconv.DeploymentEnvironment("production"),
)
// TracerProvider
traceExporter, _ := otlptrace.New(ctx, otlptracegrpc.NewClient())
tp := sdktrace.NewTracerProvider(
sdktrace.WithResource(res),
sdktrace.WithBatcher(traceExporter),
sdktrace.WithSampler(sdktrace.AlwaysSample()),
)
otel.SetTracerProvider(tp)
// MeterProvider
metricExporter, _ := otlpmetric.New(ctx, otlpmetricgrpc.NewClient())
mp := sdkmetric.NewMeterProvider(
sdkmetric.WithResource(res),
sdkmetric.WithReader(sdkmetric.NewPeriodicReader(metricExporter)),
)
otel.SetMeterProvider(mp)
// 使用
tracer := otel.Tracer("api-server")
meter := otel.Meter("api-server")
Provider 生命周期:
初始化:
Resource → TracerProvider + MeterProvider + LoggerProvider
运行时:
TracerProvider → Tracer → Span
MeterProvider → Meter → Instrument
关闭:
LoggerProvider.Shutdown()
MeterProvider.Shutdown()
TracerProvider.Shutdown()
18 OpenTelemetry 在 Kubernetes 中如何部署和配置?
答案:
OTel 在 K8s 中的标准部署模式是 Agent(DaemonSet)+ Gateway(Deployment)分层架构。
K8s 部署架构:
K8s Cluster
│
├── Node 1
│ └── otel-agent (DaemonSet)
│ └── OTLP Export → otel-gateway
│
├── Node 2
│ └── otel-agent (DaemonSet)
│ └── OTLP Export → otel-gateway
│
└── otel-gateway (Deployment)
└── Export → Jaeger/Prometheus/OTLP
Agent DaemonSet 配置:
apiVersion: v1
kind: ConfigMap
metadata:
name: otel-agent-conf
namespace: observability
data:
config.yaml: |
receivers:
otlp:
protocols:
grpc:
endpoint: 0.0.0.0:4317
http:
endpoint: 0.0.0.0:4318
processors:
batch:
timeout: 1s
send_batch_size: 1024
memory_limiter:
check_interval: 1s
limit_mib: 256
exporters:
otlp:
endpoint: otel-gateway:4317
tls:
insecure: true
service:
pipelines:
traces:
receivers: [otlp]
processors: [memory_limiter, batch]
exporters: [otlp]
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: otel-agent
spec:
selector:
matchLabels:
app: otel-agent
template:
metadata:
labels:
app: otel-agent
spec:
containers:
- name: otel-agent
image: otel/opentelemetry-collector-contrib:0.100.0
args: ["--config=/conf/config.yaml"]
ports:
- containerPort: 4317
name: otlp-grpc
- containerPort: 4318
name: otlp-http
resources:
limits:
memory: 512Mi
cpu: 500m
requests:
memory: 128Mi
cpu: 100m
volumeMounts:
- name: config
mountPath: /conf
volumes:
- name: config
configMap:
name: otel-agent-conf
apiVersion: v1
kind: Service
metadata:
name: otel-agent
spec:
ports:
- name: otlp-grpc
port: 4317
- name: otlp-http
port: 4318
selector:
app: otel-agent
Gateway Deployment 配置:
apiVersion: apps/v1
kind: Deployment
metadata:
name: otel-gateway
spec:
replicas: 2
selector:
matchLabels:
app: otel-gateway
template:
spec:
containers:
- name: otel-gateway
image: otel/opentelemetry-collector-contrib:0.100.0
args: ["--config=/conf/config.yaml"]
resources:
limits:
memory: 1Gi
cpu: "2"
requests:
memory: 512Mi
cpu: "1"
apiVersion: v1
kind: Service
metadata:
name: otel-gateway
spec:
ports:
- name: otlp-grpc
port: 4317
- name: otlp-http
port: 4318
selector:
app: otel-gateway
19 OpenTelemetry 的 Span Kind 有哪些类型?各在什么场景使用?
答案:
Span Kind 描述 Span 在 Trace 中的角色,影响父子关系和处理语义。
Span Kind 类型:
| Kind | 角色 | 典型场景 | 是否创建新 Trace |
|---|---|---|---|
| Internal | 进程内部操作 | 函数调用、计算 | 否 |
| Server | 服务端处理 | HTTP Handler、gRPC Server | 否(继承) |
| Client | 客户端请求 | HTTP Client、DB Client | 否 |
| Producer | 消息生产者 | Kafka Producer、Queue Publish | 否 |
| Consumer | 消息消费者 | Kafka Consumer、Queue Subscribe | 取决于实现 |
代码示例:
// Server Kind
span := tracer.Start(ctx, "HTTP GET /api/users",
trace.WithSpanKind(trace.SpanKindServer),
)
// Client Kind
span := tracer.Start(ctx, "SELECT * FROM users",
trace.WithSpanKind(trace.SpanKindClient),
)
// Internal Kind
span := tracer.Start(ctx, "process_data",
trace.WithSpanKind(trace.SpanKindInternal),
)
// Producer Kind
span := tracer.Start(ctx, "publish order event",
trace.WithSpanKind(trace.SpanKindProducer),
)
// Consumer Kind
span := tracer.Start(ctx, "consume order event",
trace.WithSpanKind(trace.SpanKindConsumer),
)
Span Kind 对 Trace 结构的影响:
Server ← Client ← Server ← Client
│ │
└── Internal └── Internal
│ │
└── Internal └── Internal
Producer(消息发送)
→ Trace 结束
→ Consumer(消息接收,可能在不同 Trace)
→ 通过 Link 关联
20 OpenTelemetry 的 Error Handling 策略是什么?如何处理 Span 错误?
答案:
OTel 通过 Span Status、Events 和 Attributes 来记录错误信息,支持结构化错误报告。
Span Status 状态码:
| 状态 | 说明 | 使用场景 |
|---|---|---|
| Unset | 未设置(默认) | 正常但未显式设置 |
| Ok | 成功完成 | 显式标记成功 |
| Error | 发生错误 | 异常/失败场景 |
错误处理示例:
import (
"go.opentelemetry.io/otel/codes"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/trace"
)
func processRequest(ctx context.Context, req Request) error {
ctx, span := tracer.Start(ctx, "process_request")
defer span.End()
result, err := db.Query(ctx, req.UserID)
if err != nil {
// 方式1:设置 Span Status
span.SetStatus(codes.Error, "database query failed")
// 方式2:添加错误事件(包含堆栈)
span.AddEvent("exception", trace.WithAttributes(
attribute.String("exception.type", "DBError"),
attribute.String("exception.message", err.Error()),
attribute.String("exception.stacktrace", string(debug.Stack())),
))
// 方式3:记录错误属性
span.SetAttributes(
attribute.Bool("error", true),
attribute.String("error.type", "DatabaseError"),
)
return err
}
span.SetStatus(codes.Ok, "success")
return nil
}
最佳实践:
| 实践 | 做法 | 原因 |
|---|---|---|
| 设置 Status | span.SetStatus(codes.Error, msg) | 后端识别错误 Span |
| 记录堆栈 | AddEvent("exception", stack) | 错误定位 |
| 不要重复设置 | 只设置一次 Error | 避免混淆 |
| 保留原始错误 | 记录原因链 | 完整上下文 |
| 标注错误类型 | error.type Attribute | 统计分析 |
21 OpenTelemetry 的 Attribute 和 Resource 的语义约定(Semantic Convention)是什么?
答案:
Semantic Convention 定义了跨语言/跨厂商统一的可观测性字段命名规范,确保数据互通性。
HTTP 语义约定:
// 通用 HTTP Attributes
span.SetAttributes(
semconv.HTTPMethod("GET"),
semconv.HTTPURL("/api/users"),
semconv.HTTPStatusCode(200),
semconv.HTTPRequestContentLength(1024),
)
// HTTP Server Attributes
span.SetAttributes(
semconv.NetHostName("api.example.com"),
semconv.NetTransportTCP,
)
// HTTP Client Attributes
span.SetAttributes(
semconv.HTTPTarget("/api/users"),
semconv.PeerService("user-service"),
)
数据库语义约定:
span.SetAttributes(
semconv.DBSystemPostgreSQL,
semconv.DBName("users"),
semconv.DBStatement("SELECT * FROM users WHERE id = ?"),
semconv.DBOperation("SELECT"),
semconv.DBSQLTable("users"),
)
消息队列语义约定:
span.SetAttributes(
semconv.MessagingSystemKafka,
semconv.MessagingDestination("orders"),
semconv.MessagingOperationProcess,
semconv.MessagingMessageID("msg-123"),
)
Resource 语义约定:
res := resource.NewWithAttributes(
semconv.SchemaURL,
semconv.ServiceName("user-service"),
semconv.ServiceVersion("1.2.3"),
semconv.ServiceInstanceID("pod-abc"),
semconv.DeploymentEnvironment("production"),
semconv.CloudProviderAWS,
semconv.CloudRegion("ap-southeast-1"),
semconv.HostName("node-1"),
semconv.ContainerID("docker-abc"),
)
22 OTel Collector 的 Connector 组件是什么?如何实现 Traces→Metrics 的信号转换?
答案:
Connector 是 OTel Collector v0.56+ 引入的组件,连接不同 Pipeline 并实现信号类型转换。
Connector 架构:
```mermaid
graph TD
A1["Receivers: otlp"] --> A2["Processors: batch"] --> A3["Exporters: spanmetrics"]
A3 --> C["Connector: spanmetrics<br/>Traces → Metrics"]
C --> B1["Receivers: spanmetrics"] --> B2["Processors: batch"] --> B3["Exporters: prometheus"]
subgraph PA["Pipeline A (Traces)"]
A1
A2
A3
end
subgraph PB["Pipeline B (Metrics)"]
B1
B2
B3
end
**Span Metrics Connector:**
```yaml
receivers:
otlp:
protocols:
grpc:
endpoint: 0.0.0.0:4317
processors:
batch:
timeout: 1s
send_batch_size: 1024
connectors:
spanmetrics:
# 从 Span 生成 Metrics 维度
dimensions:
- name: http.method
default: GET
- name: http.status_code
default: 200
- name: http.target
# Histogram 配置
latency_histogram_buckets:
- 5ms
- 10ms
- 25ms
- 50ms
- 100ms
- 250ms
- 500ms
- 1000ms
- 2500ms
- 5000ms
# 指标命名
metrics_flush_interval: 1m
exporters:
prometheus:
endpoint: 0.0.0.0:8889
logging:
verbosity: detailed
service:
pipelines:
traces:
receivers: [otlp]
processors: [batch]
exporters: [spanmetrics]
metrics:
receivers: [spanmetrics]
processors: [batch]
exporters: [prometheus, logging]
生成指标示例:
# Span 统计生成以下 Prometheus 指标:
traces_span_count_total{dimension="value"}
traces_latency_bucket{dimension="value",le="0.005"}
traces_latency_bucket{dimension="value",le="0.01"}
traces_latency_count{dimension="value"}
traces_latency_sum{dimension="value"}
23 OpenTelemetry 如何集成 Jaeger?
答案:
OTel 集成 Jaeger 通过 Collector 的 Jaeger Exporter 或直接 OTLP 导出实现(Jaeger v1.35+ 原生支持 OTLP)。
集成方式对比:
| 方式 | 数据流 | Jaeger 版本要求 |
|---|---|---|
| OTLP 直接导出 | App → OTLP → Jaeger (OTLP) | v1.35+ |
| Collector + Jaeger Exporter | App → OTLP → Collector → Jaeger | 任意 |
| Collector + Jaeger gRPC | App → OTLP → Collector → Jaeger (gRPC) | 任意 |
方式一:OTLP 直接导出(推荐)
# Jaeger 启动时启用 OTLP
services:
jaeger:
image: jaegertracing/all-in-one:latest
ports:
- "16686:16686" # UI
- "4317:4317" # OTLP gRPC
- "4318:4318" # OTLP HTTP
方式二:Collector 中转
# Collector 配置
receivers:
otlp:
protocols:
grpc:
endpoint: 0.0.0.0:4317
processors:
batch:
timeout: 1s
send_batch_size: 1024
exporters:
jaeger:
endpoint: jaeger:14250
tls:
insecure: true
service:
pipelines:
traces:
receivers: [otlp]
processors: [batch]
exporters: [jaeger]
Go SDK 直接导出到 Jaeger(OTLP):
exporter, _ := otlptracegrpc.New(ctx,
otlptracegrpc.WithEndpoint("jaeger:4317"),
otlptracegrpc.WithInsecure(),
)
tp := sdktrace.NewTracerProvider(
sdktrace.WithBatcher(exporter),
sdktrace.WithResource(res),
)
otel.SetTracerProvider(tp)
24 OTel Collector 的 Attributes Processor 如何修改 Span 属性?
答案:
Attributes Processor 对 Span/Metric/Log 的属性进行插入、更新、删除或提取操作。
处理器动作:
| 动作 | 说明 | 语法 |
|---|---|---|
insert | 插入新属性 | key: value |
update | 更新已有属性 | key: new_value |
upsert | 插入或更新 | key: value |
delete | 删除属性 | key |
hash | Hash 属性值 | field |
extract | 正则提取 | pattern |
配置示例:
processors:
attributes:
actions:
# 1. 插入固定属性
- key: environment
value: production
action: insert
# 2. 更新服务名
- key: service.name
value: api-gateway
action: upsert
# 3. 删除敏感属性
- key: auth.token
action: delete
- key: password
action: delete
# 4. Hash IP(匿名化)
- key: client.ip
action: hash
# 5. 提取路径(从 URL 中提取路径模式)
- key: http.target
pattern: ^/([^/?]+)
action: extract
# 条件处理
attributes/conditional:
include:
match_type: regexp
attributes:
- key: http.status_code
value: "5[0-9]{2}"
actions:
- key: error
value: true
action: upsert
service:
pipelines:
traces:
receivers: [otlp]
processors: [attributes, batch]
exporters: [otlp]
25 OpenTelemetry 的 SDK 配置环境变量有哪些?OTEL_EXPORTER_OTLP_* 系列参数?
答案:
OTel SDK 通过多种环境变量控制 Exporter、Resource、Sampler 等行为,减少代码配置。
通用配置:
| 环境变量 | 说明 | 默认值 |
|---|---|---|
OTEL_SERVICE_NAME | 服务名称 | unknown_service |
OTEL_RESOURCE_ATTRIBUTES | 额外 Resource 属性 | — |
OTEL_LOG_LEVEL | SDK 日志级别 | info |
OTEL_PROPAGATORS | Context 传播器 | tracecontext,baggage |
OTEL_TRACES_SAMPLER | 采样策略 | parentbased_always_on |
OTEL_TRACES_SAMPLER_ARG | 采样参数 | — |
OTLP Exporter 配置:
| 环境变量 | 说明 | 默认值 |
|---|---|---|
OTEL_EXPORTER_OTLP_ENDPOINT | OTLP 接收端 | http://localhost:4318 |
OTEL_EXPORTER_OTLP_PROTOCOL | 传输协议 | http/protobuf |
OTEL_EXPORTER_OTLP_TIMEOUT | 超时时间 | 10s |
OTEL_EXPORTER_OTLP_HEADERS | 自定义 Header | — |
OTEL_EXPORTER_OTLP_COMPRESSION | 压缩方式 | gzip |
OTEL_EXPORTER_OTLP_CERTIFICATE | TLS 证书 | — |
按信号类型的 OTLP 配置:
| 环境变量 | 作用 |
|---|---|
OTEL_EXPORTER_OTLP_TRACES_ENDPOINT | Traces 独立端点 |
OTEL_EXPORTER_OTLP_METRICS_ENDPOINT | Metrics 独立端点 |
OTEL_EXPORTER_OTLP_LOGS_ENDPOINT | Logs 独立端点 |
OTEL_TRACES_EXPORTER | Trace Exporter 类型 |
OTEL_METRICS_EXPORTER | Metric Exporter 类型 |
OTEL_LOGS_EXPORTER | Log Exporter 类型 |
完整配置示例:
# 基础配置
export OTEL_SERVICE_NAME=user-service
export OTEL_RESOURCE_ATTRIBUTES="deployment.environment=production,service.version=1.2.3"
export OTEL_PROPAGATORS=tracecontext,baggage
# OTLP 配置
export OTEL_EXPORTER_OTLP_ENDPOINT=http://otel-collector:4318
export OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf
export OTEL_EXPORTER_OTLP_HEADERS="api-key=abc123"
export OTEL_EXPORTER_OTLP_COMPRESSION=gzip
# 采样
export OTEL_TRACES_SAMPLER=parentbased_traceidratio
export OTEL_TRACES_SAMPLER_ARG=0.1
# 启动应用
java -jar app.jar
26 OpenTelemetry 的 Edge Cases 处理:高吞吐、背压、数据丢失
答案:
OTel SDK 通过队列、批处理和背压机制处理高吞吐量场景下的数据稳定性。
高吞吐处理策略:
高吞吐量 → OTel SDK
│
BatchSpanProcessor
├── MaxQueueSize: 2048(默认)
├── BatchTimeout: 1s
└── MaxExportBatchSize: 512
│
(队列满时的降级行为)
├── blocking: 阻塞应用(默认,高可靠)
├── dropping: 丢弃新 Span(实时性优先)
└── 可通过 SDK 配置
配置优化:
// 高吞吐场景配置
bsp := sdktrace.NewBatchSpanProcessor(
exporter,
sdktrace.WithMaxQueueSize(4096), // 增大队列
sdktrace.WithMaxExportBatchSize(1024), // 增大批量
sdktrace.WithBatchTimeout(500*time.Millisecond), // 降低延迟
sdktrace.WithExportTimeout(30*time.Second),
)
背压处理:
Collector 侧背压:
Receiver → Processors → Exporter
│
Memory Limiter
├── 内存 > limit → 返回 ResourceExhausted
└── SDK 收到错误 → 重试或降级
SDK 侧背压:
Exporter 失败 → BatchSpanProcessor 重试
→ 如果持续失败 → 队列满 → 阻塞应用
数据丢失场景:
| 场景 | 丢失类型 | 应对措施 |
|---|---|---|
| SDK 队列满 | 丢弃 Span | 增大队列或启用阻塞 |
| Exporter 不可达 | 丢失未发送数据 | 增加本地文件缓冲 |
| 进程崩溃 | 内存中未导出数据 | 配置持久化缓冲 |
| Collector 重启 | 传输中数据 | Collector HA 部署 |
| 网络分区 | 长时间不可达 | 采样减少数据量 |
27 OpenTelemetry Collector 如何实现高可用部署?
答案:
OTel Collector 通过多副本、负载均衡和无状态设计实现高可用。
无状态架构:
graph TD
LB[Load Balancer] --> C1[Collector-1]
LB --> C2[Collector-2]
LB --> C3[Collector-3]
C1 --> Exporters[Exporters - 本身 HA]
C2 --> Exporters
C3 --> Exporters
K8s 高可用部署:
apiVersion: apps/v1
kind: Deployment
metadata:
name: otel-gateway
spec:
replicas: 3
strategy:
rollingUpdate:
maxSurge: 1
maxUnavailable: 0 # 零停机更新
selector:
matchLabels:
app: otel-gateway
template:
spec:
affinity:
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchLabels:
app: otel-gateway
topologyKey: kubernetes.io/hostname
containers:
- name: collector
image: otel/opentelemetry-collector-contrib:0.100.0
readinessProbe:
httpGet:
path: /
port: 13133
livenessProbe:
httpGet:
path: /health
port: 13133
resources:
limits:
memory: 1Gi
cpu: "2"
requests:
memory: 512Mi
cpu: "1"
健康检查 Extension:
extensions:
health_check:
endpoint: 0.0.0.0:13133
pprof:
endpoint: 0.0.0.0:1777
service:
extensions: [health_check, pprof]
pipelines:
traces:
receivers: [otlp]
processors: [batch]
exporters: [otlp]
28 OpenTelemetry 的 Instrumentation 库版本兼容性规则是什么?
答案:
OTel 采用语义化版本控制,API 和 SDK 分开版本管理,各语言实现遵循统一规范。
版本兼容性矩阵:
OTel API v1.x.x → 稳定,不向后兼容性破坏
OTel SDK v1.x.x → 稳定,遵循 API 规范
OTel Contrib v0.x.x → 实验性(Instrumentation)
规则:
API v1.x ↔ SDK v1.x 兼容
Contrib v0.x ↔ SDK v1.x 兼容
API v1.x ↔ Contrib v0.x 兼容(通过 SDK)
各语言 @otel 包版本状态:
| 语言 | API 版本 | SDK 版本 | Instrumentation |
|---|---|---|---|
| Java | v1.x | v1.x | 稳定 |
| Go | v1.x | v1.x | 多数稳定 |
| Python | v1.x | v1.x | 多数稳定 |
| JavaScript | v1.x | v1.x | 多数稳定 |
| .NET | v1.x | v1.x | 多数稳定 |
| Ruby | v0.x | v0.x | 实验性 |
升级注意事项:
1. API 和 SDK 版本必须匹配(v1.x 对 v1.x)
2. Instrumentation 版本独立,但要求 SDK 兼容版本
3. 跨语言服务要求 Exporters 版本兼容
4. Collector 版本独立于 SDK 版本
推荐:保持各组件版本同步更新
29 OpenTelemetry 的 Exemplar 机制是什么?如何将 Metrics 关联到 Trace?
答案:
Exemplar 是 Metrics 数据点上附加的 Trace 引用,将聚合指标关联到具体请求的 Trace 信息。
Exemplar 工作机制:
Histogram Metric (request.duration)
Bucket: 0-100ms
DataPoint: value=45ms
Exemplar: {
trace_id: "abc...",
span_id: "123...",
value: 45ms,
timestamp: ...
}
Bucket: 100-500ms
DataPoint: value=250ms
Exemplar: {
trace_id: "def...",
span_id: "456...",
value: 250ms,
timestamp: ...
}
配置 Exemplar:
processors:
batch:
exemplar:
enabled: true
max_exemplars: 20
filter:
- http.status_code: "5[0-9]{2}"
Go SDK 设置 Exemplar:
import (
"go.opentelemetry.io/otel/sdk/metric"
"go.opentelemetry.io/otel/sdk/metric/metricdata"
)
// 启用 Exemplar
provider := metric.NewMeterProvider(
metric.WithReader(metric.NewPeriodicReader(
exporter,
metric.WithInterval(15*time.Second),
)),
metric.WithExemplarFilter(
metric.WithExemplarFilter(
metric.ExemplarFilterAlwaysOn,
),
),
)
Prometheus Exemplar 支持:
# Prometheus v2.40+ 支持 Exemplar
# 通过 OTel Collector 导出 Exemplar
exporters:
prometheus:
endpoint: 0.0.0.0:8889
enable_open_metrics: true # 启用 Exemplar 导出
30 OpenTelemetry 的完整生产部署架构设计要点是什么?
答案:
生产级 OTel 部署需考虑数据流设计、容量规划、高可用和安全四个方面。
生产架构设计:
服务 → Agent (DaemonSet) → Gateway (Deployment) → 后端
每个环节的设计要点:
Agent 层设计:
# 资源
Memory: 256MB limit
CPU: 500m limit
# 处理
Memory Limiter: 200MB → 开始降级
Batch: 1s / 1024
# 采样(减轻后端压力)
Tail Sampling:
Error: 100%
Latency > 5s: 100%
Others: 10%
Gateway 层设计:
# 高可用
Replicas: 3
Pod Anti-Affinity
# 处理
Memory Limiter: 1GB
Load Balancer
# 路由
多 Exporter → Jaeger + Prometheus + S3 归档
# 认证
API Key 验证 → 仅接受已知 Agent
容量规划:
| 环节 | 估算公式 | 示例 |
|---|---|---|
| Agent 内存 | 100MB + SpanThroughput × 1KB | 10k Spans/s → 200MB |
| Gateway 内存 | AgentCount × 50MB | 100 Agent → 5GB |
| 后端存储 | SpanCount × 1KB × Retention | 5M Spans/d × 30d ≈ 150GB |
| 网络带宽 | SpanThroughput × 1KB | 10k Spans/s ≈ 10MB/s |
安全考虑:
Agent ↔ Gateway:TLS + API Key
Gateway ↔ Backend:mTLS(双向认证)
配置管理:K8s Secret 管理凭证
网络隔离:专用 Service Mesh 策略
31 OpenTelemetry 在微服务架构中实现分布式 Trace 的最佳实践是什么?
答案:
在微服务中实现端到端 Trace 需要统一 Context Propagation、规范 Span 命名和合理的采样策略。
Context Propagation 统一:
// 所有服务使用相同的 Propagator 配置
import (
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/propagation"
)
func init() {
otel.SetTextMapPropagator(
propagation.NewCompositeTextMapPropagator(
propagation.TraceContext{},
propagation.Baggage{},
),
)
}
Span 命名规范:
HTTP: {HTTP Method} {Route}
✅ "GET /api/users/{id}"
✅ "POST /api/orders"
❌ "GET /api/users/123" (包含具体 ID)
gRPC: {Service}/{Method}
✅ "UserService/GetUser"
DB: {DB Type} {Operation} {Table}
✅ "PostgreSQL SELECT users"
MQ: {Topic} {Operation}
✅ "orders PUBLISH"
✅ "orders CONSUME"
关键属性注入:
// HTTP 服务端必备
span.SetAttributes(
semconv.HTTPMethod(r.Method),
semconv.HTTPURL(r.URL.String()),
semconv.HTTPStatusCode(statusCode),
semconv.HTTPTarget(r.URL.Path),
semconv.HTTPRequestContentLength(req.ContentLength),
semconv.HTTPRoute(pattern), // 路由模板
)
// 客户端必备
span.SetAttributes(
semconv.HTTPMethod(method),
semconv.HTTPURL(url),
semconv.PeerService(serviceName),
)
采样策略分层:
Gateway 层采样(统一控制):
- 错误请求: 100%
- 新功能灰度: 100%
- P99+ 延迟: 100%
- 基础: 10% 概率
Agent 层采样(预过滤):
- 健康检查: 0%
- 批量处理: 1%
32 OTel Collector 如何实现多租户隔离和数据路由?
答案:
多租户隔离通过 Receiver 认证、Processor 路由和 Exporter 分离实现。
多租户路由架构:
graph TD
O["OTLP Input<br/>统一入口"] --> AUTH["Auth Extensions<br/>提取 tenant"]
AUTH --> AP["Attributes Processor<br/>注入 tenant 属性"]
AP --> TS["Tail Sampling Processor<br/>租户独立策略"]
TS --> TA["Tenant A<br/>Exporter"]
TS --> TB["Tenant B<br/>Exporter"]
TS --> TC["Tenant C<br/>Exporter"]
配置示例:
extensions:
oidc_auth:
issuer_url: https://auth.example.com
audience: otel-collector
receivers:
otlp:
protocols:
grpc:
endpoint: 0.0.0.0:4317
auth:
authenticator: oidc_auth
processors:
attributes/tenant:
actions:
- key: tenant_id
from_context: auth.tenant_id
action: upsert
groupbyattrs:
keys:
- tenant_id
exporters:
otlp/tenant_a:
endpoint: tenant-a-backend:4317
headers:
authorization: Bearer ${TENANT_A_TOKEN}
otlp/tenant_b:
endpoint: tenant-b-backend:4317
headers:
authorization: Bearer ${TENANT_B_TOKEN}
routing:
from_attribute: tenant_id
default_exporters: [logging]
table:
- value: tenant_a
exporters: [otlp/tenant_a]
- value: tenant_b
exporters: [otlp/tenant_b]
service:
pipelines:
traces:
receivers: [otlp]
processors: [attributes/tenant, groupbyattrs, routing]
exporters: [routing]
33 OpenTelemetry 的 Probabilistic Sampler Processor 如何工作?
答案:
Probabilistic Sampler Processor 基于 Trace ID 的哈希值进行概率采样,确保同一 Trace 的所有 Span 被一致采样。
工作原理:
Trace ID: 0af7651916cd43dd8448eb211c80319c
│
Hash(Trace ID) → 0-16383 整数
│
threshold = sampling_percentage × 16383 / 100
│
hash < threshold → 保留
hash ≥ threshold → 丢弃
配置示例:
processors:
probabilistic_sampler:
# 采样百分比
sampling_percentage: 10
# 哈希种子(可选)
hash_seed: 42
# Attribute 来源(默认 trace_id)
attribute_source: trace_id
service:
pipelines:
traces:
receivers: [otlp]
processors: [probabilistic_sampler]
exporters: [otlp]
一致性保证:
Trace ID = abc123
Service A: hash(abc123) = 500 → threshold(10%) = 1638 → 保留 ✓
Service B: hash(abc123) = 500 → threshold(10%) = 1638 → 保留 ✓
Service C: hash(abc123) = 500 → threshold(10%) = 1638 → 保留 ✓
同一个 Trace 在不同服务采样结果一致
34 OpenTelemetry 的 gRPC 和 HTTP 协议传输的区别是什么?
答案:
OTLP 支持 gRPC 和 HTTP/1.1 两种传输协议,各有优劣。
协议对比:
| 维度 | gRPC | HTTP |
|---|---|---|
| 传输层 | HTTP/2 | HTTP/1.1 / HTTP/2 |
| 编码 | Protobuf (二进制) | Protobuf / JSON |
| 流式 | 双向流支持 | 单向 Request/Response |
| 性能 | 高 | 中 |
| 工具链 | protoc 编译 | curl 调试 |
| 浏览器支持 | 有限 | 原生 |
| 负载均衡 | gRPC L7 | HTTP L7 |
| 推荐场景 | 服务间通信 | 边缘/Web 接入 |
gRPC 配置:
receivers:
otlp:
protocols:
grpc:
endpoint: 0.0.0.0:4317
# gRPC 特有参数
max_recv_msg_size_mib: 10
max_concurrent_streams: 100
read_buffer_size: 512KB
write_buffer_size: 512KB
HTTP 配置:
receivers:
otlp:
protocols:
http:
endpoint: 0.0.0.0:4318
cors:
allowed_origins:
- http://localhost:3000
allowed_headers:
- Content-Type
- Authorization
max_request_body_size: 2MB
选型建议:
服务间通信(Collector → Backend):gRPC
- 高性能二进制传输
- 流式处理支持
- 双向 TLS 认证
边缘采集(SDK → Collector):HTTP
- 调试方便(curl)
- 浏览器支持
- 负载均衡简单
浏览器/移动端:HTTP
- 原生 Web 协议
- 避免 gRPC-Web 依赖
35 OTel Collector 的 Kubernetes Processor 功能是什么?
答案:
Kubernetes Processor 自动从 K8s API 获取 Pod 元数据并注入到 Span/Metric/Log 中。
功能列表:
| 功能 | 说明 | 配置 |
|---|---|---|
| Pod 元数据注入 | 注入 namespace/pod/node 等 | extract.annotations |
| Label 提取 | 提取 Pod Labels 作为属性 | extract.labels |
| Annotation 提取 | 提取 Pod Annotations | extract.annotations |
| Owner 查找 | 查找 Deployment/StatefulSet | extract.owner_lookup |
| 命名空间过滤 | 仅处理指定命名空间 | filter.namespaces |
配置示例:
processors:
k8sattributes:
# K8s API 配置
auth_type: serviceAccount
passthrough: false
# 提取 Pod 信息
extract:
metadata:
- k8s.pod.name
- k8s.pod.uid
- k8s.namespace.name
- k8s.node.name
- k8s.pod.start_time
# 提取 Labels
labels:
- tag_name: app.label
key: app
from: pod
# 查找 Owner
owner_lookup: true
# 命名空间过滤
filter:
namespaces:
- production
- staging
node_from_env_var: K8S_NODE_NAME
# Pod 关联
pod_association:
- sources:
- from: resource_attribute
name: k8s.pod.uid
- sources:
- from: connection
注入效果:
原始 Span:
resource: {ip: "10.0.1.5"}
K8s Processor 处理后:
resource: {
ip: "10.0.1.5",
k8s.pod.name: "api-server-7d9f8c-abc12",
k8s.namespace.name: "production",
k8s.node.name: "node-3",
k8s.deployment.name: "api-server",
app.label: "api-server",
k8s.pod.uid: "pod-uid-xxx"
}