SkyWalking性能监控工具

发布时间 2023-04-17 20:01:23作者: 西东怪

skyWalking

目录旁边可以查询具体的目录结构和跳转

一.链路追踪介绍

对于一个大型的几十个、几百个微服务构成的微服务架构系统,通常会遇到下面一些问题,比如:

  1. 如何串联整个调用链路,快速定位问题?

  2. 如何缕清各个微服务之间的依赖关系?

  3. 如何进行各个微服务接口的性能分折?

  4. 如何跟踪整个业务流程的调用处理顺序?

二.skyWalking介绍

skywalking是一个国产开源框架,2015年由吴晟开源 , 2017年加入Apache孵化器。skywalking是分布式系统的应用程序性能监视工具,专为微服务、云原生架构和基于容器(Docker、K8s、Mesos)架构而设计。它是一款优秀的APM(Application Performance Management)工具,包括了分布式追踪、性能指标分析、应用和服务依赖分析等。

官网:http://skywalking.apache.org/

下载:http://skywalking.apache.org/downloads/

Github:https://github.com/apache/skywalking

文档: https://skywalking.apache.org/docs/main/v8.4.0/readme/

中文文档: https://skyapm.github.io/document-cn-translation-of-skywalking/

2.1链路追踪框架对比

skyWalking的性能综合来说是最合适的,最优的。

2.2Skywalking 整体架构

整个架构分成四部分:

1、上部分 Agent :负责从应用中,收集链路信息,发送给 SkyWalking OAP 服务器;(skywalking Agent还可以监控应用程序的调用链路,并可以跟踪组件之间的调用。)

2、下部分 SkyWalking OAP :负责接收 Agent 发送的 Tracing 数据信息,然后进行分析(Analysis Core),存储到外部存储器(Storage),最终提供查询(Query)功能;

3、右部分 Storage:Tracing 数据存储,目前支持 ES、MySQL、Sharding Sphere、TiDB、H2 多种存储器,目前采用较多的是 ES,主要考虑是 SkyWalking 开发团队自己的生产环境采用 ES 为主;

4、左部分 SkyWalking UI:负责提供控制台,查看链路等等;

2.3 Skywalking主要功能特性

1、多种监控手段,可以通过语言探针和service mesh获得监控的数据;

2、支持多种语言自动探针,包括 Java,.NET Core 和 Node.JS;

3、轻量高效,无需大数据平台和大量的服务器资源;

4、模块化,UI、存储、集群管理都有多种机制可选;

5、支持告警;

6、优秀的可视化解决方案;

三.skyWalking下载和基本搭建

1.APM和Agent下载

自己选择下载就行了,不需要服务alibba版本配对

http://skywalking.apache.org/downloads/

因为在skyWalking9.0之后APM没有agent报了,需要单独下载

2.搭建SkyWalking OAP 服务

启动apache-skywalking-apm-bin\bin\startup.bat

启动成功后会启动两个服务,oapService.bat和webappService.bat

  • skywalking-oap-server服务启动后会暴露11800 和 12800 两个端口,分别为收集监控数据的端口11800和接受前端请求的端口12800,修改端口可以修改config/applicaiton.yml
  • skywalking-web-ui服务会占用 默认是8080(我修改为了8086), 修改端口可以修改webapp/application.yml
serverPort: ${SW_SERVER_PORT:-8068}

# Comma seperated list of OAP addresses.
oapServices: ${SW_OAP_ADDRESS:-http://localhost:12800}

访问:http://192.168.3.100:8068/

3.kyWalking中三个概念

服务(Service) :表示对请求提供相同行为的一系列或一组工作负载,在使用Agent时,可以定义服务的名字;

服务实例(Service Instance) :上述的一组工作负载中的每一个工作负载称为一个实例, 一个服务实例实际就是操作系统上的一个真实进程;

端点(Endpoint) :对于特定服务所接收的请求路径, 如HTTP的URI路径和gRPC服务的类名 + 方法签名;

四.skyWalking接入微服务

1.windos环境—在IDEA中使用Skywalking

#!!!每个服务都需要配置


# skywalking‐agent.jar的本地磁盘的路径
-javaagent:F:\2-environment\apache-skywalking-java-agent-8.13.0\skywalking-agent\skywalking-agent.jar
# 在skywalking上显示的服务名
-DSW_AGENT_NAME=api-gateway  
# skywalking的collector服务的IP及端口
-DSW_AGENT_COLLECTOR_BACKEND_SERVICES=127.0.0.1:11800

!!!!重要!!!注意:此处存在bug,跟踪链路不显示gateway服务

拷贝skywalking-agent/optional-plugins目录下的gateway插件到skywalking-agent/plugins目录


2.窗口演示

服务展示

拓朴图

链路追踪

五.使用MySQL持久化链路数据

1.修改配置

apache-skywalking-apm-bin\config\application.yml

storage:
  selector: ${SW_STORAGE:mysql}

mysql:
    properties:
      jdbcUrl: ${SW_JDBC_URL:"jdbc:mysql://localhost:3307/swtest?rewriteBatchedStatements=true&serverTimezone=UTC"}
      dataSource.user: ${SW_DATA_SOURCE_USER:root}
      dataSource.password: ${SW_DATA_SOURCE_PASSWORD:123456789}
      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}

2.Skywalkin添加mysql驱动包

添加驱动包到apache-skywalking-apm-bin\oap-libs

mysql-connector-java-8.0.21.jar

3.创建对应数据库

#数据库名和对应配置名字一致

jdbcUrl: ${SW_JDBC_URL:"jdbc:mysql://localhost:3307/swtest?rewriteBatchedStatements=true&serverTimezone=UTC"}

数据库中出现对应表

测试:重启skywalking,验证跟踪数据会不会丢失

六.自定义链路追踪

1.导入依赖

<!-- SkyWalking工具类 -->
        <dependency>
            <groupId>org.apache.skywalking</groupId>
            <artifactId>apm-toolkit-trace</artifactId>
            <version>8.12.0</version>
        </dependency>

2.@Trace将方法加入追踪链路

如果一个业务方法想在ui界面的跟踪链路上显示出来,只需要在业务方法上加上@Trace注解即可

	@Trace
    public List<Order> all() throws InterruptedException {
        TimeUnit.SECONDS.sleep(2);
        return orderMapper.selectAll();
    }


    @Trace
    public Order get(Integer id) {
        return orderMapper.selectByPrimaryKey(id);
    }

3.加入@Tags或@Tag

使用@Tags或@Tag的前提是此方法添加了@Trace注解将返回值或参数加入链路详情

@Tag 注解中  key = 方法名 ;value =  returnedObj  返回值  

						  value = arg[0] 参数

一个就用@Tag,多个就用@Tags

	@Trace
    @Tag(key="getAll",value="returnedObj") //returnedObj代表返回值
    public List<Order> all() throws InterruptedException {
        TimeUnit.SECONDS.sleep(2);
        return orderMapper.selectAll();
    }


    @Trace
    @Tags({@Tag(key="getAll",value="returnedObj"),
            @Tag(key="getAll",value="arg[0]")}) //arg[0]代表第一个参数
    public Order get(Integer id) {
        return orderMapper.selectByPrimaryKey(id);
    }

七.Skywalking集成日志框架

logback官方配置

还要其他日志框架可以集成例如log4j等

1.引入依赖

添加在需要集成日志的服务上

		<dependency>
            <groupId>org.apache.skywalking</groupId>
            <artifactId>apm-toolkit-logback-1.x</artifactId>
            <version>8.12.0</version>
        </dependency>

2.添加logback-spring.xml文件

添加logback-spring.xml文件,并配置 %tid 占位符(具体理解2参考springboot日志部分)

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <!-- 引入 Spring Boot 默认的 logback XML 配置文件  -->
    <include resource="org/springframework/boot/logging/logback/defaults.xml"/>


    <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>-%clr(%d{${LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd HH:mm:ss.SSS}}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} [%tid] %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}</Pattern>
            </layout>
        </encoder>

    </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>

    <!-- 设置 Appender -->
    <root level="INFO">
        <appender-ref ref="console"/>
        <appender-ref ref="grpc-log"/>
    </root>

</configuration>

打开agent/config/agent.config配置文件,添加如下配置信息:

agent与oap在本地的以下可以不配。

plugin.toolkit.log.grpc.reporter.server_host=${SW_GRPC_LOG_SERVER_HOST:127.0.0.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}

3.测试


打开agent/config/agent.config配置文件,添加如下配置信息:

1 plugin.toolkit.log.grpc.reporter.server_host=${SW_GRPC_LOG_SERVER_HOST:192.168.3.100}

2 plugin.toolkit.log.grpc.reporter.server_port=${SW_GRPC_LOG_SERVER_PORT:11800}

3 plugin.toolkit.log.grpc.reporter.max_message_size=${SW_GRPC_LOG_MAX_MESSAGE_SIZE:10485760}

4 plugin.toolkit.log.grpc.reporter.upstream_timeout=${SW_GRPC_LOG_GRPC_UPSTREAM_TIMEOUT:30}

以上配置是默认配置信息,agent与oap在本地的可以不配

八.SkyWalking 告警功能

SkyWalking 告警功能是在6.x版本新增的,其核心由一组规则驱动,这些规则定义在config/alarm-settings.yml文件中。 告警规则的定义分为两部分:

  1. 告警规则:它们定义了应该如何触发度量警报,应该考虑什么条件。

  2. Webhook(网络钩子:定义当警告触发时,哪些服务终端需要被告知

告警规则

SkyWalking 的发行版都会默认提供config/alarm-settings.yml文件,里面预先定义了一些常用的告警规则。如下:

  1. 过去 3 分钟内服务平均响应时间超过 1 秒。

  2. 过去 2 分钟服务成功率低于80%。

  3. 过去 3 分钟内服务响应时间超过 1s 的百分比

  4. 服务实例在过去 2 分钟内平均响应时间超过 1s,并且实例名称与正则表达式匹配。

  5. 过去 2 分钟内端点平均响应时间超过 1 秒。

  6. 过去 2 分钟内数据库访问平均响应时间超过 1 秒。

  7. 过去 2 分钟内端点关系平均响应时间超过 1 秒。

这些预定义的告警规则,打开config/alarm-settings.yml文件即可看到

告警规则配置项的说明:

  • Rule name:规则名称,也是在告警信息中显示的唯一名称。必须以_rule结尾,前缀可自定义
  • Metrics name:度量名称,取值为oal脚本中的度量名,目前只支持long、double和int类型。详见Official OAL script
  • Include names:该规则作用于哪些实体名称,比如服务名,终端名(可选,默认为全部)
  • Exclude names:该规则作不用于哪些实体名称,比如服务名,终端名(可选,默认为空)
  • Threshold:阈值
  • OP: 操作符,目前支持 >、<、=
  • Period:多久告警规则需要被核实一下。这是一个时间窗口,与后端部署环境时间相匹配
  • Count:在一个Period窗口中,如果values超过Threshold值(按op),达到Count值,需要发送警报
  • Silence period:在时间N中触发报警后,在TN -> TN + period这个阶段不告警。 默认情况下,它和Period一样,这意味着
  • 相同的告警(在同一个Metrics name拥有相同的Id)在同一个Period内只会触发一次
  • message:告警消息


Webhook(网络钩子)

Webhook可以简单理解为是一种Web层面的回调机制,通常由一些事件触发,与代码中的事件回调类似,只不过是Web层面的。由于是Web层面的,所以当事件发生时,回调的不再是代码中的方法或函数,而是服务接口。例如,在告警这个场景,告警就是一个事件。当该事件发生时,SkyWalking就会主动去调用一个配置好的接口,该接口就是所谓的Webhook。SkyWalking的告警消息会通过 HTTP 请求进行发送,请求方法为 POST,Content-Type 为 application/json,其JSON 数据实基于

List<org.apache.skywalking.oap.server.core.alarm.AlarmMessage进行序列化的。JSON数据示例:

[{
"scopeId": 1,
"scope": "SERVICE",
"name": "serviceA",
"id0": "12",
"id1": "",
"ruleName": "service_resp_time_rule",
"alarmMessage": "alarmMessage xxxx",
"startTime": 1560524171000
}, {
"scopeId": 1,
"scope": "SERVICE",
"name": "serviceB",
"id0": "23",
"id1": "",
"ruleName": "service_resp_time_rule",
"alarmMessage": "alarmMessage yyy",
"startTime": 1560524171000
}]

字段说明:

  • scopeId、scope:所有可用的 Scope 详见 org.apache.skywalking.oap.server.core.source.DefaultScopeDefine
  • name:目标 Scope 的实体名称
  • id0:Scope 实体的 ID
  • id1:保留字段,目前暂未使用
  • ruleName:告警规则名称
  • alarmMessage:告警消息内容
  • startTime:告警时间,格式为时间戳

邮件告警功能实践

根据以上两个小节的介绍,可以得知:SkyWalking是不支持直接向邮箱、短信等服务发送告警信息的,SkyWalking只会在发生告警时将告警信息发送至配置好的Webhook接口。

但我们总不能人工盯着该接口的日志信息来得知服务是否发生了告警,因此我们需要在该接口里实现发送邮件或短信等功能,从而达到个

性化的告警通知。

1.添加依赖

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring‐boot‐starter‐mail</artifactId>
</dependency>

2.配置邮箱服务

server:
 port: 9134

#邮箱配置
spring:
mail:
host: smtp.163.com
#发送者邮箱账号
username: 你的邮箱@163.com
#发送者密钥
password: 你的邮箱服务密钥
default‐encoding: utf‐8
port: 465 #端口号465或587
protocol: smtp
properties:
mail:
debug:
false
 smtp:
socketFactory:
class: javax.net.ssl.SSLSocketFactory

根据SkyWalking发送的JSON数据定义一个DTO,用于接口接收数据:

@Data
public class SwAlarmDTO {

 private Integer scopeId;
 private String scope;
 private String name;
 private Integer id0;
 private Integer id1;
 private String ruleName;
private String alarmMessage;
 private Long startTime;
}

接着定义一个接口,实现接收SkyWalking的告警通知,并将数据发送至邮箱:

@Slf4j
   @RestController
   @RequiredArgsConstructor
   @RequestMapping("/alarm")
   public class SwAlarmController {


    /**
     * 接收skywalking服务的告警通知并发送至邮箱
     *
     * 必须是post
     */
    @PostMapping("/receive")
    public void receive(@RequestBody List<SwAlarmDTO> alarmList) {
       /* SimpleMailMessage message = new SimpleMailMessage();
        // 发送者邮箱
        message.setFrom(from);
        // 接收者邮箱
        message.setTo(from);
        // 主题
        message.setSubject("告警邮件");
        String content = getContent(alarmList);
        // 邮件内容
        message.setText(content);
        sender.send(message);*/
        String content = getContent(alarmList);
        log.info("告警邮件已发送..."+content);
    }
    
    private String getContent(List<SwAlarmDTO> alarmList) {
        StringBuilder sb = new StringBuilder();
        for (SwAlarmDTO dto : alarmList) {
            sb.append("scopeId: ").append(dto.getScopeId())
                    .append("\nscope: ").append(dto.getScope())
                    .append("\n目标 Scope 的实体名称: ").append(dto.getName())
                    .append("\nScope 实体的 ID: ").append(dto.getId0())
                    .append("\nid1: ").append(dto.getId1())
                    .append("\n告警规则名称: ").append(dto.getRuleName())
                    .append("\n告警消息内容: ").append(dto.getAlarmMessage())
                    .append("\n告警时间: ").append(dto.getStartTime())
                    .append("\n标签: ").append(dto.getTags())
                    .append("\n\n---------------\n\n");
        }
    
        return sb.toString();
    }

}

最后将该接口配置到SkyWalking中,Webhook的配置位于config/alarm-settings.yml文件的末尾,格式为http://{ip}:{port}/{uri}。如下示例:

webhooks:
 - http://127.0.0.1:9134/alarm/receive

在order中all方法

@Trace
    @Tag(key="getAll",value="returnedObj")
    public List<Order> all() throws InterruptedException {
        TimeUnit.SECONDS.sleep(2);
        return orderMapper.selectAll();
    }

测试:

http://localhost:8068/order/all

执行完测试代码,等待约两分钟后,告警接口的控制台输出了一段日志信息:

(我们没有使用邮件,在本地测试了)

九.skywalking高可用

在大多数生产环境中,后端应用需要支持高吞吐量并且支持高可用来保证服务的稳定,所以你始终需要在生产环境进行

集群管理。

Skywalking集群是将skywalking oap作为一个服务注册到nacos上,只要skywalking oap服务没有全部宕机,保证有一

个skywalking oap在运行,就能进行跟踪。

搭建一个skywalking oap集群需要:

(1)至少一个Nacos(也可以是nacos集群)

(2)至少一个ElasticSearch/mysql(也可以是es/msql集群)

(3)至少2个skywalking oap服务;

(4)至少1个UI(UI也可以集群多个,用Nginx代理统一入口)

1.修改config/application.yml文件

使用nacos作为注册中心

修改nacos配置

可以选择性修改监听端口

修改存储策略,使用elasticsearch7作为storage

2.配置ui服务webapp.yml文件的listOfServers,写两个地址

3.启动服务测试

启动Skywalking服务,指定springboot应用的jvm参数

 -DSW_AGENT_COLLECTOR_BACKEND_SERVICES=192.168.3.10:11800,192.168.3.12:1180

sky walking依赖和yml配置总合

server:
 port: 9134

#邮箱配置
spring:
mail:
host: smtp.163.com
#发送者邮箱账号
username: 你的邮箱@163.com
#发送者密钥
password: 你的邮箱服务密钥
default‐encoding: utf‐8
port: 465 #端口号465或587
protocol: smtp
properties:
mail:
debug:
false
 smtp:
socketFactory:
class: javax.net.ssl.SSLSocketFactory


webhooks: #网络钩子
 - http://127.0.0.1:9134/alarm/receive

依赖

<!-- SkyWalking工具类 .自定义链路追踪 -->        
<dependency>            
    <groupId>org.apache.skywalking</groupId>            
    <artifactId>apm-toolkit-trace</artifactId>            
    <version>8.12.0</version>        
</dependency>
<!-- SkyWalking集成日志框架 -->  
<dependency>
    <groupId>org.apache.skywalking</groupId>
    <artifactId>apm-toolkit-logback-1.x</artifactId>
    <version>8.12.0</version>
</dependency>
<!-- 邮件依赖 --> 
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring‐boot‐starter‐mail</artifactId>
</dependency>