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

OpenTelemetry 接入炬鲸 OBSERVE:从埋点到 trace 检索

以 Go 服务为例,讲解 OpenTelemetry 接入炬鲸 OBSERVE 的完整流程:环境准备、SDK 初始化、自动与手动埋点、OTLP 上报,以及采样率、时钟漂移等常见坑。

OpenTelemetry 接入炬鲸 OBSERVE:从埋点到 trace 检索

想要看全链路的调用关系,光靠日志不够,需要把 trace 采进来。OpenTelemetry(OTel)是目前事实上的埋点标准,接入炬鲸 OBSERVE 只需要三步:装 SDK、配置 OTLP 上报、在控制台确认数据落库。下面以 Go 服务为例走一遍完整流程。

一、准备工作

接入前确认三件事:

  • 炬鲸 OBSERVE 版本在 v2.0 以上,控制台已开启 OpenTelemetry 接入入口;
  • 服务端 OTLP 接收地址(gRPC 4317 或 HTTP 4318)在网络层面可达,防火墙放行对应端口;
  • 确定每个服务的 service.name 命名规范,比如 {业务域}-{服务名},避免后续在 trace 检索里对不上号。

二、装 SDK 并初始化

以 Go 为例,引入 OTel SDK 和 gRPC exporter:

import (
    "go.opentelemetry.io/otel"
    "go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc"
    "go.opentelemetry.io/otel/sdk/trace"
    "go.opentelemetry.io/otel/sdk/resource"
    semconv "go.opentelemetry.io/otel/semconv/v1.17.0"
)

func initTracer(ctx context.Context) (*trace.TracerProvider, error) {
    exporter, err := otlptracegrpc.New(ctx,
        otlptracegrpc.WithEndpoint("ob.jjhub.cn:4317"),
        otlptracegrpc.WithInsecure(),
    )
    if err != nil {
        return nil, err
    }
    res := resource.NewWithAttributes(semconv.SchemaURL,
        semconv.ServiceName("order-service"),
    )
    tp := trace.NewTracerProvider(
        trace.WithBatcher(exporter),
        trace.WithResource(res),
    )
    otel.SetTracerProvider(tp)
    return tp, nil
}

两个关键点:ServiceName 会作为炬鲸里区分服务的维度,务必每个服务填准确;WithBatcher 批量上报,比逐条上报省一半网络开销。
生产环境务必换成 TLS(otlptracegrpc.WithTLSCredentials(...)),WithInsecure 只适合内网测试。OTLP 走的是长连接,跨机房部署时防火墙要放行持续连接,而不是只放行一次握手。

三、自动埋点 + 手动埋点

HTTP 服务优先用自动埋点,改一行路由注册即可:

import "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"

mux.Handle("/api/order", otelhttp.NewHandler(orderHandler, "place-order"))

自动埋点能拿到"收到请求 → 返回响应"这个 span,但业务内部的耗时(查库、调下游、计算)要靠手动埋点补:

ctx, span := otel.Tracer("order-service").Start(ctx, "query-inventory")
defer span.End()
rows, err := db.QueryContext(ctx, "SELECT stock FROM inventory WHERE sku = ?", sku)
if err != nil {
    span.RecordError(err)
    span.SetStatus(codes.Error, err.Error())
}

记得在业务错误分支调用 span.RecordError 并设置 codes.Error,否则错误 span 在 trace 视图里看不出红色标记,漏掉大量真实故障。

给 span 加业务属性是排障的关键,别只起个名字就完事。把订单号、SKU、地区这类业务标识用 span.SetAttributes 放进去,检索时才能按业务维度过滤。但要注意别放高基数属性——属性会随 span 落盘,基数过高会拖慢查询。

四、配置上报并在控制台验证

炬鲸控制台「接入中心 → OpenTelemetry」里生成一个接入 token,把它作为 header 带上,用于区分租户:

exporter, _ := otlptracegrpc.New(ctx,
    otlptracegrpc.WithEndpoint("ob.jjhub.cn:4317"),
    otlptracegrpc.WithHeaders(map[string]string{
        "Authorization": "Bearer " + token,
    }),
)

启动服务后压几条请求,到控制台「链路追踪 → Trace 检索」,按服务名或 trace_id 查询。能看到完整的父子 span 瀑布图、每个 span 的耗时占比,以及右侧关联的日志和告警。如果 5 分钟后还查不到,优先检查 exporter 的报错日志(通常是连接被拒或 token 失效)。
另一个常见问题是资源未关联:service.name 拼写不一致会把 trace 归到两个不同的服务名下,检索前先核对命名。

五、踩坑记录

  • 时间不对:确认宿主机和炬鲸服务器时间同步(NTP),trace 按时间分片,时钟漂移超过几分钟会导致 span 查询不到。
  • 采样率:高流量服务别用 100% 采样,先在 trace.WithSampler(trace.ParentBased(trace.TraceIDRatioBased(0.1))) 采样 10%,等数据量稳定再上调。
  • 跨度爆炸:循环里不要无脑起 span,尤其是批处理任务,否则一个 trace 会有几万个 span,检索页面卡顿。给循环体加一个总 span 即可。
  • gRPC 版本:OTLP exporter 与服务端的 protobuf 版本要匹配,升级 SDK 时留意炬鲸的兼容性说明,避免出现"能连上但 span 不落库"的情况。
  • 高基数属性span.SetAttributes(attribute.String("user_id", uid)) 这类值不要在所有 span 上无差别塞入,用户 ID 建议只在关键交易 span 上设置,否则会推高索引体积、拖慢 trace 检索。

六、把指标一起接进来

trace 解决的是"这次调用慢在哪",指标解决的是"整体有没有异常"。建议同一套 OTel SDK 把 metrics 也上报:Go 里用 go.opentelemetry.io/otel/sdk/metric 初始化 MeterProvider,配合 runtime 采集器上报 GC、协程数、内存等运行时指标。这样服务刚接入就有基础性能基线,trace 里发现慢查询时,也能在指标面板上判断这是个别问题还是全局性劣化。

接入完成后,把 trace_id 打印进日志(log.Info("...", "trace_id", span.SpanContext().TraceID())),日志和 trace 就能互相串联,排障时从日志一键跳到对应链路。日志-指标-trace 三者齐了,才算真正用上可观测性。