Java Agent
SkyWalking Java Agent 通过字节码插桩(Bytecode Instrumentation)在 JVM 启动时随应用加载,自动拦截受支持的框架调用,采集 Trace、Metric 和 Profile,无需修改业务代码。它是 SkyWalking 在 Java 生态中最成熟、最常用的接入方式。
加载方式
Java 通过 -javaagent JVM 参数在应用启动前加载 Agent:
-javaagent:/app/skywalking-agent/skywalking-agent.jar \
-Dskywalking.agent.service_name=abc \
-Dskywalking.collector.backend_service=localhost:11800 \-javaagent指向skywalking-agent.jar。-Dskywalking.agent.service_name设置服务名(Service Name),对应 OAP 中的一个 Service。-Dskywalking.collector.backend_service设置 OAP 的 gRPC 地址(默认127.0.0.1:11800)。
安装包从官方下载页获取。Agent 版本应与 OAP 大版本兼容。
字节码插桩(Bytecode Instrumentation)
Agent 利用 Java Instrumentation API(premain / agentmain)在类加载时改写字节码,在目标方法的入口/出口处插入埋点代码,实现"自动打点":
| 概念 | 说明 |
|---|---|
premain | JVM 启动时、应用类加载前执行,适合常规接入(-javaagent) |
agentmain | 运行期动态挂载(attach),适合热接入 |
| Transform | 通过 ClassFileTransformer 改写类字节码 |
| 类隔离 | Agent 核心类与业务类隔离,避免冲突 |
插桩发生时机与用户请求无关,业务代码不需要 import 任何 SkyWalking 类,这是其低侵入的关键。
插件体系
SkyWalking Agent 的核心能力由**插件(Plugin)**提供。每个插件针对一类框架或技术栈做插桩:
- Web 框架:Spring MVC、Spring Boot、Tomcat、Jetty 等
- RPC:Dubbo、gRPC、Spring Cloud 等
- HTTP Client:RestTemplate、HttpClient、OkHttp、Feign 等
- 数据库:JDBC、MyBatis、Redis、MongoDB 等
- 消息队列:Kafka、RocketMQ、RabbitMQ 等
插件默认启用,部分需要显式配置或按 @Trace 注解/手动 API 接入。生产环境建议只启用实际使用的插件,减少无谓的插桩开销和潜在兼容问题。
关键配置
常用 -D 配置项(也可通过 agent/config/agent.config 文件或环境变量):
| 配置项 | 作用 |
|---|---|
skywalking.agent.service_name | 服务名,对应一个 Service |
skywalking.agent.instance_name | 实例名,缺省为自动生成的 UUID |
skywalking.agent.namespace | 命名空间,用于区分多套环境 |
skywalking.collector.backend_service | OAP gRPC 地址 |
skywalking.agent.sample_n_per_3_secs | 采样率:每 3 秒抽样条数,-1 表示全采 |
skywalking.agent.ignore_suffix | 忽略的请求后缀(如静态资源) |
skywalking.agent.trace_segment_ref_limit_per_span | 每个 Span 的 Segment 引用上限 |
skywalking.agent.active_v2_header | 是否发送 sw8 传播 Header |
配置规则:命令行 -D 优先级最高,其次环境变量,最后 config 文件。
采样
Java Agent 使用头部采样:在 Trace 根部决定是否采样,之后整条链路保持一致,避免收集"半条链路"。
skywalking.agent.sample_n_per_3_secs 控制每 3 秒抽取的请求条数,-1 表示全量采样。生产环境通常不全采:
- 全采开销高、存储成本大。
- 但慢请求/错误请求应尽量采到,否则定位问题会漏样本。
采样率说明与取舍,参见 APM / 采样。
Trace ID 注入与上下文传播
Agent 在处理请求入口生成 traceId,并把追踪上下文写入下游调用的协议头,实现跨进程传播:
- HTTP:往请求头写入
sw8(SkyWalking 自有钱包格式),也支持 W3Ctraceparent。 - gRPC:写入 gRPC Metadata。
- MQ:写入消息 Header。
下游进程的 Agent 读到这些 Header 后,续接同一 traceId,从而把链路连成一条。若 Header 未对齐或线程上下文丢失,会出现断链。
跨进程传播的协议与原理详见链路追踪原理。
异步与并发场景
Java 默认用 ThreadLocal 保存当前 Trace 上下文。跨线程/异步场景不会自动传递上下文,需要配合插件或手动处理:
- Thread Pool / Executor:需要传递上下文,否则子线程产生"孤儿 Span"。
- 异步 Servlet / WebFlux / Reactive:上下文切换频繁,依赖插件支持或
Async相关 API。
社区常用做法是使用 SkyWalking 提供的跨线程工具或依赖各框架的异步插件。若发现"链路在异步处断开",优先检查这里。
手动埋点(可选)
无法自动插桩的代码可用 API 手动埋点(例如自定义业务 Span):
import org.apache.skywalking.apm.toolkit.trace.Trace;
import org.apache.skywalking.apm.toolkit.trace.TraceContext;
public class BizService {
@Trace(opName = "handleBiz", operationName = "doSomething")
public void doSomething() {
System.out.println(TraceContext.traceId());
}
}手动埋点适合自动插件覆盖不到的关键业务逻辑,但应克制使用,避免埋点过密影响性能与可读性。
与语言 Agent 的差异
Java Agent 依赖 JVM 的字节码插桩能力,最为成熟。其它语言实现方式不同、能力也有差异:
| 语言 | 实现方式 | 成熟度 |
|---|---|---|
| Java | 字节码插桩(Instrumentation API) | 最完整,插件最多 |
| Go | SDK / 手动埋点为主(编译期) | 需配合框架注入 |
| Python | 运行时包装/hook | 中等 |
| Node.js | 运行时拦截(继承原生模块) | 中等 |
非 Java 环境往往需要更多手动接入,或通过 OpenTelemetry 等链路接入 OAP。
常见问题排查
| 症状 | 排查方向 |
|---|---|
| 页面无数据 | Agent 是否加载成功、backend_service 是否可达、版本是否兼容 |
| 部分请求没链路 | 采样率是否过低、异步线程是否丢上下文 |
| 服务名错误 | service_name 配置是否唯一、是否带上了 namespace |
| Trace 断链 | 检查 HTTP/ gRPC / MQ 的 Header 传播,及异步场景 |
| 高开销 | 只启用用到的插件、降低采样率、忽略静态资源后缀 |
结合 UI 查看 Agent 上报状态与数据链路,排障思路可参考告警与指标。