跳转到内容

OpenTelemetry 面试题

35 道题
分类
可观测性
子分类
trace
题目数
35 道
已阅读 0 / 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→DBSpan + SpanContext
Metrics聚合度量指标请求数、延迟 P99Instrument + 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_idTrace 全局唯一 ID16 字节 hex
span_idSpan 唯一 ID8 字节 hex
parent_span_id父 Span ID空表示 Root Span
nameSpan 名称“HTTP GET /api/users”
kindSpan 类型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 → BackendApp → 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 直出简化架构
大规模 K8sAgent + Gateway卸载处理压力
多后端路由Gateway中央路由策略
批处理/采样Gateway 集中统一控制
边缘/资源受限Agent 轻量最小化资源
6 OpenTelemetry 的采样策略有哪些?Head Sampling 和 Tail Sampling 的区别?

答案:

采样用于控制 Trace 数据量,减少存储成本的同时保留关键请求的完整链路。

采样策略对比:

维度Head SamplingTail Sampling
决策时机Span 创建时完整 Trace 接收后
决策依据本地信息全局信息
支持策略概率/速率基于错误/延迟/标签
实现位置SDKCollector
完整性可能丢失部分 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行为场景
SimpleSpan 结束时立即导出测试/调试
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-flags00-0af7651916cd43dd8448eb211c80319c-b7ad6b7169203331-01
tracestatevendor=valuedd=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事实标准最高
B3Zipkin 格式兼容
JaegerJaeger 原生格式兼容
AWS X-RayAWS 格式兼容
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.nameuser-service服务名称
service.namespaceproduction服务命名空间
service.version1.2.3服务版本
service.instance.idpod-abc123实例唯一 ID
host.namenode-1主机名
host.typec5.xlarge实例类型
cloud.provideraws云厂商
cloud.regionap-southeast-1区域
deployment.environmentproduction部署环境

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

支持的框架自动埋点:

语言支持框架
JavaSpring Boot, Tomcat, gRPC, Kafka, JDBC, Redis
PythonDjango, Flask, FastAPI, Requests, SQLAlchemy
Gonet/http, Gin, gRPC, database/sql
Node.jsExpress, Fastify, MongoDB, Redis, gRPC
.NETASP.NET Core, HttpClient, Entity Framework
RubyRails, Sinatra, Rack, Sidekiq
12 OTel 如何实现 Metrics 的采集?Counter、Gauge、Histogram 的区别?

答案:

OTel Metrics API 定义多种 Instrument 类型,用于不同场景的度量指标采集。

Instrument 类型:

类型行为场景示例
Counter单调递增请求计数、错误计数api_requests_total
UpDownCounter可增减队列长度、活跃连接active_connections
Histogram值分布延迟 P50/P95/P99request_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后端协议适用信号
OTLPOTel Collector 或兼容后端gRPC / HTTPTraces + Metrics + Logs
JaegerJaegergRPC / HTTPTraces
PrometheusPrometheusHTTP PullMetrics
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
}

最佳实践:

实践做法原因
设置 Statusspan.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 ExporterApp → OTLP → Collector → Jaeger任意
Collector + Jaeger gRPCApp → 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
hashHash 属性值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_LEVELSDK 日志级别info
OTEL_PROPAGATORSContext 传播器tracecontext,baggage
OTEL_TRACES_SAMPLER采样策略parentbased_always_on
OTEL_TRACES_SAMPLER_ARG采样参数

OTLP Exporter 配置:

环境变量说明默认值
OTEL_EXPORTER_OTLP_ENDPOINTOTLP 接收端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_CERTIFICATETLS 证书

按信号类型的 OTLP 配置:

环境变量作用
OTEL_EXPORTER_OTLP_TRACES_ENDPOINTTraces 独立端点
OTEL_EXPORTER_OTLP_METRICS_ENDPOINTMetrics 独立端点
OTEL_EXPORTER_OTLP_LOGS_ENDPOINTLogs 独立端点
OTEL_TRACES_EXPORTERTrace Exporter 类型
OTEL_METRICS_EXPORTERMetric Exporter 类型
OTEL_LOGS_EXPORTERLog 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
Javav1.xv1.x稳定
Gov1.xv1.x多数稳定
Pythonv1.xv1.x多数稳定
JavaScriptv1.xv1.x多数稳定
.NETv1.xv1.x多数稳定
Rubyv0.xv0.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 × 1KB10k Spans/s → 200MB
Gateway 内存AgentCount × 50MB100 Agent → 5GB
后端存储SpanCount × 1KB × Retention5M Spans/d × 30d ≈ 150GB
网络带宽SpanThroughput × 1KB10k 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 两种传输协议,各有优劣。

协议对比:

维度gRPCHTTP
传输层HTTP/2HTTP/1.1 / HTTP/2
编码Protobuf (二进制)Protobuf / JSON
流式双向流支持单向 Request/Response
性能
工具链protoc 编译curl 调试
浏览器支持有限原生
负载均衡gRPC L7HTTP 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 Annotationsextract.annotations
Owner 查找查找 Deployment/StatefulSetextract.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"
  }