← 返回文章列表
使用指南 4 分钟阅读 炬鲸团队

OpenTelemetry 接入炬鲸链路追踪:从零到全链路

手把手把 OpenTelemetry SDK 接入炬鲸链路追踪。涵盖获取接入点、Java 与 Go 的 SDK 配置、Exporter 指向、埋点粒度、采样策略,以及“不上报、链路断”等问题的排查方法。

把 OpenTelemetry(OTel)接入炬鲸链路追踪,是打通全链路可观测的第一步。这篇讲清楚从拿接入点到看到完整调用树的全过程,以及中间最容易卡住的几个坑。

为什么用 OpenTelemetry 而不是自建 SDK

先说结论:链路追踪如果每换一家后端就重写一遍埋点,成本不可接受。OTel 的价值在于它把“埋点”和“后端”解耦——你用同一套 API 打 span,后端随便换,只是 exporter 配置不同。炬鲸完整支持 OTLP 协议,意味着你今天的 OTel 埋点在炬鲸、开源 Jaeger、以及任何 OTLP 兼容后端之间都能迁移。

接入前准备

先到控制台「接入中心 → 链路追踪」拿到两样东西:

  • Endpoint:OTLP 接收地址,形如 https://collector.ob.jjhub.cn:4317
  • Token:租户鉴权令牌,写入请求头 Authorization

同时确认运行环境:JDK 8+ 或 Go 1.19+,应用有出网权限(4317 端口)。

Java 接入

用 OpenTelemetry Java Agent 是最省事的方式,不用改代码。下载 agent 后,在启动参数里加:

java -javaagent:opentelemetry-javaagent.jar \
  -Dotel.exporter.otlp.endpoint=https://collector.ob.jjhub.cn:4317 \
  -Dotel.exporter.otlp.headers='Authorization=Bearer <你的token>' \
  -Dotel.service.name=order-service \
  -Dotel.traces.exporter=otlp \
  -Dotel.metrics.exporter=none \
  -jar your-app.jar

几个关键参数:

  • otel.service.name 是服务在链路图上的显示名,按服务命名规范统一,别留默认的 unknown_service
  • otel.traces.exporter=otlp 只开 trace;暂不收 metrics 时把 metrics exporter 关掉,减少无效上报。
  • 生产环境加 otel.propagators=tracecontext,baggage,保证跨服务传播 trace 上下文。

Go 接入

Go 用 SDK 手动埋点,或借助 otelhttp 等自动插桩库。核心是初始化一个 TracerProvider 并指向炬鲸:

import (
    "go.opentelemetry.io/otel"
    "go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp"
    "go.opentelemetry.io/otel/sdk/trace"
)

func initTracer(ctx context.Context) (*trace.TracerProvider, error) {
    headers := map[string]string{"Authorization": "Bearer " + token}
    exp, err := otlptracehttp.New(ctx,
        otlptracehttp.WithEndpoint("collector.ob.jjhub.cn"),
        otlptracehttp.WithHeaders(headers),
        otlptracehttp.WithInsecure(),
    )
    if err != nil { return nil, err }
    tp := trace.NewTracerProvider(
        trace.WithBatcher(exp),
        trace.WithSampler(trace.ParentBased(trace.TraceIDRatioBased(0.1))),
    )
    otel.SetTracerProvider(tp)
    return tp, nil
}

埋点粒度与 span 属性

接入不等于“能用了”。要让链路真正可读,注意三点:

  1. span 属性带上业务标识:每个 span 至少带 order_iduser_id 这类业务键,排查时才能按业务维度反查,而不是盯着 trace_id 猜。
  2. 别过度埋点:只给“跨服务调用”和“关键业务步骤”打 span。循环里的每一步都打 span,会产生海量无意义数据,拖慢查询。
  3. 错误要显式标记:捕获异常时用 span.RecordError(err)span.SetStatus(codes.Error),这样尾采样和“只看报错链路”才有依据,否则错误链路和正常链路混在一起没法筛。

其他语言简注

Java 和 Go 之外,其他语言接入思路一致:

  • Python:用 opentelemetry-distroopentelemetry-instrument 自动插桩,配置 OTEL_EXPORTER_OTLP_ENDPOINTOTEL_EXPORTER_OTLP_HEADERS 环境变量即可。
  • Node.js:用 @opentelemetry/sdk-node + @opentelemetry/exporter-trace-otlp-httpOTEL_SERVICE_NAME 设服务名。
  • 资源属性:所有语言都建议通过 OTEL_RESOURCE_ATTRIBUTES 补上 deployment.environment=prodservice.version,排查时按环境过滤链路会方便很多。

采样策略:别全量上报

全量 trace 对高 QPS 服务是灾难——存储和带宽都扛不住。炬鲸推荐分级采样:

  • 开发/测试AlwaysSample,全量,方便调试。
  • 生产核心链路TraceIDRatioBased(0.1) 起,按 10% 采样;配合 ParentBased + 自定义 sampler,让“带 error 的 span”全量保留。
  • 尾采样(tail sampling)也能在服务端做,但先从上端 SDK 控制总量,最简单有效。

采样比例别拍脑袋定:先按 10% 跑一周,看存储成本和链路覆盖率,再回调。

常见问题排查

Q1:控制台看不到任何 trace。
按顺序查:① 4317 端口通不通(curl -v https://collector.ob.jjhub.cn:4317);② token 是否写对、是否带 Bearer 前缀;③ exporter 是否生效(看启动日志有没有 OTel 相关输出);④ 服务名是否为空。

Q2:链路是断的,只有单段 span。
多半是传播没配好:检查下游是否也装了 SDK、propagator 是否一致(都用 tracecontext);跨 HTTP 调用确认请求头里带 traceparent。断链最常见的原因就是上下游 propagator 版本不一致。

Q3:有 span 但耗时明显偏大。
先看是不是 exporter 的批量上报(batcher)延迟导致的,再看 span 是否包含了大体积属性。把日志和 span 属性精简,耗时通常会回落。

验证成功最直观的方式:在应用里打一条带 trace_id 的日志,然后在炬鲸里用日志一键跳到对应链路,看到完整调用树就说明通了。

上线前验证清单

上线前过一遍这四条,基本能避免绝大多数“以为接好了”的问题:

  • 服务名、endpoint、token 三处配置核对无误。
  • 跨两个以上服务的请求能看到完整调用树。
  • 采样比例与预期一致,error span 全量保留。
  • 资源属性里带上了环境与版本标识。

四条都过,就可以把服务接入生产流量了。