1. 什么是 Skywalking
1.1 架构图

整体架构包含如下三个组成部分
- 探针 (agent) 负责进行数据的收集,包含了 Tracing 和 Metrics 的数据,agent 会被安装到服务所在的服务器上,以方便数据的获取。
- 可观测性分析平台 OAP(Observability Analysis Platform),接收探针发送的数据,并在内存中使用分析引擎 (Analysis Core) 进行数据的整合运算,然后将数据存储到对应的存储介质上,比如 Elasticsearch、MySQL 数据库、H2 数据库等。同时 OAP 还使用查询引擎 (Query Core) 提供HTTP查 询接口。
- Skywalking 提供单独的 UI 进行数据的查看,此时 UI 会调用 OAP 提供的接口,获取对应的数据然后进行展示。
主要概念
服务(service):服务是一个独立的应用(Application)
端点(Endpoint):服务对外提供的 Http 接口就是一个端点
实例(Instance):相同服务部署的多个节点就是实例
1.2 环境搭建
1.2.1 源码编译
官方地址 https://github.com/apache/skywalking 也可以使用我编译后带源码的地址 https://github.com/masteryourself-opensource/skywalking.git
打包完成后在 dist 目录得到产物 apache-skywalking-apm-bin.tar.gz 解压后得到 apache-skywalking-apm-bin
git clone https://github.com/masteryourself-opensource/skywalkinggit checkout -b masteryourself-v6.5.0 origin/masteryourself-v6.5.0cd skywalking/git submodule initgit submodule updatemvn clean package -Dmaven.test.skip
1.2.2 启动 OAP
OAP 服务的配置文件在 config/application.yml ,默认是 H2 数据库,可以在这里进行修改
1.2.3 启动 UI
UI 服务的配置文件在 webapp/webappp.yml 中,可以定义服务端口号,OAP 服务地址列表等
通过命令 sh bin/webappService.sh 启动
可以通过 sh startup.sh 同时启动 OAP 和 UI
1.3 属性覆盖
优先级顺序是:探针配置 > 系统配置 > 系统环境变量 > 配置文件中的值
1.3.1 系统配置
使用 skywalking. + 配置文件中的配置名作为系统配置项来进行覆盖
如想覆盖 agent.service_name 配置
-Dskywalking.agent.service_name=skywalking_mysql
1.3.2 探针配置
如想覆盖 agent.service_name 配置,特殊字符可以使用 '' 引号包裹
-javaagent:/path/to/skywalking-agent.jar=[option1]=[value1],[option2]=[value2]
1.3.3 系统环境变量
如想覆盖 agent.service_name 配置,只需要在环境变量中配置 SW_AGENT_NAME 属性即可
agent.service_name=${SW_AGENT_NAME:Your_ApplicationName}
2. SkyWalking 使用
2.1 Agent 目录
+-- agent # agent 目录+-- activations # 工具包apm-toolkit-log4j-1.x-activation.jarapm-toolkit-log4j-2.x-activation.jarapm-toolkit-logback-1.x-activation.jar...+-- bootstrap-plugins # 需要用 Bootstrap Classloader 加载的插件+-- config # 配置文件agent.config+-- plugins # 生效的插件包apm-dubbo-plugin.jarapm-feign-default-http-9.x.jarapm-httpClient-4.x-plugin.jar.....skywalking-agent.jar # 使用 -javaagent 指定的 agent 包
2.2 Agent 使用
在编译器 IDE 中启动
-javaagent:/Users/ruanrenzhao/environment/apache-skywalking-apm-bin/agent/skywalking-agent.jar
使用命令行启动
java -javaagent:/Users/ruanrenzhao/environment/apache-skywalking-apm-bin/agent/skywalking-agent.jar jar xxx.jar
在 Tomcat Web 容器中修改 tomcat/bin/catalina.sh 的第一行
CATALINA_OPTS="$CATALINA_OPTS -javaagent:/path/to/skywalking-agent/skywalking-agent.jar"; export CATALINA_OPTS
2.3 RocketBot 使用
2.3.1 仪表盘

仪表盘分为两大块
- 服务仪表盘,展示服务的调用情况
- 数据库仪表盘,展示数据库的响应时间等数据
选中服务仪表盘,有四个维度的统计数据可以进行查看
- 全局,查看全局接口的调用,包括全局响应时长的百分比,最慢的端点,服务的吞吐量等
- 服务,显示服务的响应时长、SLA、吞吐量等信息
- 端点,显示端点的响应时长、SLA、吞吐量等信息
- 实例,显示实例的响应时长、SLA、吞吐量等信息,还可以查看实例的JVM的GC信息、CPU信息、 内存信息
2.3.2 拓扑图

可以详细看到应用之间的调用关系,上图表示 user 调用了 Your_ApplicationName,Your_ApplicationName 调用了数据库2.3.3 追踪
在 SkyWalking 中,每一次用户发起一条请求,就可以视为一条追踪数据,每条追踪数据携带有一个 ID 值。追踪数据在追踪页面中可以进行查询
每条追踪记录有三种展示效果,列表,树结构,表格
点击每个 Span 可以查看详细的 Span 信息,如 SQL、异常堆栈等
2.4 工具包使用
2.4.1 引入 Jar 包
<!--skywalking trace工具包--><dependency><groupId>org.apache.skywalking</groupId><artifactId>apm-toolkit-trace</artifactId><version>6.5.0</version></dependency>
2.4.2 API 使用
使用 TraceContext.traceId() 可以打印出当前追踪的ID,方便在 RocketBot 中进行搜索
ActiveSpan 提供了三个方法进行信息的打印:
- error 方法会将本次调用变为失败状态,同时可以打印对应的堆栈信息和错误提示。
- info 方法打印 info 级别的信息。
debug 方法打印 debug 级别的信息。
@GetMapping("/plugin")public String plugin() {//使当前链路报错,并且提示报错信息ActiveSpan.error(new RuntimeException("Test-Error-Throwable"));//打印info信息ActiveSpan.info("Test-Info-Msg");// 打印debug信息ActiveSpan.debug("Test-debug-Msg");return TraceContext.traceId();}
2.4.3 查看追踪面板
异常堆栈有如下内容
事件类型为 error
- 调用方法时传递的异常类型
- 调用方法时的异常 message 信息
异常堆栈内容
2.5 查看增强后的字节码内容
Java 实时反编译工具 https://github.com/zifeihan/friday
git clone https://github.com/zifeihan/fridaymvn clean install -Dmaven.test.skipcd starter/targettar -zxvf friday-starter.tar.gzsh bin/run.sh
选择一个 Java 进程后,连上去后可以查看到实时运行的字节码文件
/** Decompiled with CFR 0.149.** Could not load the following classes:* org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ConstructorInter* org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance* org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstMethodsInter* org.masteryourself.tutorial.skywalking.demo.controller.DemoController* org.masteryourself.tutorial.skywalking.demo.controller.DemoController$auxiliary$9g06w93P* org.masteryourself.tutorial.skywalking.demo.controller.DemoController$auxiliary$pucJ4sy3* org.springframework.web.bind.annotation.GetMapping* org.springframework.web.bind.annotation.RequestMapping* org.springframework.web.bind.annotation.RestController*/package org.masteryourself.tutorial.skywalking.demo.controller;import java.lang.reflect.Method;import java.util.concurrent.Callable;import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ConstructorInter;import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstMethodsInter;import org.masteryourself.tutorial.skywalking.demo.controller.DemoController;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;@RestController@RequestMapping(value={"/demo"})public class DemoControllerimplements EnhancedInstance,EnhancedInstance {// 这里多了一个字段private volatile Object _$EnhancedClassField_ws;public static volatile /* synthetic */ InstMethodsInter delegate$o59nu91;public static volatile /* synthetic */ InstMethodsInter delegate$3p5b3r0;public static volatile /* synthetic */ ConstructorInter delegate$hut6vg1;private static final /* synthetic */ Method cachedValue$fzikR5Vm$epivfa1;public static volatile /* synthetic */ InstMethodsInter delegate$l1upa31;public static volatile /* synthetic */ InstMethodsInter delegate$72rosd1;public static volatile /* synthetic */ ConstructorInter delegate$bggua40;private static final /* synthetic */ Method cachedValue$tbOTwlWY$epivfa1;public DemoController() {this(null);delegate$bggua40.intercept((Object)this, new Object[0]);}private /* synthetic */ DemoController(auxiliary.pucJ4sy3 pucJ4sy32) {}@GetMapping(value={"/hello"})public String hello() {// 目标方法已经被代理return (String)delegate$l1upa31.intercept((Object)this, new Object[0], (Callable)new auxiliary.9g06w93P(this), cachedValue$tbOTwlWY$epivfa1);}private /* synthetic */ String hello$original$c0h8eDbn() {// 原方法会保留, 替换方法名称return "hello skywalking";}static {ClassLoader.getSystemClassLoader().loadClass("org.apache.skywalking.apm.dependencies.net.bytebuddy.dynamic.Nexus").getMethod("initialize", Class.class, Integer.TYPE).invoke(null, DemoController.class, -830093591);cachedValue$tbOTwlWY$epivfa1 = DemoController.class.getMethod("hello", new Class[0]);}final /* synthetic */ String hello$original$c0h8eDbn$accessor$tbOTwlWY() {return this.hello$original$c0h8eDbn();}}
