4、应用接入Jaeger(Java):使用OpenTelemetry Java Agent自动埋点、配置导出端点与采样策略

Java 应用接入 Jaeger 最简洁的方式是使用 OpenTelemetry Java Agent。该 Agent 通过字节码增强技术自动拦截主流框架(如 Spring Boot、gRPC、Servlet、JDBC、HTTP Client 等)的调用,无需修改业务代码即可生成分布式追踪数据。本章将详细讲解 Agent 的安装、配置导出端点以及采样策略的设定。

核心原则:自动埋点适用于标准协议和框架;若涉及自定义异步链路或消息队列的特殊消费模式,仍需结合手动埋点(@WithSpan 注解或 OpenTelemetry API)进行补充。

4.1 OpenTelemetry Java Agent 自动埋点原理

Agent 在 JVM 启动时通过 javaagent 参数挂载,利用 Instrumentation API 修改目标类的字节码,在方法入口/出口插入 Span 创建与结束逻辑。整个过程对应用代码完全透明。

OpenTelemetry Java Agent 自动埋点流程 Java 应用进程 OTel Java Agent 字节码增强 -javaagent Instrumentation Spring MVC JDBC HTTP Client gRPC Redis Span 数据生成 SpanProcessor 批处理 OTLP/gRPC 导出 说明:Agent 自动为每个被拦截的框架调用创建子 Span,并自动传递 Trace Context,无需手动编写埋点代码。

4.2 快速接入步骤

4.2.1 下载 Agent JAR

从 OpenTelemetry Java Instrumentation 官方 Releases 页面下载最新版本的 opentelemetry-javaagent.jar。建议固定版本号用于生产环境,避免自动升级引入不兼容变更。

4.2.2 配置 JVM 启动参数

在应用启动命令中添加以下参数,即可完成基础接入:

java -javaagent:/path/to/opentelemetry-javaagent.jar \
     -Dotel.service.name=order-service \
     -Dotel.traces.exporter=otlp \
     -Dotel.exporter.otlp.endpoint=http://jaeger-collector:4318 \
     -jar myapp.jar
参数 说明 示例值
-Dotel.service.name 服务名称,在 Jaeger UI 中标识服务 order-service
-Dotel.traces.exporter 导出器类型,otlp 为 Jaeger 推荐协议 otlp
-Dotel.exporter.otlp.endpoint OTLP 接收端点(HTTP/gRPC) http://jaeger-collector:4318
-Dotel.resource.attributes 附加资源属性,如环境、版本 environment=production,version=1.2.3
注意:若 Jaeger Collector 使用 gRPC 端口(4317),端点应配置为 http://jaeger-collector:4317;若使用 HTTP 端口(4318),则配置为 http://jaeger-collector:4318。请根据实际部署的 Collector 协议选择。

4.3 配置导出端点

导出端点决定了 Span 数据发送的目标地址。除 JVM 参数外,也支持通过环境变量或 YAML 配置文件设定。以下为三种配置方式对比:

配置方式 优先级 适用场景
JVM 参数(-D) 最高 容器化部署、启动脚本
环境变量 中 Kubernetes ConfigMap/Secret
Agent 配置文件(YAML) 低 统一配置管理、多服务共享

环境变量示例:

export OTEL_SERVICE_NAME=payment-service
export OTEL_TRACES_EXPORTER=otlp
export OTEL_EXPORTER_OTLP_ENDPOINT=http://jaeger-collector:4318

Agent 配置文件示例(otel-config.yaml):

otel:
  service:
    name: inventory-service
  traces:
    exporter: otlp
  exporter:
    otlp:
      endpoint: http://jaeger-collector:4318
      headers:
        - "Authorization=Bearer mytoken"

使用配置文件时,启动参数需指定:-Dotel.javaagent.configuration-file=/path/to/otel-config.yaml。

4.4 采样策略配置

采样策略控制哪些请求被记录为 Trace,直接影响存储成本和性能开销。OpenTelemetry Java Agent 支持多种采样器,通过 -Dotel.traces.sampler 参数指定。

4.4.1 常用采样器对比

采样器名称 参数值 行为 推荐场景
始终采样 always_on 记录所有 Trace 开发/测试环境
始终不采样 always_off 不记录任何 Trace 性能压测、数据清理
基于比率 traceidratio 按 TraceId 哈希比例采样 生产环境低流量服务
基于父 Span parentbased_traceidratio 继承父 Span 采样决策,否则按比率 生产环境推荐

4.4.2 生产环境推荐配置

生产环境建议使用 parentbased_traceidratio 采样器,并设置合理的采样比率:

# 采样 10% 的请求,并继承上游采样决策
-Dotel.traces.sampler=parentbased_traceidratio
-Dotel.traces.sampler.arg=0.1
采样比率选择建议:
  • 高流量服务(>1000 req/s): 0.01 ~ 0.05(1% ~ 5%)
  • 中流量服务(100~1000 req/s): 0.1 ~ 0.2(10% ~ 20%)
  • 低流量服务(<100 req/s): 0.5 ~ 1.0(50% ~ 100%)
  • 核心交易链路: 可结合 Jaeger 的 Head-Based 采样或后续的 Tail-Based 采样实现差异化策略

4.4.3 基于头部属性的自定义采样

若需要根据 HTTP 头部(如 X-Debug)或请求参数动态采样,可通过自定义 Sampler 实现。以下为 Spring Boot 中注册自定义采样器的示例:

import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.api.trace.SpanKind;
import io.opentelemetry.context.Context;
import io.opentelemetry.sdk.trace.data.LinkData;
import io.opentelemetry.sdk.trace.samplers.Sampler;
import io.opentelemetry.sdk.trace.samplers.SamplingResult;
import java.util.List;

public class DebugHeaderSampler implements Sampler {
    private final Sampler fallback;

    public DebugHeaderSampler(Sampler fallback) {
        this.fallback = fallback;
    }

    @Override
    public SamplingResult shouldSample(Context parentContext, String traceId,
                                       String name, SpanKind spanKind,
                                       Attributes attributes, List<LinkData> parentLinks) {
        // 从 Context 中提取 HTTP 头部(需配合手动拦截器)
        String debugFlag = (String) parentContext.get("X-Debug");
        if ("true".equalsIgnoreCase(debugFlag)) {
            return SamplingResult.recordAndSample(); // 强制采样
        }
        return fallback.shouldSample(parentContext, traceId, name, spanKind, attributes, parentLinks);
    }

    @Override
    public String getDescription() {
        return "DebugHeaderSampler{fallback=" + fallback.getDescription() + "}";
    }
}

在配置类中注册:

@Bean
public Sampler customSampler() {
    Sampler fallback = Sampler.parentBased(Sampler.traceIdRatioBased(0.1));
    return new DebugHeaderSampler(fallback);
}

4.5 验证接入是否成功

启动应用后,执行以下检查步骤:

  1. 查看应用日志: 搜索 OTel SDK initialized 或 OpenTelemetry Java Agent initialized 确认 Agent 加载成功。
  2. 触发请求: 访问应用的任意 HTTP 端点,或执行一次业务操作。
  3. 检查 Jaeger UI: 打开 Jaeger 查询界面,在 Service 下拉框中应能看到配置的 otel.service.name。搜索最近时间段的 Trace,确认有数据展示。
  4. 检查 Collector 日志: 若数据未到达,查看 Jaeger Collector 日志是否有连接拒绝或协议不匹配错误。
快速诊断命令: 使用 curl 测试 OTLP HTTP 端点是否可达:
curl -v http://jaeger-collector:4318/v1/traces(应返回 200 或 405,而非 Connection Refused)。

4.6 常见问题与避坑

问题 原因 解决方案
Agent 加载后应用启动失败 Agent 版本与 JDK 版本不兼容 使用与 JDK 11+ 匹配的最新 Agent 版本;JDK 8 需使用 1.32.x 及以下版本
Jaeger UI 无数据 端点配置错误或网络不通 检查 otel.exporter.otlp.endpoint 协议(http/https)和端口;确认防火墙规则
Span 丢失或链路不完整 采样比率过低或 SpanProcessor 队列溢出 适当提高采样比率;增加 -Dotel.spanprocessor.batch.max.queue.size=4096
自定义框架未被自动埋点 Agent 不支持该框架版本 升级框架版本;或使用 OpenTelemetry API 手动埋点