分布式链路追踪组件Skywalking

7/4/2022 微服务

# 什么是Skywalking

SkyWalking是一个开源APM系统,包含了云原生架构下的分布式系统的监控、跟踪、诊断功能。

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

# Skywalking和Spring Cloud Sleuth+ZipKin选型

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

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

# Skywalking架构

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

Skywalking01

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

大致流程就是Agent负责收集日志传输数据,通过GRPC的方式传递给OAP进行分析并且存储到数据库中,最终通过UI界面将分析的统计报表、服务依赖、拓扑关系图展示出来。

# 服务端搭建

# 下载安装包

Skywalking同样是通过Jar包启动,点击skywalking (opens new window)进入下载

Skywalking02

Skywalking03

Foundations 我们选择 V9.0.1 进行下载,Agents 选择 V8.11.0 下载,解压后完整目录如下:

Skywalking04

Skywalking05

# 配置修改

# 1、apache-skywalking-apm-bin\config下 application.yml

这个是 oap 服务的配置文件,需要修改注册中心为 nacos,如下图:

Skywalking06

# 2、apache-skywalking-apm-bin\webapp下 webapp.yml

这个是UI服务的配置文件,其中有一个 server.port 配置,是UI服务的端口,默认8080,避免端口冲突,修改为其他值:

Skywalking07

# 3、启动服务

先将Nacos启动,再启动Skywalking服务,Skywalking启动命令在/bin目录下,这里需要启动两个服务,如下:

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

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

Skywalking08

Skywalking09

然后浏览器直接访问:http://localhost:8888/general

Skywalking10

目前还没有启动任何微服务,所以数据都是空的,接下来我们搭建客户端。

# 客户端搭建

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

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

-javaagent:G:\java\SpringCloud2020\Skywalking\skywalking-agent\skywalking-agent.jar
-Dskywalking.agent.service_name=cloud-gateway
-Dskywalking.collector.backend_service=127.0.0.1:11800
1
2
3
  • -javaagent:指定skywalking中的agent中的skywalking-agent.jar的路径
  • -Dskywalking.agent.service_name:指定在skywalking中的服务名称,一般是微服务的spring.application.name
  • -Dskywalking.collector.backend_service:指定oap服务绑定的地址,由于陈某这里是本地,并且oap服务默认的端口是11800,因此只需要配置为127.0.0.1:11800

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

Skywalking11

上述三个微服务都需要配置skywalking的启动配置,配置成功后正常启动即可。

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

配置完成后启动服务,然后通过网关访问:http://localhost:9527/consumer/paymentSQL/1?uname=zhangsan

Skywalking12

此时查看skywalking的UI端,可以看到几个微服务已经监控成功了,如下图:

Skywalking13

服务之前的依赖关系也是可以很清楚的看到,如下图:

Skywalking14

请求链路的信息也是能够很清楚的看到,比如请求的url,执行时间、调用的服务,如下图:

Skywalking15

# 数据持久化配置

skywalking默认持久化的方式是存储在内存中,一旦服务重启则链路追踪数据就会丢失。skywalking提供了诸如ES、MySQL等方式进行数据的持久化,这里记录下使用MySQL进行数据持久化配置。

# 1、修改配置文件

同样的,修改apache-skywalking-apm-bin\configapplication.yml

storage:
  selector: ${SW_STORAGE:mysql}
  mysql:
    properties:
      jdbcUrl: ${SW_JDBC_URL:"jdbc:mysql://localhost:3306/skywalking?rewriteBatchedStatements=true&characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=UTC"}
      dataSource.user: ${SW_DATA_SOURCE_USER:root}
      dataSource.password: ${SW_DATA_SOURCE_PASSWORD:admin}
      dataSource.cachePrepStmts: ${SW_DATA_SOURCE_CACHE_PREP_STMTS:true}
      dataSource.prepStmtCacheSize: ${SW_DATA_SOURCE_PREP_STMT_CACHE_SQL_SIZE:250}
      dataSource.prepStmtCacheSqlLimit: ${SW_DATA_SOURCE_PREP_STMT_CACHE_SQL_LIMIT:2048}
      dataSource.useServerPrepStmts: ${SW_DATA_SOURCE_USE_SERVER_PREP_STMTS:true}
    metadataQueryMaxSize: ${SW_STORAGE_MYSQL_QUERY_MAX_SIZE:5000}
    maxSizeOfBatchSql: ${SW_STORAGE_MAX_SIZE_OF_BATCH_SQL:2000}
    asyncBatchPersistentPoolSize: ${SW_STORAGE_ASYNC_BATCH_PERSISTENT_POOL_SIZE:4}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# 2、添加MSQL的JDBC依赖

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

Skywalking16

配置完成后,在本地创建好skywalking数据库,然后再启动skywalking服务端

启动完成后,skywalking数据库中将会自动创建表,如下图:

Skywalking17

# 日志监控

在skywalking的控制台上有一个日志菜单,用于收集客户端的日志,默认是没有数据的。

skywalking提供了主流的日志框架接入,像log4j,logback,log4j2等,这里将以logback为例子记录一下如何配置日志框架,以下是一些官方接入日志框架的文档:

# 1、添加依赖

<dependency>
   <groupId>org.apache.skywalking</groupId>
   <artifactId>apm-toolkit-logback-1.x</artifactId>
   <version>${project.release.version}</version>
</dependency>
1
2
3
4
5

# 2、添加日志配置文件

新建一个logback-spring.xml放在resource目录下

<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod=" 5 seconds">
        <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>
    
        <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>
    
        <root level="INFO">
            <appender-ref ref="ASYNC"/>
            <appender-ref ref="grpc-log"/>
        </root>
    </configuration>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

# 配置完成后,启动服务,打开skywalking控制台就能看见日志模块的输出。

Skywalking18

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

# 指定要向其报告日志数据的Grpc服务的主机,默认10.10.10.1
plugin.toolkit.log.grpc.reporter.server_host=${SW_GRPC_LOG_SERVER_HOST:10.10.10.1}
# 指定要向其报告日志数据的Grpc服务的端口,默认11800
plugin.toolkit.log.grpc.reporter.server_port=${SW_GRPC_LOG_SERVER_PORT:11800}
# 指定Grpc客户端要报告的日志数据的最大大小,默认10485760
plugin.toolkit.log.grpc.reporter.max_message_size=${SW_GRPC_LOG_MAX_MESSAGE_SIZE:10485760}
# 客户端向上游发送数据时将超时多长时间,单位秒,默认30
plugin.toolkit.log.grpc.reporter.upstream_timeout=${SW_GRPC_LOG_GRPC_UPSTREAM_TIMEOUT:30}

1
2
3
4
5
6
7
8
9

# 监控告警

# skywalking中有一些默认的告警规则,如下:

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

这些规则的配置在apache-skywalking-apm-bin/config/alarm-settings.yml配置文件中

# Sample alarm rules.
rules:
  # Rule unique name, must be ended with `_rule`.
  service_resp_time_rule:
    metrics-name: service_resp_time
    op: ">"
    threshold: 1000
    period: 10
    count: 3
    silence-period: 5
    message: Response time of service {name} is more than 1000ms in 3 minutes of last 10 minutes.
  service_sla_rule:
    # Metrics value need to be long, double or int
    metrics-name: service_sla
    op: "<"
    threshold: 8000
    # The length of time to evaluate the metrics
    period: 10
    # How many times after the metrics match the condition, will trigger alarm
    count: 2
    # How many times of checks, the alarm keeps silence after alarm triggered, default as same as period.
    silence-period: 3
    message: Successful rate of service {name} is lower than 80% in 2 minutes of last 10 minutes
  service_resp_time_percentile_rule:
    # Metrics value need to be long, double or int
    metrics-name: service_percentile
    op: ">"
    threshold: 1000,1000,1000,1000,1000
    period: 10
    count: 3
    silence-period: 5
    message: Percentile response time of service {name} alarm in 3 minutes of last 10 minutes, due to more than one condition of p50 > 1000, p75 > 1000, p90 > 1000, p95 > 1000, p99 > 1000
  service_instance_resp_time_rule:
    metrics-name: service_instance_resp_time
    op: ">"
    threshold: 1000
    period: 10
    count: 2
    silence-period: 5
    message: Response time of service instance {name} is more than 1000ms in 2 minutes of last 10 minutes
  database_access_resp_time_rule:
    metrics-name: database_access_resp_time
    threshold: 1000
    op: ">"
    period: 10
    count: 2
    message: Response time of database access {name} is more than 1000ms in 2 minutes of last 10 minutes
  endpoint_relation_resp_time_rule:
    metrics-name: endpoint_relation_resp_time
    threshold: 1000
    op: ">"
    period: 10
    count: 2
    message: Response time of endpoint relation {name} is more than 1000ms in 2 minutes of last 10 minutes

webhooks:
#  - http://127.0.0.1/notify/
#  - http://127.0.0.1/go-wechat/
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58

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

Skywalking19

除了以上几种默认的规则,Skywalking还提供了webhooks方法,相当于一个回调,一旦触发了上述规则告警,skywalking则会调用配置的webhook,这就给开发者们提供了告警的后置处理,比如发送告警邮件告警短信等等。

但是webhooks也有自己的一些规则:

其中,AlarmMessage类不同版本可能会有所不同,需要自行找到对应版本的源码去拷贝其属性。对应的源码的路径:org.apache.skywalking.oap.server.core.alarm

Skywalking20

# 新建一个告警模块,代码如下:

@RestController
@RequestMapping("alarm")
@Slf4j
public class AlarmController
{
    @PostMapping("/receive")
    public void receive(@RequestBody List<AlarmMessage> list)
    {
        log.info("处理一些通知告警事项");
        log.info(JSON.toJSONString(list));
    }
}
1
2
3
4
5
6
7
8
9
10
11
12

然后在apache-skywalking-apm-bin/config/alarm-settings.yml中配置

webhooks:
#  - http://127.0.0.1/alarm/receive
1
2