手把手把 OpenTelemetry SDK 接入炬鲸链路追踪。涵盖获取接入点、Java 与 Go 的 SDK 配置、Exporter 指向、埋点粒度、采样策略,以及“不上报、链路断”等问题的排查方法。
把 OpenTelemetry(OTel)接入炬鲸链路追踪,是打通全链路可观测的第一步。这篇讲清楚从拿接入点到看到完整调用树的全过程,以及中间最容易卡住的几个坑。
先说结论:链路追踪如果每换一家后端就重写一遍埋点,成本不可接受。OTel 的价值在于它把“埋点”和“后端”解耦——你用同一套 API 打 span,后端随便换,只是 exporter 配置不同。炬鲸完整支持 OTLP 协议,意味着你今天的 OTel 埋点在炬鲸、开源 Jaeger、以及任何 OTLP 兼容后端之间都能迁移。
先到控制台「接入中心 → 链路追踪」拿到两样东西:
https://collector.ob.jjhub.cn:4317Authorization同时确认运行环境:JDK 8+ 或 Go 1.19+,应用有出网权限(4317 端口)。
用 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 用 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
}
接入不等于“能用了”。要让链路真正可读,注意三点:
order_id、user_id 这类业务键,排查时才能按业务维度反查,而不是盯着 trace_id 猜。span.RecordError(err) 并 span.SetStatus(codes.Error),这样尾采样和“只看报错链路”才有依据,否则错误链路和正常链路混在一起没法筛。Java 和 Go 之外,其他语言接入思路一致:
opentelemetry-distro 或 opentelemetry-instrument 自动插桩,配置 OTEL_EXPORTER_OTLP_ENDPOINT 与 OTEL_EXPORTER_OTLP_HEADERS 环境变量即可。@opentelemetry/sdk-node + @opentelemetry/exporter-trace-otlp-http,OTEL_SERVICE_NAME 设服务名。OTEL_RESOURCE_ATTRIBUTES 补上 deployment.environment=prod、service.version,排查时按环境过滤链路会方便很多。全量 trace 对高 QPS 服务是灾难——存储和带宽都扛不住。炬鲸推荐分级采样:
AlwaysSample,全量,方便调试。TraceIDRatioBased(0.1) 起,按 10% 采样;配合 ParentBased + 自定义 sampler,让“带 error 的 span”全量保留。采样比例别拍脑袋定:先按 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 的日志,然后在炬鲸里用日志一键跳到对应链路,看到完整调用树就说明通了。
上线前过一遍这四条,基本能避免绝大多数“以为接好了”的问题:
四条都过,就可以把服务接入生产流量了。