链路追踪Skywalking

一、什么是Skywalking

分布式链路追踪的一种方式:Spring Cloud Sleuth+ZipKin,这种方案目前也是有很多企业在用,但是作为程序员要的追逐一些新奇的技术,Skywalking作为后起之秀也是值得大家去学习的。

Skywalking是一个优秀的国产开源框架,2015年由个人吴晟(华为开发者)开源 , 2017年加入Apache孵化器。短短两年就被Apache收入麾下,实力可见一斑。

Skywalking支持dubbo,SpringCloud,SpringBoot集成,代码无侵入,通信方式采用GRPC,性能较好,实现方式是java探针,支持告警,支持JVM监控,支持全局调用统计等等,功能较完善。

二、Skywalking和Spring Cloud Sleuth+ZipKin如何选型

Skywalking相比于zipkin还是有很大的优势的,如下:

  • skywalking采用字节码增强的技术实现代码无侵入,zipKin代码侵入性比较高
  • skywalking功能比较丰富,报表统计,UI界面更加人性化

个人建议:如果是新的架构,建议优先选择Skywalking

三、Skywalking架构

skywalking和zipkin一样,也分为服务端和客户端,服务端负责收集日志数据并且展示,架构如下:

上述架构图中主要分为四个部分,如下:

  • 上面的Agent:负责收集日志数据,并且传递给中间的OAP服务器
  • 中间的OAP:负责接收Agent发送的Tracing 和Metric的数据信息,然后进行分析(Analysis Core) ,存储到外部存储器( Storage ),最终提供查询( Query )功能。
  • 左面的UI:负责提供web控制台,查看链路,查看各种指标,性能等等。
  • 右面Storage:负责数据的存储,支持多种存储类型。

看了架构图之后,思路很清晰了,Agent负责收集日志传输数据,通过GRPC的方式传递给OAP进行分析并且存储到数据库中,最终通过UI界面将分析的统计报表、服务依赖、拓扑关系图展示出来。

四、服务端如何搭建

提前说明:当前所使用的版本为8.7.0,不同的版本其启动方式存在差异,需要另外查询资料。

3.1 下载安装包

SkyWalking是通过jar包方式启动,需要下载jar包,我们可以通过下述地址找到并下载Skywalking的8.7.0版本,如下所示:

bash 复制代码
https://archive.apache.org/dist/skywalking/

3.2 OAP服务的配置

将上述压缩包进行解压,解压以后首先找到 /config/application.yml目录文件,这个是oap服务的配置文件,需要将配置中心修改为nacos,如下所示:

修改默认注册中心选择nacos,这样就不用在启动参数中指定了。另外由于nacos服务是本地启动的,所以相关的配置不需要修改。

3.3 UI服务的配置

UI服务的配置文件是 /webapp/webapp.yml,其中有一个server.port配置,是UI服务的端口,默认为8080,为避免端口冲突,将其改成8888。

3.4 启动

启动命令在/bin目录下,这里需要启动两个服务,如下所示:

  • oap服务:对应的启动脚本oapService.bat,Linux下对应的后缀是sh
  • UI服务:对应的启动脚本webappService.bat,Linux下对应的后缀是sh

还有一个startup.bat启动文件,可以直接启动上述两个服务,我们可以直接使用这个脚本,直接双击,将会弹出两个窗口则表示启动成功,如下所示:

浏览器访问localhost:8888,直接进入UI端,如下所示:

再回看Skywalkingj解压后的完整目录,如下所示:

重要的目录结构分析如下:

  • agent:客户端需要指定的目录,其中有一个jar,就是负责和客户端整合收集日志
  • bin:服务端启动的脚本
  • config:一些配置文件的目录
  • logs:oap服务的日志目录
  • oap-libs:oap所需的依赖目录
  • webapp:UI服务的目录

五、客户端如何搭建

客户端也就是单个微服务,由于Skywalking采用字节码增强技术,因此对于微服务无代码侵入,只要是普通的微服务即可,不需要引入什么依赖。

想要传输数据必须借助skywalking提供的agent,只需要在对应服务的启动参数指定agent即可,命令如下:

bash 复制代码
-javaagent:D:\demo\apache-skywalking-apm-8.7.0\apache-skywalking-apm-bin\agent\skywalking-agent.jar
-Dskywalking.agent.service_name=demo
-Dskywalking.collector.backend_service=127.0.0.1:11800

上述命令解析如下:

  • -javaagent:指定skywalking中的agent中的skywalking-agent.jar的路径
  • -Dskywalking.agent.service_name:指定在skywalking中的服务名称,一般是微服务的spring.application.name
  • -Dskywalking.collector.backend_service:指定oap服务绑定的地址,由于这里是在本地环境中启动oap,并且oap服务默认的端口是11800,因此只需要配置为127.0.0.1:11800

上述参数可以在命令行通过 java -jar xxx指定,在IDEA中操作如下所示:

如果是在微服务中,每一个微服务都需要配置Skywalking的agent启动配置,配置成功后正常启动即可。

注意:agent的jar包路径不能包含中文,不能有空格,否则运行不成功。

此处构造测试使用的接口/api/hello和/api/chain,后续其它模块也会使用到。

java 复制代码
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@Slf4j
@RestController
@RequestMapping("/api")
public class DemoController {

    @GetMapping("/hello")
    public String hello() {
        log.info("调用了hello方法");
        return "Hello, SkyWalking!";
    }

    @GetMapping("/chain")
    public String chain() {
        log.info("调用了chain方法");
        doSomeThing();
        return callAnotherService();
    }

    private String callAnotherService() {
        // 模拟调用另一个服务
        return "Service call chain";
    }

    private void doSomeThing(){
        try{
            Thread.sleep(1000);
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

在准备工作完成以后,启动服务,分别访问localhost:8001/api/hello和localhost:8001/api/chain,然后再去查看Skywalking的UI端。 这里如果想在下述三个模块中可以尽快的看到相关数据,那么建议打开UI界面右上角的 **"自动刷新"**功能。(PS:第一次使用时,由于不了解相关的功能特性,所以花了很长的时间研究为什么这三个模块中没有数据,呜呜呜!!!)

查看 "仪表盘模块",可以看到demo服务已经被监控成功了,如下所示:

查看 "拓扑图模块",可以看到服务之前的依赖关系,如下所示:

查看 "追踪模块",请求链路的信息也是能够很清楚的看到,比如请求的url,执行时间、调用的服务,如下所示:

六、数据持久化

你会发现只要服务端重启之后,这些链路追踪数据将会丢失了,因为Skywalking默认持久化的方式是存储在内存中。我们是可以通过插拔方式的替换掉存储中间件,企业中往往是使用ES存储,这里介绍的是MySQL的方式存储。

6.1 修改配置文件

修改config/application.yml文件中的存储方式,总共需要修改两处地方。

第一个地方:修改默认的存储方式为mysql

第二个地方:修改mysql相关的信息,此处我新建了一个名为skywalking_config的数据库

6.2 添加MySQL的jdbc依赖

默认的oap中是没有jdbc驱动依赖,因此需要我们手动添加一下,只需要将驱动的jar放在oap-libs文件夹中,如下所示:

配置完成以后,启动服务端,在skywalking_config这个数据库中将会自动创建表,如下所示:

数据库中新建的表是逐步缓慢创建的,最终一共会有142张表,所以提前创建一个独有的数据库还是很有必要的,与业务数据库分隔开。

七、日志监控

在skywalking的UI端有一个日志的模块,用于收集客户端的日志,默认是没有数据的,我们可以相关的日志框架将日志数据推送到Skywalking中。

日志框架的种类很多,比较出名的有log4j、log4j2、logback,其官方文档如下。

log4j日志框架的文档:

bash 复制代码
https://skywalking.apache.org/docs/skywalking-java/v8.7.0/en/setup/service-agent/java-agent/application-toolkit-log4j-1.x/

log4j2日志框架的文档:

bash 复制代码
https://skywalking.apache.org/docs/skywalking-java/v8.7.0/en/setup/service-agent/java-agent/application-toolkit-log4j-2.x/

logback日志框架的文档:

bash 复制代码
https://skywalking.apache.org/docs/skywalking-java/v8.7.0/en/setup/service-agent/java-agent/application-toolkit-logback-1.x/

下面就以logback日志框架为例子介绍一下如何配置。

7.1 添加依赖

在pom.xml文件中添加下述依赖,如下所示:

html 复制代码
<dependency>
	<groupId>org.apache.skywalking</groupId>
	<artifactId>apm-toolkit-logback-1.x</artifactId>
	<version>8.7.0</version>
</dependency>

7.2 添加配置文件

新建一个 logback-spring.xml 放在resource目录下,配置如下:

html 复制代码
<configuration scan="true" scanPeriod=" 5 seconds">
    <!-- 控制台打印tracId的格式,只需要加一个%tid -->
    <appender name="STDOUT" 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.mdc.TraceIdMDCPatternLogbackLayout">
                <Pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%X{tid}] [%thread] %-5level %logger{36} -%msg%n</Pattern>
            </layout>
        </encoder>
    </appender>

    <!--异步打印-->
    <appender name="ASYNC" class="ch.qos.logback.classic.AsyncAppender">
        <discardingThreshold>0</discardingThreshold>
        <queueSize>1024</queueSize>
        <neverBlock>true</neverBlock>
        <appender-ref ref="STDOUT"/>
    </appender>

    <!--日志传输到Skywalking中的appender,通过grpc传输-->
    <appender name="grpc-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.mdc.TraceIdMDCPatternLogbackLayout">
                <Pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%X{tid}] [%thread] %-5level %logger{36} -%msg%n</Pattern>
            </layout>
        </encoder>
    </appender>

    <!-- 日志级别为INFO,控制台打印,并且传输到Skywalking -->
    <root level="INFO">
        <appender-ref ref="ASYNC"/>
        <appender-ref ref="grpc-log"/>
    </root>
</configuration>

7.3 测试日志传输

在上述配置完成以后,启动对应的服务,访问localhost:8001/api/hello和localhost:8001/api/chain接口,控制台打印的日志如下所示:

可以看到控制台中已经打印出了traceId,接着再去Skywalking的日志模块中查看相关的日志,如下所示:

可以看到日志已经传输到了skywalking中,那么则说明前面的配置已经成功!!!

特别说明:在当前Skywalking的8.7.0版本中日志模块的 **"时间范围"**选项,在默认情况下不会自动更新数据范围,这样就会给使用者造成一种困扰,当IDEA控制台打印了相关日志以后,我们去Skywalking的日志模块中查询会发现没有数据。那么针对这种情况,就需要我们手动去调整时间范围,然后再点击"搜索"按钮查询相关日志信息。

注意:如果agent和oap服务不在同一台服务器上,需要在/agent/config/agent.config配置文件末尾添加下述4行配置。

bash 复制代码
plugin.toolkit.log.grpc.reporter.server_host=${SW_GRPC_LOG_SERVER_HOST:10.10.10.1}
plugin.toolkit.log.grpc.reporter.server_port=${SW_GRPC_LOG_SERVER_PORT:11800}
plugin.toolkit.log.grpc.reporter.max_message_size=${SW_GRPC_LOG_MAX_MESSAGE_SIZE:10485760}
plugin.toolkit.log.grpc.reporter.upstream_timeout=${SW_GRPC_LOG_GRPC_UPSTREAM_TIMEOUT:30}

4个配置分析如下:

  • plugin.toolkit.log.transmit_formatted:是否以格式化或未格式化的格式传输记录的数据,默认值为true
  • plugin.toolkit.log.grpc.reporter.server_host:指定要向其报告日志数据的grpc服务器的主机,例如192.168.1.2
  • plugin.toolkit.log.grpc.reporter.server_port:指定要向其报告日志数据的grpc服务器的端口,默认为11800
  • plugin.toolkit.log.grpc.reporter.max message size:指定grpc客户端要报告的日志数据的最大大小,默认值为10485760
  • plugin.toolkit.log.grpc,reporter.upstream timeout:客户端向上游发送数据时将超时多长时间,单位是秒,默认值是30

八、性能剖析

Skywalking在性能剖析方面真的是非常强大,提供到基于堆栈的分析结果,能够让运维人员一眼定位到问题。

新建一个/order/list接口,如下所示:

java 复制代码
import cn.hutool.core.util.RandomUtil;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/order")
public class OrderController {

    @GetMapping("/list")
    public void list() throws Exception {
        Thread.sleep(2000);
        int sum = 1 + RandomUtil.randomInt(10);
        System.out.println(sum);
    }
}

上述代码中休眠了2秒,看看如何在Skywalking中定位这个问题。

"性能剖析模块" - > "新建任务"->选择服务、填写端点、监控时间,如下所示:

上图中选择了最大采样数为5,则直接访问5次localhost:8001/order/list,然后选择这个任务将会出现监控到的数据,如下所示:

上图中可以看到 {GET}/order/list这个接口上耗费了2秒以上,因此选择这个接口点击分析,可以看到详细的堆栈信息,如下所示:

如何定位到睡眠2秒钟的那一行代码呢?直接往下翻,如下所示:

此时就很清楚了,在OrderController这个接口中线程睡眠了两秒!!!

九、监控告警

Skywalking中有一些默认的告警规则,如下所示:

  • 最近3分钟内服务的平均响应时间超过1秒
  • 最近2分钟服务成功率低于80%
  • 最近3分钟90%服务响应时间超过1秒
  • 最近2分钟内服务实例的平均响应时间超过1秒

当然除了上述四种告警规则,随着Skywalking不断迭代也会新增其它规则,这些规则的配置在 config/alarm-settings.yml配置文件中,如下所示:

每个规则都由相同的属性组成,这些属性的含义如下:

  • metrics-name:监控的指标名称(如 service_resp_time)
  • threshold:触发告警的阈值(如 > 1000、< 90%)
  • op:比较运算符(>,<,=,>=,<=)
  • period:多久检查一次当前的指标数据是否符合告警规则,单位是分钟
  • count:连续多少次触发阈值才发送告警(如值为3,则表示连续3次超阈值才告警)
  • silence-period:在多久之内,忽略相同的告警消息
  • message:告警消息内容
  • include-names:本规则告警生效的服务列表

如果想要调整默认的规则,比如监控返回的信息,监控的参数等等,只需要改动上述配置文件中的参数即可。

当然除了以上默认的几种规则,Skywalking还适配了一些钩子(webhooks)。其实就是相当于一个回调,一旦触发了上述规则告警,Skywalking则会调用配置的webhook,这样开发者就可以定制一些处理方法,比如发送邮件、微信、钉钉通知运维人员处理。

当然这个钩子也是有些规则的,如下所示:

  • POST请求
  • application/json 接收数据
  • 接收的参数必须是AlarmMessage中指定的参数

特别注意:AlarmMessage这个类随着Skywalking版本的迭代可能出现不同,一定要到对应版本源码中去找到这个类,拷贝其中的属性,这个类在源码的路径:org.apache.skywalking.oap.server.core.alarm。

java 复制代码
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

import cn.hutool.core.collection.CollectionUtil;
import lombok.AllArgsConstructor;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

@Getter
@Setter
@EqualsAndHashCode
@NoArgsConstructor
@AllArgsConstructor
public class Tag {
    private String key;
    private String value;

    @Override
    public String toString() {
        return key + "=" + value;
    }

    public static class Util {
        public static List<String> toStringList(List<Tag> list) {
            if (CollectionUtil.isEmpty(list)) {
                return Collections.emptyList();
            }
            return list.stream().map(Tag::toString).collect(Collectors.toList());
        }
    }
}
java 复制代码
import lombok.Getter;
import lombok.Setter;

import java.util.List;

@Setter
@Getter
public class AlarmMessage {
    private int scopeId;
    private String scope;
    private String name;
    private String id0;
    private String id1;
    private String ruleName;
    private String alarmMessage;
    private List<Tag> tags;
    private long startTime;
    private transient int period;
    private transient boolean onlyAsCondition;
}

定义一个用于回调的钩子接口,如下所示:

java 复制代码
import cn.hutool.json.JSONUtil;
import com.example.demo.dto.AlarmMessage;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
@RequestMapping("/alarm")
public class AlarmController {

    @PostMapping("/receive")
    public void receive(@RequestBody List<AlarmMessage> list) {
        // todo::仅仅打印JSON,至于发送邮件、微信、钉钉自己根据业务需求完成
        System.out.println(JSONUtil.toJsonPrettyStr(list));
    }
}

钩子接口完成以后,只需要在 config/alarm-settings.yml 配置文件中添加这个钩子:

好了,这就已经配置完成了,测试也很简单,还是调用上面案例中的睡眠两秒的接口localhost:8001/order/list,多调用几次,则会触发告警,控制台打印日志如下:

对于服务的异常信息,比如接口有较长延迟,Skywalking的 **"告警模块"**UI界面也会有相关的展示,如下所示:

特别说明:此处我发现了一个问题,就是控制台的钩子接口会先打印出告警信息,在稍微等待一会后(需要一会时间)UI界面才会有相关的告警展示。

相关推荐
Linux-187417 小时前
分布式链路追踪系统之docker-compose安装skywalking
云原生·docker-compose·skywalking·分布式链路追踪系统·应用程序性能监控
流烟默1 天前
SpringBoot应用链路追踪 traceId 技术方案
spring boot·skywalking·traceid
Linux-18742 天前
分布式链路追踪系统之二进制安装skywalking
elasticsearch·云原生·skywalking·分布式链路追踪系统·应用程序性能监控
令狐前生5 天前
SpringBoot3项目集成Skywalking示例
skywalking
乒乓狂魔7 天前
SkyWalking 也能 AI 智能化了
人工智能·skywalking
摇滚侠14 天前
Skywalking 应用性能监控和可观测性分析平台 简介
skywalking
Databuff14 天前
skywalking 快速使用入门
skywalking
摇滚侠16 天前
Apache Skywalking 实战 阅读笔记 第三章
笔记·apache·skywalking
摇滚侠17 天前
Apache Skywalking 实战 阅读笔记 第二章
笔记·apache·skywalking
Databuff17 天前
国产开源APM databuff 成为 CNCF 顶级项目opentelemetry 官宣Vendor
运维·开源·skywalking·apm·可观测性·opentelemetry