1. 什么是 Skywalking

1.1 架构图

image.png

整体架构包含如下三个组成部分

  1. 探针 (agent) 负责进行数据的收集,包含了 Tracing 和 Metrics 的数据,agent 会被安装到服务所在的服务器上,以方便数据的获取。
  2. 可观测性分析平台 OAP(Observability Analysis Platform),接收探针发送的数据,并在内存中使用分析引擎 (Analysis Core) 进行数据的整合运算,然后将数据存储到对应的存储介质上,比如 Elasticsearch、MySQL 数据库、H2 数据库等。同时 OAP 还使用查询引擎 (Query Core) 提供HTTP查 询接口。
  3. 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

  1. git clone https://github.com/masteryourself-opensource/skywalking
  2. git checkout -b masteryourself-v6.5.0 origin/masteryourself-v6.5.0
  3. cd skywalking/
  4. git submodule init
  5. git submodule update
  6. mvn clean package -Dmaven.test.skip

1.2.2 启动 OAP

OAP 服务的配置文件在 config/application.yml ,默认是 H2 数据库,可以在这里进行修改

通过命令 sh bin/oapService.sh 启动

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 配置

  1. -Dskywalking.agent.service_name=skywalking_mysql

1.3.2 探针配置

如想覆盖 agent.service_name 配置,特殊字符可以使用 '' 引号包裹

  1. -javaagent:/path/to/skywalking-agent.jar=[option1]=[value1],[option2]=[value2]

1.3.3 系统环境变量

如想覆盖 agent.service_name 配置,只需要在环境变量中配置 SW_AGENT_NAME 属性即可

  1. agent.service_name=${SW_AGENT_NAME:Your_ApplicationName}

2. SkyWalking 使用

2.1 Agent 目录

  1. +-- agent # agent 目录
  2. +-- activations # 工具包
  3. apm-toolkit-log4j-1.x-activation.jar
  4. apm-toolkit-log4j-2.x-activation.jar
  5. apm-toolkit-logback-1.x-activation.jar
  6. ...
  7. +-- bootstrap-plugins # 需要用 Bootstrap Classloader 加载的插件
  8. +-- config # 配置文件
  9. agent.config
  10. +-- plugins # 生效的插件包
  11. apm-dubbo-plugin.jar
  12. apm-feign-default-http-9.x.jar
  13. apm-httpClient-4.x-plugin.jar
  14. .....
  15. skywalking-agent.jar # 使用 -javaagent 指定的 agent 包

2.2 Agent 使用

在编译器 IDE 中启动
image.png

  1. -javaagent:/Users/ruanrenzhao/environment/apache-skywalking-apm-bin/agent/skywalking-agent.jar

使用命令行启动

  1. java -javaagent:/Users/ruanrenzhao/environment/apache-skywalking-apm-bin/agent/skywalking-agent.jar jar xxx.jar

在 Tomcat Web 容器中修改 tomcat/bin/catalina.sh 的第一行

  1. CATALINA_OPTS="$CATALINA_OPTS -javaagent:/path/to/skywalking-agent/skywalking-agent.jar"; export CATALINA_OPTS

2.3 RocketBot 使用

2.3.1 仪表盘

image.png

仪表盘分为两大块

  1. 服务仪表盘,展示服务的调用情况
  2. 数据库仪表盘,展示数据库的响应时间等数据

选中服务仪表盘,有四个维度的统计数据可以进行查看

  1. 全局,查看全局接口的调用,包括全局响应时长的百分比,最慢的端点,服务的吞吐量等
  2. 服务,显示服务的响应时长、SLA、吞吐量等信息
  3. 端点,显示端点的响应时长、SLA、吞吐量等信息
  4. 实例,显示实例的响应时长、SLA、吞吐量等信息,还可以查看实例的JVM的GC信息、CPU信息、 内存信息

    2.3.2 拓扑图

    image.png
    可以详细看到应用之间的调用关系,上图表示 user 调用了 Your_ApplicationName,Your_ApplicationName 调用了数据库

    2.3.3 追踪

    在 SkyWalking 中,每一次用户发起一条请求,就可以视为一条追踪数据,每条追踪数据携带有一个 ID 值。追踪数据在追踪页面中可以进行查询

每条追踪记录有三种展示效果,列表,树结构,表格

点击每个 Span 可以查看详细的 Span 信息,如 SQL、异常堆栈等
image.png

2.4 工具包使用

2.4.1 引入 Jar 包

  1. <!--skywalking trace工具包-->
  2. <dependency>
  3. <groupId>org.apache.skywalking</groupId>
  4. <artifactId>apm-toolkit-trace</artifactId>
  5. <version>6.5.0</version>
  6. </dependency>

2.4.2 API 使用

使用 TraceContext.traceId() 可以打印出当前追踪的ID,方便在 RocketBot 中进行搜索

ActiveSpan 提供了三个方法进行信息的打印:

  1. error 方法会将本次调用变为失败状态,同时可以打印对应的堆栈信息和错误提示。
  2. info 方法打印 info 级别的信息。
  3. debug 方法打印 debug 级别的信息。

    1. @GetMapping("/plugin")
    2. public String plugin() {
    3. //使当前链路报错,并且提示报错信息
    4. ActiveSpan.error(new RuntimeException("Test-Error-Throwable"));
    5. //打印info信息
    6. ActiveSpan.info("Test-Info-Msg");
    7. // 打印debug信息
    8. ActiveSpan.debug("Test-debug-Msg");
    9. return TraceContext.traceId();
    10. }

    2.4.3 查看追踪面板

    异常堆栈有如下内容

  4. 事件类型为 error

  5. 调用方法时传递的异常类型
  6. 调用方法时的异常 message 信息

异常堆栈内容
image.png

info 信息和 debug 信息展示如下
image.png

2.5 查看增强后的字节码内容

Java 实时反编译工具 https://github.com/zifeihan/friday

  1. git clone https://github.com/zifeihan/friday
  2. mvn clean install -Dmaven.test.skip
  3. cd starter/target
  4. tar -zxvf friday-starter.tar.gz
  5. sh bin/run.sh

选择一个 Java 进程后,连上去后可以查看到实时运行的字节码文件

  1. /*
  2. * Decompiled with CFR 0.149.
  3. *
  4. * Could not load the following classes:
  5. * org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ConstructorInter
  6. * org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance
  7. * org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstMethodsInter
  8. * org.masteryourself.tutorial.skywalking.demo.controller.DemoController
  9. * org.masteryourself.tutorial.skywalking.demo.controller.DemoController$auxiliary$9g06w93P
  10. * org.masteryourself.tutorial.skywalking.demo.controller.DemoController$auxiliary$pucJ4sy3
  11. * org.springframework.web.bind.annotation.GetMapping
  12. * org.springframework.web.bind.annotation.RequestMapping
  13. * org.springframework.web.bind.annotation.RestController
  14. */
  15. package org.masteryourself.tutorial.skywalking.demo.controller;
  16. import java.lang.reflect.Method;
  17. import java.util.concurrent.Callable;
  18. import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ConstructorInter;
  19. import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
  20. import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstMethodsInter;
  21. import org.masteryourself.tutorial.skywalking.demo.controller.DemoController;
  22. import org.springframework.web.bind.annotation.GetMapping;
  23. import org.springframework.web.bind.annotation.RequestMapping;
  24. import org.springframework.web.bind.annotation.RestController;
  25. @RestController
  26. @RequestMapping(value={"/demo"})
  27. public class DemoController
  28. implements EnhancedInstance,
  29. EnhancedInstance {
  30. // 这里多了一个字段
  31. private volatile Object _$EnhancedClassField_ws;
  32. public static volatile /* synthetic */ InstMethodsInter delegate$o59nu91;
  33. public static volatile /* synthetic */ InstMethodsInter delegate$3p5b3r0;
  34. public static volatile /* synthetic */ ConstructorInter delegate$hut6vg1;
  35. private static final /* synthetic */ Method cachedValue$fzikR5Vm$epivfa1;
  36. public static volatile /* synthetic */ InstMethodsInter delegate$l1upa31;
  37. public static volatile /* synthetic */ InstMethodsInter delegate$72rosd1;
  38. public static volatile /* synthetic */ ConstructorInter delegate$bggua40;
  39. private static final /* synthetic */ Method cachedValue$tbOTwlWY$epivfa1;
  40. public DemoController() {
  41. this(null);
  42. delegate$bggua40.intercept((Object)this, new Object[0]);
  43. }
  44. private /* synthetic */ DemoController(auxiliary.pucJ4sy3 pucJ4sy32) {
  45. }
  46. @GetMapping(value={"/hello"})
  47. public String hello() {
  48. // 目标方法已经被代理
  49. return (String)delegate$l1upa31.intercept((Object)this, new Object[0], (Callable)new auxiliary.9g06w93P(this), cachedValue$tbOTwlWY$epivfa1);
  50. }
  51. private /* synthetic */ String hello$original$c0h8eDbn() {
  52. // 原方法会保留, 替换方法名称
  53. return "hello skywalking";
  54. }
  55. static {
  56. ClassLoader.getSystemClassLoader().loadClass("org.apache.skywalking.apm.dependencies.net.bytebuddy.dynamic.Nexus").getMethod("initialize", Class.class, Integer.TYPE).invoke(null, DemoController.class, -830093591);
  57. cachedValue$tbOTwlWY$epivfa1 = DemoController.class.getMethod("hello", new Class[0]);
  58. }
  59. final /* synthetic */ String hello$original$c0h8eDbn$accessor$tbOTwlWY() {
  60. return this.hello$original$c0h8eDbn();
  61. }
  62. }