引言:当分布式系统遇见 "盲人摸象" 困境
在单体应用时代,我们排查问题就像在自己家里找东西,虽然偶尔也会找不到,但至少对整个空间了如指掌。而进入分布式系统时代,排查问题更像是在一个陌生的大型商场里找一串丢失的钥匙 ------ 你知道它就在某个地方,但完全不知道从何找起。
想象这样一个场景:用户投诉某个电商平台下单后长时间未收到确认信息。客服反馈给技术团队,前端工程师检查后发现接口调用超时,后端工程师查看服务日志未发现异常,数据库团队确认查询性能正常,运维团队表示服务器资源充足。每个环节看起来都没问题,但整个流程却失败了。这就是分布式系统的 "盲人摸象" 困境 ------ 每个团队只能看到自己负责的部分,无法把握全局。
SkyWalking 正是为解决这一困境而生的分布式追踪系统。它就像给分布式系统装上了 "透视镜" 和 "黑匣子",不仅能看到系统的整体运行状态,还能在出现问题时快速定位根因。本文将从理论到实践,全面解析 SkyWalking 的核心原理、架构设计、实战应用和高级特性,帮助你真正理解并掌握这一强大的分布式追踪工具。
一、SkyWalking 核心概念与价值定位
1.1 什么是 SkyWalking?
SkyWalking 是一个开源的分布式追踪系统,由华为工程师吴晟(现 Apache 基金会董事)发起,目前已成为 Apache 顶级项目。它主要用于微服务、云原生和容器化应用的可观测性分析,提供分布式追踪、服务网格(Service Mesh)遥测分析、度量聚合和可视化一体化解决方案。
简单来说,SkyWalking 能帮助我们回答这些关键问题:
- 一个请求在分布式系统中经过了哪些服务?
- 每个服务处理请求花费了多长时间?
- 哪个服务或组件是系统性能瓶颈?
- 当请求失败时,具体是在哪个环节出了问题?
- 系统整体的调用拓扑结构是怎样的?
1.2 SkyWalking 的核心价值
在分布式系统中,SkyWalking 的核心价值体现在三个方面:
- 问题定位:快速定位跨服务调用中的异常和性能瓶颈,减少故障排查时间
- 性能优化:通过分析调用链和性能指标,发现系统优化点
- 系统可视化:将抽象的分布式系统转化为直观的拓扑图和指标图表
- 容量规划:基于历史数据和趋势分析,为系统扩容提供决策依据
- 服务治理:识别不健康的服务实例,为服务熔断和降级提供数据支持
1.3 可观测性三支柱与 SkyWalking 的定位
现代分布式系统的可观测性(Observability)建立在三个支柱上:

- 追踪(Tracing):记录请求在分布式系统中的完整路径,关注单个请求的流转
- 度量(Metrics):对系统状态的数值化描述,关注聚合数据和趋势
- 日志(Logging):系统产生的离散事件记录,关注具体细节
SkyWalking 以分布式追踪为核心,同时整合了度量和日志功能,形成了一个完整的可观测性平台。与其他工具相比,SkyWalking 的特点是:
- 探针性能优异,对应用侵入性小
- 支持多种语言和框架
- 提供丰富的可视化界面
- 可扩展性强,支持自定义插件
- 对 Service Mesh 有良好支持
1.4 SkyWalking 与其他可观测性工具的对比
工具 | 特点 | 优势场景 | 不足 |
---|---|---|---|
SkyWalking | 全栈可观测性,性能优秀,国产开源 | 微服务、云原生应用 | 生态相对 Prometheus+Grafana 较小 |
Zipkin | 简单轻量,易于部署 | 中小规模分布式系统 | 功能相对简单,可视化较弱 |
Jaeger | CNCF 毕业项目,与 K8s 生态融合好 | Kubernetes 环境 | 对部分旧框架支持不够完善 |
Pinpoint | 字节码增强,无需代码侵入 | 无法修改代码的场景 | 插件开发相对复杂 |
Prometheus+Grafana | 度量监控强大,生态丰富 | 指标监控和告警 | 追踪功能需要额外集成 |
二、SkyWalking 核心原理深度解析
2.1 分布式追踪的基础:追踪上下文传播
分布式追踪的核心是如何将跨服务的请求关联起来,形成完整的调用链。SkyWalking 采用了与 OpenTelemetry 兼容的上下文传播机制,主要通过以下几个标识符实现:
- Trace ID:整个分布式调用链的唯一标识,一个 Trace ID 代表一个完整的请求链路
- Segment ID:每个服务处理请求时生成的片段 ID,一个 Trace 由多个 Segment 组成
- Span ID:每个 Segment 中具体操作的标识,代表一个具体的处理单元
当请求从一个服务传递到另一个服务时,这些标识符通过网络协议(如 HTTP 头、RPC 元数据)进行传递,从而将分散在不同服务的处理过程关联起来。

2.2 SkyWalking 的核心工作流程
SkyWalking 的工作流程可以分为四个主要阶段:

- 数据采集:通过 Agent 探针对应用进行字节码增强,自动生成追踪数据;同时支持手动埋点补充关键业务信息
- 数据传输:Agent 采集的数据通过 gRPC 或 HTTP 协议发送到 SkyWalking 后端(OAP Server)
- 数据存储:OAP Server 对数据进行分析和聚合后,存储到指定的存储介质(如 Elasticsearch)
- 数据展示:通过 SkyWalking UI 展示系统拓扑、调用链、性能指标等,并提供告警功能
2.3 字节码增强技术:SkyWalking 的 "无侵入" 秘诀
SkyWalking Agent 之所以能实现对应用的无侵入式监控,核心在于其采用了字节码增强技术。简单来说,就是在应用程序的类加载过程中,动态修改字节码,插入监控逻辑,而无需修改应用源代码。
字节码增强的工作流程:

SkyWalking 内置了对主流框架的增强器,如 Spring Boot、Dubbo、MyBatis、HttpClient 等,覆盖了大多数常见的调用场景。对于自定义框架或特殊场景,也可以开发自定义增强器。
2.4 SkyWalking 的数据模型
SkyWalking 定义了一套完整的数据模型来描述分布式系统的运行状态,核心模型包括:
- 服务(Service):具有相同功能的一组实例的集合,如订单服务、用户服务
- 服务实例(Service Instance):服务的具体运行实例,通常对应一个进程
- 端点(Endpoint):服务中可以被调用的具体接口或方法,如 HTTP 接口、RPC 方法
- 进程(Process):操作系统层面的进程,一个服务实例对应一个进程
- 追踪(Trace):一个请求在分布式系统中的完整调用路径
- 片段(Segment):追踪在单个服务实例中的部分
- 跨度(Span):片段中的一个具体操作,如一次数据库查询、一次 HTTP 调用
这些模型之间的关系如下:

2.5 OAP Server 的核心功能
SkyWalking OAP(Observability Analysis Platform)服务器是整个系统的核心,负责数据处理、分析和存储,主要功能包括:
- 数据接收:接收来自 Agent 和其他数据源的数据
- 数据解析:解析不同格式的输入数据
- 拓扑分析:根据调用关系自动构建服务拓扑图
- 指标计算:聚合计算各种性能指标(响应时间、吞吐量、错误率等)
- 数据存储:将处理后的数据存储到指定的存储介质
- 查询服务:提供查询接口供 UI 和其他系统使用
- 告警管理:根据预设规则判断是否触发告警
OAP Server 采用了模块化设计,不同功能通过插件实现,便于扩展和定制。
三、SkyWalking 环境搭建与基础配置
3.1 环境准备
在开始搭建 SkyWalking 之前,需要准备以下环境:
- JDK 17+(SkyWalking 9.x 及以上版本推荐)
- 操作系统:Linux、Windows 或 MacOS
- 存储介质:推荐使用 Elasticsearch 7.x 或 8.x
- 网络:确保 Agent、OAP Server 和 UI 之间的网络连通
3.2 搭建 Elasticsearch 存储
SkyWalking 支持多种存储介质,其中 Elasticsearch 是最常用的选择,因为它在处理时序数据和支持复杂查询方面表现优异。
使用 Docker 快速启动 Elasticsearch 8.11.3(最新稳定版):
bash
# 拉取镜像
docker pull elasticsearch:8.11.3
# 启动容器
docker run -d \
--name elasticsearch \
-p 9200:9200 \
-p 9300:9300 \
-e "discovery.type=single-node" \
-e "xpack.security.enabled=false" \
-e "ES_JAVA_OPTS=-Xms512m -Xmx512m" \
elasticsearch:8.11.3
验证 Elasticsearch 是否启动成功:
bash
curl http://localhost:9200
成功启动会返回类似以下的响应:
json
{
"name" : "3f1a91f8b6a",
"cluster_name" : "docker-cluster",
"cluster_uuid" : "3zH7x1a5Qv-5L7Z9y8YJ-Q",
"version" : {
"number" : "8.11.3",
"build_flavor" : "default",
"build_type" : "docker",
"build_hash" : "64cf052f3b56b10c041973289942cb37b108e6",
"build_date" : "2023-12-08T11:33:53.634979450Z",
"build_snapshot" : false,
"lucene_version" : "9.8.0",
"minimum_wire_compatibility_version" : "7.17.0",
"minimum_index_compatibility_version" : "7.0.0"
},
"tagline" : "You Know, for Search"
}
3.3 安装 SkyWalking OAP Server
下载并解压 SkyWalking 9.7.0(最新稳定版):
bash
# 下载
wget https://archive.apache.org/dist/skywalking/9.7.0/apache-skywalking-apm-9.7.0.tar.gz
# 解压
tar -zxvf apache-skywalking-apm-9.7.0.tar.gz
cd apache-skywalking-apm-bin
配置 OAP Server 使用 Elasticsearch 存储:
编辑config/application.yml
文件,修改存储配置:
yaml
storage:
selector: ${SW_STORAGE:elasticsearch}
elasticsearch:
namespace: ${SW_NAMESPACE:""}
clusterNodes: ${SW_STORAGE_ES_CLUSTER_NODES:localhost:9200}
protocol: ${SW_STORAGE_ES_HTTP_PROTOCOL:http}
connectTimeout: ${SW_STORAGE_ES_CONNECT_TIMEOUT:3000}
socketTimeout: ${SW_STORAGE_ES_SOCKET_TIMEOUT:30000}
responseTimeout: ${SW_STORAGE_ES_RESPONSE_TIMEOUT:15000}
numHttpClientThread: ${SW_STORAGE_ES_NUM_HTTP_CLIENT_THREAD:0}
user: ${SW_ES_USER:""}
password: ${SW_ES_PASSWORD:""}
# 其他配置保持默认
启动 OAP Server:
bash
# Linux/Mac
bin/oapService.sh
# Windows
bin/oapService.bat
OAP Server 启动成功后,会监听 11800 端口(gRPC)和 12800 端口(HTTP)。
3.4 启动 SkyWalking UI
SkyWalking UI 是一个基于 React 的前端应用,用于可视化展示监控数据。
启动 UI 服务:
bash
# Linux/Mac
bin/webappService.sh
# Windows
bin/webappService.bat
默认情况下,UI 会监听 8080 端口,并连接本地的 OAP Server(127.0.0.1:12800)。如果 OAP Server 部署在其他地址,需要修改webapp/application.yml
文件:
yaml
server:
port: 8080
spring:
cloud:
gateway:
routes:
- id: oap-route
uri: http://localhost:12800 # 修改为实际的OAP Server地址
predicates:
- Path=/graphql/**,/ui/**,/api/**,/analysis/**,/logs/**
启动成功后,访问http://localhost:8080
即可打开 SkyWalking UI 界面。
3.5 配置 SkyWalking Agent
SkyWalking Agent 是嵌入到应用中的探针,负责收集监控数据。
下载 Agent:
SkyWalking Agent 已经包含在之前下载的安装包中,位于agent
目录下。也可以单独下载:
bash
wget https://archive.apache.org/dist/skywalking/java-agent/8.16.0/apache-skywalking-java-agent-8.16.0.tgz
tar -zxvf apache-skywalking-java-agent-8.16.0.tgz
Agent 核心配置:
Agent 的主要配置文件是agent/config/agent.config
,关键配置项包括:
properties
# 应用名称(服务名称)
agent.service_name=${SW_AGENT_NAME:YourApplicationName}
# OAP Server地址
collector.backend_service=${SW_AGENT_COLLECTOR_BACKEND_SERVICES:127.0.0.1:11800}
# 采样率,1表示100%采样
agent.sample_n_per_3_secs=${SW_AGENT_SAMPLE:-1}
# 日志级别
logging.level=${SW_LOGGING_LEVEL:INFO}
# 插件配置,默认启用所有插件
plugin.mount=${SW_MOUNT_PLUGINS:}
3.6 在 Spring Boot 应用中集成 Agent
创建一个简单的 Spring Boot 应用:
首先,创建一个 Maven 项目,pom.xml
配置如下:
xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.2.0</version>
<relativePath/>
</parent>
<groupId>com.example</groupId>
<artifactId>skywalking-demo</artifactId>
<version>1.0.0</version>
<properties>
<java.version>17</java.version>
<lombok.version>1.18.30</lombok.version>
<springdoc.version>2.1.0</springdoc.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
<version>${springdoc.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
创建一个简单的控制器:
java
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import java.util.Random;
/**
* 演示控制器
*
* @author ken
*/
@Slf4j
@RestController
@RequestMapping("/demo")
@Tag(name = "演示接口", description = "用于SkyWalking演示的接口")
public class DemoController {
private final RestTemplate restTemplate = new RestTemplate();
private final Random random = new Random();
/**
* 简单的Hello接口
*
* @param name 名称
* @return 问候语
*/
@GetMapping("/hello/{name}")
@Operation(summary = "Hello接口", description = "返回简单的问候语")
public String hello(@PathVariable String name) {
log.info("收到hello请求,名称:{}", name);
// 模拟处理时间
try {
Thread.sleep(random.nextInt(200));
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
log.error("处理hello请求时发生中断", e);
}
return "Hello, " + name + "!";
}
/**
* 调用另一个接口的示例
*
* @param id ID参数
* @return 处理结果
*/
@GetMapping("/call/{id}")
@Operation(summary = "调用示例", description = "调用另一个接口的示例")
public String callAnother(@PathVariable Long id) {
log.info("收到call请求,ID:{}", id);
// 模拟调用另一个服务
String result = restTemplate.getForObject("http://localhost:8081/demo/process/" + id, String.class);
return "处理结果:" + result;
}
}
创建应用启动类:
java
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* 应用启动类
*
* @author ken
*/
@SpringBootApplication
public class SkywalkingDemoApplication {
public static void main(String[] args) {
SpringApplication.run(SkywalkingDemoApplication.class, args);
}
}
使用 Agent 启动应用:
bash
java -javaagent:/path/to/skywalking-agent/skywalking-agent.jar \
-Dskywalking.agent.service_name=demo-service \
-Dskywalking.collector.backend_service=localhost:11800 \
-jar target/skywalking-demo-1.0.0.jar
其中:
-javaagent
:指定 Agent 的路径-Dskywalking.agent.service_name
:设置服务名称-Dskywalking.collector.backend_service
:设置 OAP Server 地址
启动成功后,访问几次http://localhost:8080/demo/hello/world
接口,然后打开 SkyWalking UI(http://localhost:8080
),就可以看到服务的监控数据了。
四、SkyWalking 核心功能实战
4.1 服务拓扑图分析
服务拓扑图是 SkyWalking 最直观的功能之一,它能自动根据服务间的调用关系生成可视化的系统架构图。
查看服务拓扑图的步骤:
- 登录 SkyWalking UI
- 在左侧菜单中选择 "拓扑图"
- 选择时间范围(如最近 10 分钟)
- 点击 "刷新" 按钮
拓扑图会展示:
- 所有被监控的服务节点
- 服务之间的调用关系
- 调用的吞吐量(每秒请求数)
- 调用的响应时间
- 调用的错误率
通过拓扑图,我们可以快速了解:
- 系统由哪些服务组成
- 服务之间的依赖关系
- 哪些服务之间的交互频繁
- 哪些调用路径存在性能问题(红色表示响应时间长或错误率高)
4.2 分布式调用链追踪
当系统出现问题时,调用链追踪是定位问题的关键工具。SkyWalking 可以展示一个请求从开始到结束的完整路径,包括每个环节的处理时间。
查询调用链的步骤:
- 在 SkyWalking UI 左侧菜单中选择 "追踪"
- 设置查询条件(如服务名称、时间范围、是否包含错误等)
- 点击 "查询" 按钮
- 在结果列表中选择一个追踪记录查看详情
调用链详情展示:
- 每个服务的处理时间
- 每个 Span 的具体信息(如 HTTP 方法、URL、参数摘要)
- 异常信息(如果有)
- 标签信息(如数据库语句、缓存键等)
示例:分析一个慢查询
假设我们发现/demo/call/{id}
接口响应缓慢,通过调用链追踪发现:
demo-service
调用process-service
的/demo/process/{id}
接口耗时 2.3 秒- 在
process-service
中,ProcessService.process()
方法耗时 2.2 秒 - 进一步查看发现,
ProcessService
中的数据库查询耗时 2.1 秒
通过这个调用链,我们可以快速定位到性能瓶颈在process-service
的数据库查询上,而不是网络传输或其他环节。
4.3 性能指标监控
SkyWalking 提供了丰富的性能指标监控,帮助我们了解系统的运行状态。主要指标包括:
- 响应时间(Response Time):服务处理请求的时间,包括 P50、P90、P99 等百分位值
- 吞吐量(Throughput):单位时间内处理的请求数
- 错误率(Error Rate):错误请求占总请求的比例
- SLA(Service Level Agreement):服务可用性指标
查看性能指标的步骤:
- 在 SkyWalking UI 左侧菜单中选择 "仪表盘"
- 选择要查看的服务
- 选择时间范围
- 查看各项指标图表
通过性能指标,我们可以:
- 发现服务的性能趋势
- 比较不同服务的性能表现
- 识别性能异常(如响应时间突增、错误率上升)
- 评估系统的整体健康状况
4.4 日志集成与分析
SkyWalking 可以与应用日志集成,将日志与调用链关联起来,方便问题排查。
集成 Logback 日志框架:
- 添加 Logback 依赖:
xml
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.4.8</version>
</dependency>
- 创建
src/main/resources/logback-spring.xml
配置文件:
xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
<layout class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.TraceIdPatternLogbackLayout">
<Pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%tid] [%thread] %-5level %logger{36} - %msg%n</Pattern>
</layout>
</encoder>
</appender>
<!-- 输出到SkyWalking OAP的日志追加器 -->
<appender name="SKYWALKING_LOG" class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.log.GRPCLogClientAppender">
<encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
<layout class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.TraceIdPatternLogbackLayout">
<Pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%tid] [%thread] %-5level %logger{36} - %msg%n</Pattern>
</layout>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="CONSOLE" />
<appender-ref ref="SKYWALKING_LOG" />
</root>
</configuration>
- 添加 SkyWalking 日志工具包依赖:
xml
<dependency>
<groupId>org.apache.skywalking</groupId>
<artifactId>apm-toolkit-logback-1.x</artifactId>
<version>8.16.0</version>
</dependency>
配置完成后,应用日志中会自动包含TraceID
,并且日志会被发送到 SkyWalking OAP Server。在 SkyWalking UI 的 "日志" 菜单中,可以根据TraceID
查询与特定调用链相关的所有日志,实现日志与调用链的联动分析。
4.5 告警配置与使用
SkyWalking 支持基于各种指标设置告警规则,当指标超过阈值时会触发告警通知。
配置告警规则:
编辑 OAP Server 的config/alarm-settings.yml
文件,添加或修改告警规则:
yaml
rules:
# 服务响应时间告警
service_resp_time_rule:
metrics-name: service_resp_time
op: ">"
threshold: 1000
period: 10
count: 3
silence-period: 5
message: "服务 {name} 的响应时间超过1000ms,持续3个周期"
# 服务错误率告警
service_error_rate_rule:
metrics-name: service_error_rate
op: ">"
threshold: 0.05
period: 10
count: 2
silence-period: 5
message: "服务 {name} 的错误率超过5%,持续2个周期"
# 端点响应时间告警
endpoint_resp_time_rule:
metrics-name: endpoint_resp_time
op: ">"
threshold: 500
period: 10
count: 3
silence-period: 5
message: "端点 {name} 的响应时间超过500ms,持续3个周期"
# 告警通知器配置
notification-settings:
default:
# 钉钉通知器
dingtalk:
enabled: true
webhook: https://oapi.dingtalk.com/robot/send?access_token=your_token
secret: your_secret
message-type: TEXT
# 邮件通知器
email:
enabled: false
host: smtp.example.com
port: 587
username: alert@example.com
password: password
from: alert@example.com
to: admin@example.com
subject: "SkyWalking 告警通知"
配置说明:
metrics-name
:要监控的指标名称op
:比较运算符(>、<、>=、<=、==)threshold
:阈值period
:检查周期(分钟)count
:连续多少次超过阈值后触发告警silence-period
:告警沉默期,避免重复告警(分钟)message
:告警消息内容
修改配置后需要重启 OAP Server 生效。在 SkyWalking UI 的 "告警" 菜单中,可以查看所有触发的告警记录。
五、SkyWalking 高级特性与定制化
5.1 自定义埋点与增强
虽然 SkyWalking 的自动埋点已经覆盖了大部分场景,但在某些情况下,我们需要添加自定义埋点来跟踪特定的业务逻辑。
使用 SkyWalking 工具包进行自定义埋点:
- 添加工具包依赖:
xml
<dependency>
<groupId>org.apache.skywalking</groupId>
<artifactId>apm-toolkit-trace</artifactId>
<version>8.16.0</version>
</dependency>
- 在代码中添加自定义埋点:
java
import org.apache.skywalking.apm.toolkit.trace.ActiveSpan;
import org.apache.skywalking.apm.toolkit.trace.Trace;
import org.apache.skywalking.apm.toolkit.trace.TraceContext;
import org.springframework.stereotype.Service;
/**
* 自定义埋点示例服务
*
* @author ken
*/
@Service
public class CustomTraceService {
/**
* 使用@Trace注解标记需要追踪的方法
*
* @param orderId 订单ID
* @return 处理结果
*/
@Trace
public String processOrder(Long orderId) {
// 添加自定义标签
ActiveSpan.tag("orderId", orderId.toString());
try {
// 模拟业务处理
validateOrder(orderId);
calculatePrice(orderId);
saveOrder(orderId);
// 记录日志,包含TraceID
log.info("订单处理完成,订单ID:{},TraceID:{}",
orderId, TraceContext.traceId());
return "SUCCESS";
} catch (Exception e) {
// 标记Span为错误状态
ActiveSpan.error(e);
log.error("订单处理失败,订单ID:{}", orderId, e);
return "FAIL";
}
}
/**
* 子方法也会被追踪
*/
@Trace
private void validateOrder(Long orderId) {
// 模拟验证逻辑
ActiveSpan.tag("step", "validate");
}
/**
* 子方法也会被追踪
*/
@Trace
private void calculatePrice(Long orderId) {
// 模拟计算价格
ActiveSpan.tag("step", "calculate");
}
/**
* 子方法也会被追踪
*/
@Trace
private void saveOrder(Long orderId) {
// 模拟保存订单
ActiveSpan.tag("step", "save");
}
}
@Trace
注解会让 SkyWalking 对方法进行追踪,创建相应的 Span。ActiveSpan
类可以用来添加标签、记录错误等。通过自定义埋点,我们可以更细致地追踪业务流程,特别是核心业务逻辑的执行情况。
5.2 自定义指标与仪表盘
SkyWalking 允许我们定义自定义指标,并在 UI 中创建自定义仪表盘来展示这些指标。
创建自定义指标:
- 首先,在代码中使用 SkyWalking API 记录自定义指标:
java
import org.apache.skywalking.apm.toolkit.meter.MeterFactory;
import org.apache.skywalking.apm.toolkit.meter.api.Counter;
import org.apache.skywalking.apm.toolkit.meter.api.Gauge;
import org.apache.skywalking.apm.toolkit.meter.api.Histogram;
import org.springframework.stereotype.Service;
import java.util.concurrent.atomic.AtomicInteger;
/**
* 自定义指标服务
*
* @author ken
*/
@Service
public class CustomMetricService {
// 订单创建计数器
private final Counter orderCreateCounter = MeterFactory.counter("order.create.count")
.tag("status", "success")
.build();
// 订单支付计数器
private final Counter orderPayCounter = MeterFactory.counter("order.pay.count")
.tag("status", "success")
.build();
// 库存 gauge 指标
private final AtomicInteger inventory = new AtomicInteger(1000);
private final Gauge inventoryGauge = MeterFactory.gauge("product.inventory", inventory::get)
.tag("product", "phone")
.build();
// 订单金额直方图
private final Histogram orderAmountHistogram = MeterFactory.histogram("order.amount")
.tag("type", "normal")
.build();
/**
* 记录订单创建
*/
public void recordOrderCreate() {
orderCreateCounter.increment();
}
/**
* 记录订单支付
*/
public void recordOrderPay() {
orderPayCounter.increment();
}
/**
* 更新库存
*/
public void updateInventory(int amount) {
inventory.addAndGet(amount);
}
/**
* 记录订单金额
*/
public void recordOrderAmount(double amount) {
orderAmountHistogram.observe(amount);
}
}
-
在业务代码中使用这些指标:
@Service
public class OrderService {@Autowired private CustomMetricService metricService; public void createOrder(Order order) { // 业务逻辑... // 记录指标 metricService.recordOrderCreate(); metricService.recordOrderAmount(order.getAmount()); metricService.updateInventory(-order.getQuantity()); } public void payOrder(Long orderId) { // 业务逻辑... // 记录指标 metricService.recordOrderPay(); }
}
-
在 SkyWalking UI 中创建自定义仪表盘:
- 登录 SkyWalking UI
- 点击右上角的 "+" 号,选择 "创建仪表盘"
- 输入仪表盘名称和描述
- 点击 "添加图表",选择自定义指标
- 配置图表类型、时间范围等
- 保存仪表盘
通过自定义指标和仪表盘,我们可以监控业务层面的关键指标,如订单量、支付转化率、库存水平等,实现技术指标与业务指标的统一监控。
5.3 SkyWalking 插件开发
SkyWalking 的插件机制允许我们扩展其功能,支持更多的框架和组件。下面以开发一个简单的插件为例,介绍插件开发的基本流程。
插件开发步骤:
- 创建插件项目,
pom.xml
配置:
xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>skywalking-custom-plugin</artifactId>
<version>1.0.0</version>
<properties>
<skywalking.version>8.16.0</skywalking.version>
<java.version>17</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.apache.skywalking</groupId>
<artifactId>apm-agent-core</artifactId>
<version>${skywalking.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.skywalking</groupId>
<artifactId>apm-util</artifactId>
<version>${skywalking.version}</version>
<scope>provided</scope>
</dependency>
<!-- 被增强的目标框架依赖 -->
<dependency>
<groupId>com.example</groupId>
<artifactId>custom-framework</artifactId>
<version>1.0.0</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
-
创建增强类:
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.matcher.ElementMatcher;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
import static net.bytebuddy.matcher.ElementMatchers.named;
import static org.apache.skywalking.apm.agent.core.plugin.match.NameMatch.byName;/**
-
自定义框架插件定义
-
@author ken
*/
public class CustomFrameworkPlugin extends ClassInstanceMethodsEnhancePluginDefine {/**
- 定义需要增强的类
*/
@Override
protected ClassMatch enhanceClass() {
// 匹配com.example.framework.CustomService类
return byName("com.example.framework.CustomService");
}
/**
- 定义构造方法拦截点
*/
@Override
public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
return new ConstructorInterceptPoint[0];
}
/**
-
定义实例方法拦截点
*/
@Override
public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
return new InstanceMethodsInterceptPoint[]{
new InstanceMethodsInterceptPoint() {
@Override
public ElementMatcher<MethodDescription> getMethodsMatcher() {
// 匹配execute方法
return named("execute");
}@Override public String getMethodsInterceptor() { // 拦截器类 return "com.example.plugin.CustomServiceInterceptor"; } @Override public boolean isOverrideArgs() { return false; } }
};
}
}
- 定义需要增强的类
-
-
创建拦截器类:
import org.apache.skywalking.apm.agent.core.context.ContextCarrier;
import org.apache.skywalking.apm.agent.core.context.ContextManager;
import org.apache.skywalking.apm.agent.core.context.tag.Tags;
import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan;
import org.apache.skywalking.apm.agent.core.context.trace.SpanLayer;
import org.apache.skywalking.apm.agent.core.interceptor.enhance.EnhancedInstance;
import org.apache.skywalking.apm.agent.core.interceptor.enhance.InstanceMethodsAroundInterceptor;
import org.apache.skywalking.apm.agent.core.interceptor.enhance.MethodInterceptResult;
import org.apache.skywalking.apm.network.trace.component.ComponentsDefine;import java.lang.reflect.Method;
/**
-
自定义服务拦截器
-
@author ken
*/
public class CustomServiceInterceptor implements InstanceMethodsAroundInterceptor {@Override
public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments,
Class<?>[] argumentsTypes, MethodInterceptResult result) throws Throwable {
// 创建一个新的Span
AbstractSpan span = ContextManager.createLocalSpan("CustomService.execute()");// 设置组件类型 span.setComponent(ComponentsDefine.CUSTOM); // 设置层级为中间件 SpanLayer.asMiddleware(span); // 添加标签 if (allArguments != null && allArguments.length > 0) { Tags.ARGS.set(span, String.valueOf(allArguments[0])); }
}
@Override
public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments,
Class<?>[] argumentsTypes, Object ret) throws Throwable {
// 结束Span
ContextManager.stopSpan();
return ret;
}@Override
public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments,
Class<?>[] argumentsTypes, Throwable t) {
// 记录异常
ContextManager.activeSpan().log(t);
}
}
-
-
创建插件描述文件:
在src/main/resources
目录下创建skywalking-plugin.def
文件:
custom-framework-plugin=com.example.plugin.CustomFrameworkPlugin
-
打包插件:
mvn clean package
-
安装插件:
将生成的 jar 包复制到 SkyWalking Agent 的plugins
目录下,重启应用即可生效。
通过开发自定义插件,我们可以扩展 SkyWalking 的监控能力,使其支持特定的框架、组件或业务逻辑,满足个性化的监控需求。
5.4 SkyWalking 与 Kubernetes 集成
在云原生环境中,SkyWalking 可以与 Kubernetes 无缝集成,实现对容器化应用的全面监控。
在 Kubernetes 中部署 SkyWalking:
- 创建命名空间:
yaml
apiVersion: v1
kind: Namespace
metadata:
name: skywalking
- 部署 Elasticsearch:
yaml
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: elasticsearch
namespace: skywalking
spec:
serviceName: elasticsearch
replicas: 1
selector:
matchLabels:
app: elasticsearch
template:
metadata:
labels:
app: elasticsearch
spec:
containers:
- name: elasticsearch
image: elasticsearch:8.11.3
ports:
- containerPort: 9200
name: rest
protocol: TCP
- containerPort: 9300
name: inter-node
protocol: TCP
env:
- name: discovery.type
value: single-node
- name: xpack.security.enabled
value: "false"
- name: ES_JAVA_OPTS
value: -Xms512m -Xmx512m
resources:
limits:
cpu: 1
memory: 1Gi
requests:
cpu: 500m
memory: 512Mi
volumeMounts:
- name: data
mountPath: /usr/share/elasticsearch/data
volumeClaimTemplates:
- metadata:
name: data
spec:
accessModes: [ "ReadWriteOnce" ]
resources:
requests:
storage: 10Gi
---
apiVersion: v1
kind: Service
metadata:
name: elasticsearch
namespace: skywalking
spec:
selector:
app: elasticsearch
ports:
- port: 9200
targetPort: 9200
clusterIP: None
- 部署 SkyWalking OAP Server:
yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: skywalking-oap
namespace: skywalking
spec:
replicas: 1
selector:
matchLabels:
app: skywalking-oap
template:
metadata:
labels:
app: skywalking-oap
spec:
containers:
- name: skywalking-oap
image: apache/skywalking-oap-server:9.7.0
ports:
- containerPort: 11800
name: grpc
- containerPort: 12800
name: rest
env:
- name: SW_STORAGE
value: elasticsearch
- name: SW_STORAGE_ES_CLUSTER_NODES
value: elasticsearch:9200
- name: JAVA_OPTS
value: -Xms512m -Xmx512m
---
apiVersion: v1
kind: Service
metadata:
name: skywalking-oap
namespace: skywalking
spec:
selector:
app: skywalking-oap
ports:
- port: 11800
targetPort: 11800
name: grpc
- port: 12800
targetPort: 12800
name: rest
- 部署 SkyWalking UI:
yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: skywalking-ui
namespace: skywalking
spec:
replicas: 1
selector:
matchLabels:
app: skywalking-ui
template:
metadata:
labels:
app: skywalking-ui
spec:
containers:
- name: skywalking-ui
image: apache/skywalking-ui:9.7.0
ports:
- containerPort: 8080
env:
- name: SW_OAP_ADDRESS
value: http://skywalking-oap:12800
---
apiVersion: v1
kind: Service
metadata:
name: skywalking-ui
namespace: skywalking
spec:
selector:
app: skywalking-ui
ports:
- port: 80
targetPort: 8080
type: NodePort
- 在 Kubernetes 中部署应用时集成 SkyWalking Agent:
yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: demo-service
spec:
replicas: 1
selector:
matchLabels:
app: demo-service
template:
metadata:
labels:
app: demo-service
spec:
initContainers:
- name: init-agent
image: busybox:1.35
command:
- sh
- -c
- wget -q -O /skywalking/agent.tar.gz https://archive.apache.org/dist/skywalking/java-agent/8.16.0/apache-skywalking-java-agent-8.16.0.tgz && tar -zxf /skywalking/agent.tar.gz -C /skywalking
volumeMounts:
- name: skywalking-agent
mountPath: /skywalking
containers:
- name: demo-service
image: demo-service:1.0.0
ports:
- containerPort: 8080
env:
- name: JAVA_OPTS
value: >-
-javaagent:/skywalking/agent/skywalking-agent.jar
-Dskywalking.agent.service_name=demo-service
-Dskywalking.collector.backend_service=skywalking-oap.skywalking:11800
volumeMounts:
- name: skywalking-agent
mountPath: /skywalking
volumes:
- name: skywalking-agent
emptyDir: {}
通过这种方式,我们可以在 Kubernetes 环境中实现 SkyWalking 的完整部署,并对容器化应用进行全面监控。SkyWalking 能够自动识别 Kubernetes 中的服务和实例,提供与容器平台深度集成的监控能力。
六、SkyWalking 性能优化与最佳实践
6.1 Agent 性能优化
SkyWalking Agent 作为嵌入在应用中的组件,其性能对整个系统有直接影响。以下是一些优化 Agent 性能的建议:
-
合理设置采样率:
- 高流量系统可以降低采样率(如 1%),减少数据量
- 关键业务或调试期间可以提高采样率(如 100%)
- 配置方式:
agent.sample_n_per_3_secs=1
(每 3 秒采样 1 个请求)
-
禁用不必要的插件:
- SkyWalking 默认启用所有插件,对于不需要的插件可以禁用
- 配置方式:
plugin.mount=!mysql,!redis
(禁用 mysql 和 redis 插件)
-
调整缓存大小:
- 对于高并发系统,可以适当增大 Agent 的缓存
- 配置方式:
agent.buffer_size=30000
(设置缓存大小为 30000)
-
异步报告数据:
- 确保 Agent 使用异步方式向 OAP Server 报告数据
- 配置方式:
agent.force_tls=false
(禁用 TLS,提高传输效率)
-
合理设置批量发送参数:
-
调整批量发送的大小和间隔,平衡实时性和性能
-
配置方式: plaintext
agent.batch_size=1000 agent.batch_interval=3000
-
6.2 OAP Server 性能优化
OAP Server 作为数据处理和分析的核心,其性能优化同样重要:
-
集群部署:
- 对于大规模系统,OAP Server 应采用集群部署,分担负载
- 配置方式:通过
cluster
配置项设置集群模式(如 zookeeper、kubernetes)
-
调整 JVM 参数:
- 根据服务器配置合理分配内存,避免 OOM 或 GC 问题
- 推荐配置:
-Xms4g -Xmx8g -XX:+UseG1GC -XX:MaxGCPauseMillis=200
-
优化存储配置:
- 使用性能更好的存储介质(如 Elasticsearch 集群)
- 调整索引生命周期管理,自动清理过期数据
- 配置方式:在
application.yml
中设置storage.elasticsearch.indexTTL
-
水平扩展:
- 根据数据量和查询压力,增加 OAP Server 实例数量
- 确保存储层也能相应扩展
-
优化线程池配置:
- 根据 CPU 核心数调整处理线程池大小
- 配置方式:在
application.yml
中调整core.default.workers
6.3 存储优化
存储是 SkyWalking 性能的关键瓶颈之一,合理的存储优化可以显著提升系统性能:
-
选择合适的存储介质:
- 中小规模系统:可以使用 MySQL 或 TiDB
- 大规模系统:推荐使用 Elasticsearch 集群
- 超大规模系统:考虑使用专门的时序数据库(如 InfluxDB、TimescaleDB)
-
Elasticsearch 优化:
- 增加数据节点数量,提高存储和查询性能
- 合理设置分片和副本数量(推荐分片数 = 数据节点数)
- 配置索引生命周期管理(ILM),自动删除过期数据
- 调整刷新间隔(
index.refresh_interval
),平衡实时性和性能
-
数据保留策略:
-
根据业务需求设置不同数据的保留时间
-
配置方式: yaml
storage: elasticsearch: traceDataTTL: 7 # 追踪数据保留7天 metricsDataTTL: 30 # 指标数据保留30天 logDataTTL: 15 # 日志数据保留15天
-
-
定期优化:
- 定期执行存储优化操作(如 ES 的 force merge)
- 监控存储性能指标,及时扩容
6.4 生产环境最佳实践
在生产环境中使用 SkyWalking,建议遵循以下最佳实践:
-
分环境部署:
- 开发、测试、生产环境使用独立的 SkyWalking 部署
- 生产环境配置应更注重性能和稳定性
-
渐进式接入:
- 初次接入时,可以先选择非核心服务进行试点
- 逐步扩大监控范围,观察系统性能影响
-
完善的监控告警:
- 不仅监控业务系统,也要监控 SkyWalking 自身
- 设置关键指标的告警阈值,及时发现问题
-
安全配置:
- 生产环境应启用 TLS 加密传输
- 限制 UI 和 API 的访问权限
- 敏感数据脱敏处理
-
定期备份:
- 定期备份 SkyWalking 的配置和数据
- 制定灾难恢复计划
-
持续优化:
- 定期 review 监控数据,优化系统性能
- 关注 SkyWalking 新版本,及时升级获取新功能和性能优化
-
文档和培训:
- 建立 SkyWalking 使用文档
- 对开发和运维人员进行培训,提高问题排查效率
七、总结与展望
SkyWalking 作为一款优秀的开源分布式追踪系统,为我们解决分布式系统的可观测性问题提供了全面的解决方案。从核心原理来看,它通过字节码增强技术实现了对应用的无侵入式监控,通过分布式追踪上下文传播将分散的服务调用关联起来,形成完整的调用链。
在功能上,SkyWalking 不仅提供了基础的服务拓扑图和调用链追踪,还整合了性能指标监控、日志分析和告警功能,形成了一个完整的可观测性平台。通过本文的介绍,我们了解了 SkyWalking 的核心概念、工作原理、环境搭建、功能使用以及高级特性。
从实践角度来看,SkyWalking 的优势在于:
- 对应用的侵入性小,部署和使用简单
- 性能优秀,对系统的影响小
- 支持多种语言和框架,兼容性好
- 提供丰富的可视化界面,易于理解和使用
- 可扩展性强,支持自定义埋点、指标和插件
掌握 SkyWalking 不仅能帮助我们快速定位分布式系统中的问题,还能让我们更深入地理解系统的运行状态,为系统优化和架构演进提供数据支持。希望本文能成为你学习和使用 SkyWalking 的有益指南,让你在分布式系统的复杂世界中,拥有一双 "透视" 的眼睛。