从 0 到 1 精通 SkyWalking:分布式系统的 “透视镜“ 技术全解析
引言:当分布式系统遇见 "盲人摸象" 困境
在单体应用时代,我们排查问题就像在自己家里找东西,虽然偶尔也会找不到,但至少对整个空间了如指掌。而进入分布式系统时代,排查问题更像是在一个陌生的大型商场里找一串丢失的钥匙 —— 你知道它就在某个地方,但完全不知道从何找起。
想象这样一个场景:用户投诉某个电商平台下单后长时间未收到确认信息。客服反馈给技术团队,前端工程师检查后发现接口调用超时,后端工程师查看服务日志未发现异常,数据库团队确认查询性能正常,运维团队表示服务器资源充足。每个环节看起来都没问题,但整个流程却失败了。这就是分布式系统的 "盲人摸象" 困境 —— 每个团队只能看到自己负责的部分,无法把握全局。
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: 8080spring:cloud:gateway:routes:- id: oap-routeuri: 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_timeop: ">"threshold: 1000period: 10count: 3silence-period: 5message: "服务 {name} 的响应时间超过1000ms,持续3个周期"# 服务错误率告警service_error_rate_rule:metrics-name: service_error_rateop: ">"threshold: 0.05period: 10count: 2silence-period: 5message: "服务 {name} 的错误率超过5%,持续2个周期"# 端点响应时间告警endpoint_resp_time_rule:metrics-name: endpoint_resp_timeop: ">"threshold: 500period: 10count: 3silence-period: 5message: "端点 {name} 的响应时间超过500ms,持续3个周期"# 告警通知器配置
notification-settings:default:# 钉钉通知器dingtalk:enabled: truewebhook: https://oapi.dingtalk.com/robot/send?access_token=your_tokensecret: your_secretmessage-type: TEXT# 邮件通知器email:enabled: falsehost: smtp.example.comport: 587username: alert@example.compassword: passwordfrom: alert@example.comto: admin@example.comsubject: "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 处理结果*/@Tracepublic String processOrder(Long orderId) {// 添加自定义标签ActiveSpan.tag("orderId", orderId.toString());try {// 模拟业务处理validateOrder(orderId);calculatePrice(orderId);saveOrder(orderId);// 记录日志,包含TraceIDlog.info("订单处理完成,订单ID:{},TraceID:{}", orderId, TraceContext.traceId());return "SUCCESS";} catch (Exception e) {// 标记Span为错误状态ActiveSpan.error(e);log.error("订单处理失败,订单ID:{}", orderId, e);return "FAIL";}}/*** 子方法也会被追踪*/@Traceprivate void validateOrder(Long orderId) {// 模拟验证逻辑ActiveSpan.tag("step", "validate");}/*** 子方法也会被追踪*/@Traceprivate void calculatePrice(Long orderId) {// 模拟计算价格ActiveSpan.tag("step", "calculate");}/*** 子方法也会被追踪*/@Traceprivate 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 {@Autowiredprivate 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 {/*** 定义需要增强的类*/@Overrideprotected ClassMatch enhanceClass() {// 匹配com.example.framework.CustomService类return byName("com.example.framework.CustomService");}/*** 定义构造方法拦截点*/@Overridepublic ConstructorInterceptPoint[] getConstructorsInterceptPoints() {return new ConstructorInterceptPoint[0];}/*** 定义实例方法拦截点*/@Overridepublic InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {return new InstanceMethodsInterceptPoint[]{new InstanceMethodsInterceptPoint() {@Overridepublic ElementMatcher<MethodDescription> getMethodsMatcher() {// 匹配execute方法return named("execute");}@Overridepublic String getMethodsInterceptor() {// 拦截器类return "com.example.plugin.CustomServiceInterceptor";}@Overridepublic 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 {@Overridepublic void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments,Class<?>[] argumentsTypes, MethodInterceptResult result) throws Throwable {// 创建一个新的SpanAbstractSpan 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]));}}@Overridepublic Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments,Class<?>[] argumentsTypes, Object ret) throws Throwable {// 结束SpanContextManager.stopSpan();return ret;}@Overridepublic 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: elasticsearchnamespace: skywalking
spec:serviceName: elasticsearchreplicas: 1selector:matchLabels:app: elasticsearchtemplate:metadata:labels:app: elasticsearchspec:containers:- name: elasticsearchimage: elasticsearch:8.11.3ports:- containerPort: 9200name: restprotocol: TCP- containerPort: 9300name: inter-nodeprotocol: TCPenv:- name: discovery.typevalue: single-node- name: xpack.security.enabledvalue: "false"- name: ES_JAVA_OPTSvalue: -Xms512m -Xmx512mresources:limits:cpu: 1memory: 1Girequests:cpu: 500mmemory: 512MivolumeMounts:- name: datamountPath: /usr/share/elasticsearch/datavolumeClaimTemplates:- metadata:name: dataspec:accessModes: [ "ReadWriteOnce" ]resources:requests:storage: 10Gi
---
apiVersion: v1
kind: Service
metadata:name: elasticsearchnamespace: skywalking
spec:selector:app: elasticsearchports:- port: 9200targetPort: 9200clusterIP: None
- 部署 SkyWalking OAP Server:
yaml
apiVersion: apps/v1
kind: Deployment
metadata:name: skywalking-oapnamespace: skywalking
spec:replicas: 1selector:matchLabels:app: skywalking-oaptemplate:metadata:labels:app: skywalking-oapspec:containers:- name: skywalking-oapimage: apache/skywalking-oap-server:9.7.0ports:- containerPort: 11800name: grpc- containerPort: 12800name: restenv:- name: SW_STORAGEvalue: elasticsearch- name: SW_STORAGE_ES_CLUSTER_NODESvalue: elasticsearch:9200- name: JAVA_OPTSvalue: -Xms512m -Xmx512m
---
apiVersion: v1
kind: Service
metadata:name: skywalking-oapnamespace: skywalking
spec:selector:app: skywalking-oapports:- port: 11800targetPort: 11800name: grpc- port: 12800targetPort: 12800name: rest
- 部署 SkyWalking UI:
yaml
apiVersion: apps/v1
kind: Deployment
metadata:name: skywalking-uinamespace: skywalking
spec:replicas: 1selector:matchLabels:app: skywalking-uitemplate:metadata:labels:app: skywalking-uispec:containers:- name: skywalking-uiimage: apache/skywalking-ui:9.7.0ports:- containerPort: 8080env:- name: SW_OAP_ADDRESSvalue: http://skywalking-oap:12800
---
apiVersion: v1
kind: Service
metadata:name: skywalking-uinamespace: skywalking
spec:selector:app: skywalking-uiports:- port: 80targetPort: 8080type: NodePort
- 在 Kubernetes 中部署应用时集成 SkyWalking Agent:
yaml
apiVersion: apps/v1
kind: Deployment
metadata:name: demo-service
spec:replicas: 1selector:matchLabels:app: demo-servicetemplate:metadata:labels:app: demo-servicespec:initContainers:- name: init-agentimage: busybox:1.35command:- 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 /skywalkingvolumeMounts:- name: skywalking-agentmountPath: /skywalkingcontainers:- name: demo-serviceimage: demo-service:1.0.0ports:- containerPort: 8080env:- name: JAVA_OPTSvalue: >--javaagent:/skywalking/agent/skywalking-agent.jar-Dskywalking.agent.service_name=demo-service-Dskywalking.collector.backend_service=skywalking-oap.skywalking:11800volumeMounts:- name: skywalking-agentmountPath: /skywalkingvolumes:- name: skywalking-agentemptyDir: {}
通过这种方式,我们可以在 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 的有益指南,让你在分布式系统的复杂世界中,拥有一双 "透视" 的眼睛。