上一篇【第11篇】JavaAgent安装与配置:给应用植入可观测性的基因
下一篇【第13篇】Server部署详解:解读指挥中心的控制面板


上一篇我们把基因改造针(JavaAgent)成功植入了应用体内。但注射完成只是第一步——就像买了一辆跑车,只会点火启动可不够,你得学会调教引擎、调整悬挂、切换驾驶模式。

今天,我们就来深入Agent的高级配置:插件机制、采样率、异步追踪、上下文传播……这些参数决定了你的Agent是"见啥追踪啥"的莽夫,还是"精准高效"的忍者。

1. 插件机制详解

1.1 三种插件类型

SkyWalking Agent的插件分为三个阵营,就像基因改造液的三层药效:

┌──────────────────────────────────────────────────────────────────┐
│                  Agent插件三层架构                                 │
│                                                                  │
│  ┌──────────────────────────────────────────────────────────┐    │
│  │  bootstrap-plugins/ (底层突变层)                          │    │
│  │  拦截JDK内部类(如Thread/HttpURLConnection)              │    │
│  │  在JVM bootstrap classloader加载时生效                    │    │
│  │  ── apm-jdk-thread-plugin.jar                            │    │
│  │  ── apm-jdk-http-plugin.jar                              │    │
│  └──────────────────────────────────────────────────────────┘    │
│                          │                                       │
│  ┌──────────────────────────────────────────────────────────┐    │
│  │  plugins/ (基础能力层)                                    │    │
│  │  默认激活,覆盖主流框架                                    │    │
│  │  ── Spring/Tomcat/MySQL/Redis/Dubbo/Kafka...              │    │
│  │  约30+插件,开箱即用                                      │    │
│  └──────────────────────────────────────────────────────────┘    │
│                          │                                       │
│  ┌──────────────────────────────────────────────────────────┐    │
│  │  optional-plugins/ (高级能力层)                           │    │
│  │  按需激活,特殊框架或高级功能                              │    │
│  │  ── Oracle/Jedis/Gateway/自定义增强...                    │    │
│  │  约30+插件,手动启用                                      │    │
│  └──────────────────────────────────────────────────────────┘    │
└──────────────────────────────────────────────────────────────────┘

这三层插件各有不同的加载时机和适用范围:

bootstrap-plugins:这是最底层的插件,拦截的是JDK内部类。为什么单独分出来?因为JDK的核心类(如java.lang.Thread)是由Bootstrap ClassLoader加载的,普通插件无法触及这个层次。这些插件在Agent初始化的最早阶段就被加载,相当于给JVM的底层基因做了手术。

plugins:默认激活的插件,覆盖了大多数主流框架。只要你的应用用了Spring、Tomcat、MySQL这些常见技术栈,这些插件就会自动追踪。就像基因改造的基础套餐——你不需要主动选择,它就在那里。

optional-plugins:可选插件,需要手动激活。这些插件覆盖的是更特殊或更新兴的框架(如Oracle数据库、Spring Cloud Gateway),或者是一些有争议的功能(如自定义增强)。就像基因改造的高级套餐——需要你主动选择,按需激活。

1.2 插件激活与禁用

激活可选插件

激活optional-plugins非常简单——把jar包从optional-plugins/目录移到plugins/目录即可:

# 激活Spring Cloud Gateway插件
mv optional-plugins/apm-spring-cloud-gateway-2.x-plugin.jar plugins/

# 激活Oracle数据库插件
mv optional-plugins/apm-oracle-10.x-plugin.jar plugins/

# 激活自定义增强插件
mv optional-plugins/apm-customize-enhance-plugin.jar plugins/

# 激活多个插件(批量移动)
mv optional-plugins/apm-kafka-plugin.jar plugins/
mv optional-plugins/apm-jedis-2.x-4.x-plugin.jar plugins/
禁用默认插件

有时候你可能想禁用某个默认插件——比如你的应用不用MySQL,不需要追踪数据库调用;或者某个插件和你的代码有冲突。方法同样简单——把jar包从plugins/移到optional-plugins/

# 禁用MySQL追踪插件
mv plugins/apm-mysql-5.x-plugin-8.x-plugin.jar optional-plugins/

# 禁用Tomcat追踪插件
mv plugins/apm-tomcat-7.x-8.x-9.x-plugin.jar optional-plugins/
插件冲突排查

当多个插件对同一个类进行增强时,可能会产生冲突。排查方法:

# 查看Agent日志中的插件加载信息
grep "plugin found" skywalking-agent/logs/skywalking-api.log

# 查看哪些类被哪些插件增强
grep "Enhance class" skywalking-agent/logs/skywalking-api.log

1.3 自定义增强插件

optional-plugins目录中有一个特殊的插件——apm-customize-enhance-plugin.jar,它允许你不用写Java代码就能追踪自定义方法。

激活后,在config/目录下创建customize-enhance.xml

<?xml version="1.0" encoding="UTF-8"?>
<enhances>
    <!-- 追踪指定类的指定方法 -->
    <enhance class="com.mycompany.service.UserService" method="getUserById">
        <operationName>UserService.getUserById</operationName>
    </enhance>
    
    <!-- 追踪带参数匹配的方法 -->
    <enhance class="com.mycompany.service.OrderService" method="createOrder">
        <operationName>OrderService.createOrder</operationName>
        <include subClass="true"/>  <!-- 包含子类 -->
    </enhance>
    
    <!-- 追踪所有匹配类名的public方法 -->
    <enhance class="com.mycompany.controller.*Controller" method="*">
        <operationName>Controller.${methodName}</operationName>
    </enhance>
</enhances>

这个功能就像基因改造液的"自定义配方"——不需要开发新插件,只需要一个XML文件就能追踪任何方法。

2. 采样率配置

2.1 为什么需要采样

在生产环境中,如果每个请求都被完整追踪,会给OAP Server带来巨大的存储和计算压力。就像一个城市里的每一个行人都被DNA追踪——数据量太大了,系统会崩溃。

采样率就是控制"追踪多少比例的请求"的参数:

┌──────────────────────────────────────────────────────────┐
│              采样率对数据量的影响                           │
│                                                          │
│  100%采样 → 所有请求被追踪 → 数据量巨大 → 存储压力高       │
│                                                          │
│  ┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┐              │
│  │ ✓ │ ✓ │ ✓ │ ✓ │ ✓ │ ✓ │ ✓ │ ✓ │ ✓ │ ✓ │  全量       │
│  └───┴───┴───┴───┴───┴───┴───┴───┴───┴───┘              │
│                                                          │
│  10%采样 → 每10个请求追踪1个 → 数据量可控 → 存储友好       │
│                                                          │
│  ┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┐              │
│  │ ✓ │   │   │   │   │   │   │   │   │   │  采样        │
│  └───┴───┴───┴───┴───┴───┴───┴───┴───┴───┘              │
│                                                          │
│  关键:慢请求和错误请求会被强制追踪(不受采样率影响)       │
└──────────────────────────────────────────────────────────┘

2.2 sampler配置参数

# agent.config

# 采样策略:基于3秒时间窗口内的采样数量
# 默认值为-1,表示不采样(全量追踪)
# 正整数N表示每3秒追踪N个请求
agent.sample_n_per_3_secs=${SW_AGENT_SAMPLE:N_PER_3_SECS:-1}

注意:这里的采样率不是百分比!它是一个每3秒的采样数量

配置值 效果
-1 全量追踪(默认)
3 每3秒追踪3个请求
10 每3秒追踪10个请求
100 每3秒追踪100个请求

计算等效百分比需要知道你的请求QPS:

# 如果QPS=100,sample_n_per_3_secs=10
# 等效采样率 = 10 / (100 * 3) ≈ 3.3%

# 如果QPS=50,sample_n_per_3_secs=5
# 等效采样率 = 5 / (50 * 3) ≈ 3.3%

# 通用公式:
# 等效采样率 ≈ sample_n_per_3_secs / (QPS * 3)

2.3 采样率的注意事项

一个关键设计:采样率不影响慢请求和错误请求的追踪。无论采样率设置多低,SkyWalking都会强制追踪:

  • 响应时间超过阈值的请求
  • 出现异常/错误的请求

这就像基因改造液的智能模式——普通人按比例抽查,但可疑人物一律详细追踪。

# 慢请求阈值(毫秒),超过此值的请求强制追踪
trace.slow_threshold=${SW_TRACE_SLOW_THRESHOLD:-1}

# -1表示不强制追踪慢请求
# 正整数表示超过此毫秒数的请求强制追踪

2.4 不同场景的采样率建议

┌──────────────────────────────────────────────────────┐
│          不同场景的采样率推荐                           │
│                                                      │
│  开发/测试环境:-1(全量追踪)                         │
│  └───────────────────── 没有性能压力,数据全量分析      │
│                                                      │
│  低流量生产(QPS<50):-1或3                          │
│  └───────────────────── 流量低,全量或轻微采样          │
│                                                      │
│  中流量生产(QPS 50-500):3-10                       │
│  └───────────────────── 适度采样,保证核心数据         │
│                                                      │
│  高流量生产(QPS>500):10-50                         │
│  └───────────────────── 重点采样,错误和慢请求不漏     │
│                                                      │
│  超高流量(QPS>5000):50-100                         │
│  └───────────────────── 粗粒度采样,只追踪代表性请求   │
└──────────────────────────────────────────────────────┘

3. Agent日志配置

3.1 日志级别与含义

Agent有自己的日志系统(基于Log4j2),日志级别从低到高:

# agent.config
logging.level=${SW_LOGGING_LEVEL:INFO}
级别 输出内容 适用场景
DEBUG 所有调试信息,包括字节码增强细节 插件开发/排查问题
INFO 关键事件(启动/连接/采样) 日常生产
WARN 潜在问题(连接超时/采样溢出) 生产环境
ERROR 严重错误(Agent崩溃/数据丢失) 所有环境

生产环境建议设为WARNINFO。DEBUG级别会产生大量日志,仅在排查问题时临时启用。

3.2 日志文件管理

# agent.config

# 日志输出目录(空=Agent根目录/logs/)
logging.dir=${SW_LOGGING_DIR:}

# 日志文件名
logging.file_name=${SW_LOGGING_FILE_NAME:skywalking-api.log}

# 单个日志文件最大大小(字节),默认300MB
logging.max_file_size=${SW_LOGGING_MAX_FILE_SIZE:300000000}

# 最大日志文件数量,默认3个(轮转)
logging.max_file_num=${SW_LOGGING_MAX_FILE_NUM:3}

日志文件会自动轮转——当当前文件达到max_file_size时,会创建新文件,最多保留max_file_num个文件:

logs/
├── skywalking-api.log         # 当前日志(正在写入)
├── skywalking-api.log.1       # 第一轮转文件
└── skywalking-api.log.2       # 第二轮转文件
│
│  超过3个文件 → 最老的文件自动删除
│  skywalking-api.log → 满了 → 重命名为.1
│  新的skywalking-api.log → 继续写入

3.3 将Agent日志输出到应用日志

有时你希望Agent日志和应用日志混在一起,方便统一查看。可以通过修改config/log4j2.xml实现:

<!-- 修改log4j2.xml,将Console appender设为异步 -->
<Configuration status="WARN">
    <Appenders>
        <Console name="Console" target="SYSTEM_OUT">
            <PatternLayout pattern="%d %p %c - %m%n"/>
        </Console>
        <RollingFile name="RollingFile"
                     fileName="${sys:skywalking.log.dir}/${sys:skywalking.log.file.name}"
                     filePattern="${sys:skywalking.log.dir}/${sys:skywalking.log.file.name}.%i">
            <PatternLayout pattern="%d %p %c - %m%n"/>
            <SizeBasedTriggeringPolicy size="${sys:skywalking.log.max_file_size}"/>
            <DefaultRolloverStrategy max="${sys:skywalking.log.max_file_num}"/>
        </RollingFile>
    </Appenders>
    <Loggers>
        <Root level="${sys:skywalking.log.level}">
            <AppenderRef ref="Console"/>      <!-- 输出到控制台 -->
            <AppenderRef ref="RollingFile"/>  <!-- 输出到文件 -->
        </Root>
    </Loggers>
</Configuration>

4. 高级特性

4.1 Ignore Suffix——忽略特定后缀的请求

有些URL后缀是静态资源请求,追踪它们毫无意义:

# agent.config

# 忽略追踪的URL后缀(逗号分隔)
trace.ignore_path=${SW_TRACE_IGNORE_PATH:.css,.js,.html,.jpg,.png,.gif,.ico,.svg,.woff,.woff2,.ttf,.eot}

这就像基因改造液忽略了所有"路人甲"——只追踪有意义的动作,忽略走马观花的闲逛。

配置后,这些请求不会产生任何Trace数据:

# 不追踪的请求示例:
GET /static/css/style.css        → 忽略
GET /images/logo.png             → 忽略
GET /scripts/app.js              → 忽略

# 正常追踪的请求示例:
GET /api/users/123               → 追踪 ✓
POST /api/orders                 → 追踪 ✓
GET /health                      → 追踪 ✓(除非也加入忽略列表)

4.2 Correlation Context——跨进程上下文传播

有时候你需要在Trace中传播自定义的业务数据(如用户ID、订单号),SkyWalking提供了Correlation Context机制:

// 在代码中设置自定义上下文
import org.apache.skywalking.apm.toolkit.trace.TraceContext;

// 设置跨进程传播的上下文数据(最多3个键值对)
TraceContext.putCorrelation("userId", "user-12345");
TraceContext.putCorrelation("orderId", "order-67890");

// 在下游服务中获取
String userId = TraceContext.getCorrelation("userId");
String orderId = TraceContext.getCorrelation("orderId");

配置参数:

# agent.config

# Correlation Context最大数据量(最多传播几个键值对)
correlation.max=${SW_CORRELATION_MAX:3}

# 单个值的最大长度(字符数)
correlation.value_max_length=${SW_CORRELATION_VALUE_MAX_LENGTH:128}

这就像基因改造后超级英雄之间的加密通讯——通过Trace链路传播的业务信息,只有同一条追踪链上的服务才能读取。

4.3 异步追踪

在微服务中,异步处理非常常见——CompletableFuture、@Async、Reactive编程。追踪异步调用是APM领域最棘手的问题之一,就像追踪一个会瞬移的超级英雄——他消失了又出现在另一个地方,你怎么把前后联系起来?

SkyWalking的解决方案是异步Span

import org.apache.skywalking.apm.toolkit.trace.ActiveSpan;
import org.apache.skywalking.apm.toolkit.trace.TraceContext;

// 方式一:使用@Trace注解标记异步方法
@Trace
@Async
public void asyncProcessOrder(Order order) {
    // 这个异步方法会被自动追踪
    ActiveSpan.setTag("orderId", order.getId());
}

// 方式二:手动创建异步Span
public void processAsync() {
    // 获取当前Trace的SegmentRef
    Runnable task = TraceContext.capture(); // 捕获当前上下文
    
    CompletableFuture.runAsync(() -> {
        TraceContext.continue(task); // 在异步线程中恢复上下文
        try {
            // 异步处理逻辑...
            doSomething();
        } finally {
            TraceContext.stop(); // 结束异步Span
        }
    });
}

异步追踪的原理图:

┌──────────────────────────────────────────────────────────────────┐
│                异步追踪上下文传播原理                               │
│                                                                  │
│  主线程:  ┌─────SpanA─────┐                                      │
│           │               │ capture() → 保存上下文快照             │
│           │    ┌──────────┼─────────────────────┐                │
│           └────┘          │                     │                │
│                           │  异步线程            │                │
│                           │  continue() → 恢复   │                │
│                           │  ┌───SpanB──────┐   │                │
│                           │  │ 异步处理      │   │                │
│                           │  │ stop()→结束   │   │                │
│                           │  └──────────────┘   │                │
│                           └─────────────────────┘                │
│                                                                  │
│  SpanA和SpanB属于同一个Trace,通过上下文快照关联                    │
└──────────────────────────────────────────────────────────────────┘

4.4 Trace Limit——Span数量限制

一个Trace可能包含很多Span,但无限增长会导致数据膨胀:

# agent.config

# 单个Trace的最大Span数量
trace.limit=${SW_TRACE_LIMIT:500}

# 超过限制后,新Span会被丢弃(但Trace不会截断)
# 默认500,对于大多数场景足够

如果你的业务链路特别深(比如一个请求要调用20+个下游服务),可能需要调大这个值。

4.5 Force Trace——强制追踪条件

你可以配置在特定条件下强制追踪,不受采样率影响:

# agent.config

# 慢请求阈值(毫秒),超过此值的请求强制追踪
# -1 = 不强制追踪慢请求
trace.slow_threshold=${SW_TRACE_SLOW_THRESHOLD:-1}

不同服务可以设置不同的阈值——对核心业务设置严格的阈值,对非核心业务放宽:

# 核心支付服务:200ms就算慢
export SW_TRACE_SLOW_THRESHOLD=200

# 用户服务:500ms才算慢
export SW_TRACE_SLOW_THRESHOLD=500

5. 插件开发简介

如果内置插件和自定义增强插件都不够,你可以开发自己的Agent插件。SkyWalking提供了完整的插件开发框架:

┌──────────────────────────────────────────────────────────────────┐
│                  Agent插件开发核心概念                              │
│                                                                  │
│  1. ClassMatch:定义要拦截哪些类                                  │
│     ── NameMatch:精确匹配类名                                    │
│     ── PrefixMatch:前缀匹配                                      │
│     ── RegexMatch:正则匹配                                       │
│     ── AnnotationMatch:注解匹配                                  │
│                                                                  │
│  2. InstanceMethodIntercept:拦截实例方法                          │
│     ── beforeMethod:方法执行前                                   │
│     ── afterMethod:方法执行后                                    │
│     ── handleMethodException:方法异常时                          │
│                                                                  │
│  3. StaticMethodIntercept:拦截静态方法                            │
│     ── 同上三个拦截点                                             │
│                                                                  │
│  4. EnhanceTemplate:将ClassMatch和Intercept组合                  │
│     ── 定义拦截规则和拦截逻辑                                      │
│                                                                  │
│  完整开发流程在后续文章(053+)中详解                               │
└──────────────────────────────────────────────────────────────────┘

6. 配置速查表

把所有高级配置参数整理在一起,方便快速查阅:

# ==================== 采样配置 ====================
agent.sample_n_per_3_secs=${SW_AGENT_SAMPLE:N_PER_3_SECS:-1}
trace.slow_threshold=${SW_TRACE_SLOW_THRESHOLD:-1}
trace.limit=${SW_TRACE_LIMIT:500}

# ==================== 忽略配置 ====================
trace.ignore_path=${SW_TRACE_IGNORE_PATH:.css,.js,.html,.jpg,.png}
trace.operation_name_length_limit=${SW_TRACE_OPERATION_NAME_LENGTH_LIMIT:500}

# ==================== 上下文配置 ====================
correlation.max=${SW_CORRELATION_MAX:3}
correlation.value_max_length=${SW_CORRELATION_VALUE_MAX_LENGTH:128}

# ==================== 日志配置 ====================
logging.level=${SW_LOGGING_LEVEL:INFO}
logging.dir=${SW_LOGGING_DIR:}
logging.file_name=${SW_LOGGING_FILE_NAME:skywalking-api.log}
logging.max_file_size=${SW_LOGGING_MAX_FILE_SIZE:300000000}
logging.max_file_num=${SW_LOGGING_MAX_FILE_NUM:3}

# ==================== 网络配置 ====================
collector.grpc.max_message_size=${SW_COLLECTOR_GRPC_MAX_MESSAGE_SIZE:10485760}
collector.grpc.timeout=${SW_COLLECTOR_GRPC_TIMEOUT:30}

7. 小结

Agent的高级配置就像调教基因改造针的精度:

  • 插件三层架构:bootstrap(底层突变)、plugins(基础能力)、optional-plugins(高级能力)
  • 采样率:不是百分比,是每3秒追踪N个请求;慢请求和错误不受采样限制
  • 日志管理:WARN级别适合生产,自动轮转管理
  • 高级特性:ignore suffix过滤噪音、correlation context传播业务数据、异步追踪串联瞬移英雄
  • 自定义增强:XML配置即可追踪任意方法,无需开发插件

下一篇文章,我们将从Agent端转向OAP Server端——解读后端的部署与配置。基因改造针已经调教完毕,接下来要看看指挥中心的运作方式。


上一篇【第11篇】JavaAgent安装与配置:给应用植入可观测性的基因
下一篇【第13篇】Server部署详解:解读指挥中心的控制面板


Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐