Trace Skill 入门指南:从零构建分布式追踪系统

4次阅读
没有评论

共计 2065 个字符,预计需要花费 6 分钟才能阅读完成。

image.webp

核心概念:理解分布式追踪的黄金指标

分布式系统的可观测性建立在四大黄金指标之上,它们就像医生检查身体的体温、血压等基础指标一样重要:

Trace Skill 入门指南:从零构建分布式追踪系统

  • 延迟(Latency):请求从发起到响应的时间,直接影响用户体验
  • 错误(Errors):系统处理请求时发生的异常情况
  • 流量(Traffic):系统正在处理的请求量或并发量
  • 饱和度(Saturation):系统资源的使用程度,如 CPU、内存等

OpenTelemetry 是目前最主流的开源观测框架,它由三部分组成:

  1. API 层:定义统一的埋点接口规范
  2. SDK 层:实现数据采集、处理、导出等核心功能
  3. 导出器:将数据发送到后端系统如 Jaeger、Zipkin

痛点场景:为什么我们需要分布式追踪

假设一个电商系统包含订单、支付、库存三个服务,当用户投诉 ” 支付失败 ” 时:

  • 没有追踪系统:需要人工查看三个服务的日志,耗时且难以关联
  • 有追踪系统:通过 TraceID 一键查询完整调用链,快速定位是库存服务超时导致了支付回滚

技术实现:从代码层面接入追踪

Go 语言自动埋点示例

package main

import (
    "go.opentelemetry.io/otel"
    "go.opentelemetry.io/otel/exporters/jaeger"
    "go.opentelemetry.io/otel/sdk/trace"
)

func initTracer() (*trace.TracerProvider, error) {exp, err := jaeger.New(jaeger.WithCollectorEndpoint())
    if err != nil {return nil, err}

    tp := trace.NewTracerProvider(trace.WithBatcher(exp),
        // 采样率设置为 100%
        trace.WithSampler(trace.AlwaysSample()),
    )
    otel.SetTracerProvider(tp)
    return tp, nil
}

// 在 main 函数中初始化
tracer := otel.Tracer("order-service")
ctx, span := tracer.Start(ctx, "ProcessOrder")
defer span.End()  // 确保 span 结束

Java 手动埋点示例

@GetMapping("/payment")
public String processPayment(@RequestHeader HttpHeaders headers) {
    // 从 HTTP 头提取 TraceContext
    Span span = tracer.spanBuilder("payment-process")
        .setParent(extractContext(headers))
        .startSpan();

    try (Scope scope = span.makeCurrent()) {
        // 业务逻辑...
        span.addEvent("Charge credit card");
        return "Success";
    } catch (Exception e) {span.recordException(e);
        span.setStatus(StatusCode.ERROR);
        throw e;
    } finally {span.end();
    }
}

生产级配置策略

采样策略选择

  • 头部采样:在请求开始时决定是否采样,适合流量稳定的系统

    # OpenTelemetry Collector 配置示例
    processors:
      probabilistic_sampler:
        sampling_percentage: 10

  • 尾部采样:先收集所有数据再按规则筛选,适合需要保留异常请求的场景

导出器选型建议

  • Jaeger:适合需要强大可视化分析的企业
  • Zipkin:轻量级方案,适合资源有限的环境
  • OTLP:OpenTelemetry 原生协议,未来兼容性最好

避坑指南

  1. Span 命名规范
  2. 使用 serviceName.operationName 格式
  3. 避免动态名称如/user/123,应改为/user/{id}

  4. 标签使用禁忌

  5. 不要记录敏感信息如密码、token
  6. 控制标签数量(建议不超过 20 个)

  7. 高并发上下文丢失

  8. 使用线程局部变量存储 Context
  9. 框架集成时检查异步调用链是否完整

验证环节:本地 Jaeger 快速启动

# docker-compose.yml
version: '3'
services:
  jaeger:
    image: jaegertracing/all-in-one:latest
    ports:
      - "16686:16686"  # UI 端口
      - "14268:14268"  # 接收数据端口

启动后访问 http://localhost:16686 即可查看追踪数据。

动手实验

尝试实现以下场景:

  1. 创建两个 HTTP 服务(A 和 B)
  2. 服务 A 调用服务 B 时,通过 HTTP 头传递 TraceContext
  3. 在 Jaeger 中确认能看到完整的跨服务调用链

通过这个练习,你会深刻理解分布式追踪的核心价值——让复杂的系统调用变得透明可见。当遇到生产环境问题时,再也不用像无头苍蝇一样到处翻日志了!

正文完
 0
评论(没有评论)