微服务链路追踪组件 SkyWalking

前言

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

  1. 如何串联整个调用链路,快速定位问题
  2. 如何捋清各个微服务的依赖关系
  3. 如何进行各个微服务接口的性能分析
  4. 如何跟踪整个业务流程的调用处理顺序

一、什么是 SkyWalking

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

中文文档地址

中文文档地址

1.1、链路追踪框架对比

  1. Zipkin 是 Twitter 开源的调用链分析工具,目前基于springcloud sleuth 得到了广泛的使用,特点是轻量,使用部署简单。
  2. Pinpoint 是韩国人开源的基于字节码注入的调用链分析,以及应用监控分析工具。特点是支持多种插件, UI 功能强大,接入端无代码侵入。
  3. SkyWalking 是本土开源的基于字节码注入的调用链分析,以及应用监控分析工具。特点是支持多种插件, UI 功能较强,接入端无代码侵入。目前已加入 Apache 孵化器。
  4. CAT 是大众点评开源的基于编码和配置的调用链分析,应用监控分析,日志采集,监控报警等一系列的监控平台工具。
项目 Cat Zipkin Skywalking
调用链可视化
聚合报告 非常丰富 较丰富
服务依赖图 简单 简单
埋点方式 侵入式 侵入式 非侵入,字节码增强
VM监控指标
支持语言 java/.net 丰富 java/.net/Nodejs/php/go
存储机制 mysql(报表)、本地文件/HDFS(调用链) 内存、es、mysql等 H2、es等
社区支持 主要在国内 国外主流 Apache 支持
使用案例 美团、携程、陆金所 京东、阿里定之后不开源 华为、小米、当当、微众银行
APM
开发基础 eBay cal Google Dapper Google Dapper
是否支持 webflux
Github stars(2022.8) 17.1k 15.6k 20k

在三种链路监控组件中, skywalking的探针对吞吐量的影响最小。

1.2、Skywalking 主要特性

1、多种监控手段,可以通过语言探针和 service mesh 获得监控的数据。
2、支持多种语言自动探针(agent),包括Java,.NET Core 和 Node.JS。
3、轻量高效,无需大数据平台和大量的服务器资源。
4、模块化,UI、存储、集群管理都有多种机制可选。
5、支持告警。
6、优秀的可视化解决方案。

二、SkyWalking 环境搭建部署

微服务链路追踪组件 SkyWalking

  • skywalking agent和业务系统绑定在一起,负责收集各种监控数据
  • Skywalking oapservice 是负责处理监控数据的,比如接受 skywalking agent 的监控数据,并存储在数据库中;接受 skywalking webapp 的前端请求,从数据库查询数据,并返回数据给前端。Skywalking oapservice 通常以集群的形式存在。
  • skywalking webapp,前端界面,用于展示数据。
  • 用于存储监控数据的数据库,比如mysql、elasticsearch 等。

2.1、下载 SkyWalking

下载地址

OAP Server 下载

微服务链路追踪组件 SkyWalking

Java-agent 接入

微服务链路追踪组件 SkyWalking

OAP 目录结构

  • webapp:UI 前端(web监控页面)的 jar 包和配置文件
  • oap-libs:后台应用的 jar 包,以及它依赖的 jar 包,里面有一个 server-starter.jar 启动程序
  • config:启动后台应用程序的配置文件,是使用的各种配置
  • bin:各种脚本,一般使用脚本 startup.sh 来启动 web 页面和对应的后台应用:
    • oapService.*:默认使用后台程序的启动脚本;(使用的是默认模式启动,还支持其他模式)
    • oapServiceInit.*:使用 init 模式启动;在此模式下,OAP 服务器启动以执行初始化工作,用于集群环境。为了防止多节点同时启动导致冲突,单节点执行oapServiceInit.sh进行初始化,其他节点执行oapServiceNoInit.sh 等待初始化完成后再启动。
    • oapServiceNoInit.*:使用 no init 模式启动;在此模式下,OAP 服务器不进行初始化
    • webappService.*:UI 前端的启动脚本
    • startup.*:同时启动oapService.*webappService.*脚本;

Java Agents 目录结构

  • activations:工具包
  • bootstrap-plugins:启动插件,默认加载
  • config:配置文件
  • optional-plugins:可选拓展插件,启动不加载,如需加载将其移入 plugins 目录下
  • optional-reporter-plugins:可选统计类插件,启动不加载
  • plugins:服务类插件
  • skywalking-agent.jar:客户端主程序,需要被服务启动时引用

2.2、搭建 SkyWalking OAP 服务

为了方式端口冲突,将前端页面地址进行修改

vim webapp/webapp.yml

server:
  port: 8868

微服务链路追踪组件 SkyWalking

SkyWalking UI 界面是通过请求 SkyWalking OAP 服务来获得的

启动脚本bin/startup.sh

$ bash startup.sh 
SkyWalking OAP started successfully!
SkyWalking Web Application started successfully!

日志信息存储在 logs 目录

logs/
├── oap.log
├── skywalking-oap-server.log
└── webapp-console.log

启动成功之后会启动两个服务,一个是 skywalking-oap-server,一个是 skywalking-web-ui
skywalking-oap-server 服务启动后会暴露 11800 和 12800 两个端口,分别为手机监控数据的端口 11800 和接受前端请求的端口 12800,修改端口可以修改config/application.yml

2.3、SkyWalking 中三个概念

  • 服务(Service):表示对请求提供相同行为的一系列或一组工作负载,在使用 Agent 时,可以定义服务的名字;
  • 服务实例(Service Instance):上述的一组工作负载中的每一个工作负载称为一 个实例,一个服务实例实际就是操作系统上的一个真实进程;
  • 端点(Endpoint):对于特定服务所接收的请求路径,如 HTTP 的 URI 路径和 gRPC 服务的类名+方法签名;

三、SkyWalking 接入微服务

3.1、linux 通过 jar 包方式接入

准备一个 springboot 程序,打包成可执行 jar 包,写一个 shell 脚本,在启动项目的 shell 脚本上,通过 -javaagent 参数进行配置 skywalking agent 来跟踪微服务;

startup.sh 脚本

#! /bin/bash
# SkyWalking Agent 配置
# Agent 名字,一般使用`spring.application.name`
export SW_AGENT_NAME=springboot-skywalking-demo
# 配置 Collector 地址
export SW_AGENT_COLLECTOR_BACKEND_SERVICERS=127.0.0.1:11800
export JAVA_AGENT=-javaagent:skywalking-agent.java 地址
# jar 启动
java $JAVA_AGENT -jar spring-boot-skywalking-demo.jar

等同于

java -javaagent:skywalking-agent.jar 地址 -DSW_AGENT_COLLECTOR_BACKEND_SERVICERS=127.0.0.1:11800 -DSW_AGENT_NAME=springboot-skywalking-demo -jar spring-boot-skywalking-demo.jar

参数名对应 agent/config/agent.config 配置文件中的属性
属性对应源码:org.apache.skywalking.apm.agent.core.conf.Config.java

# The service name in UI
agent.service_name=${SW_AGENT_NAME:Your_ApplicationName}
# Backend service addresses
collector.backend_sercvice=${SW_AGENT_COLLECTOR_BACKEND_SERVICES:127.0.0.1:11800}

3.2、Windows 环境 - IDEA 中使用 SkyWalking

在运行程序中配置 jvm 参数

# 指定 agent.jar 所在位置
-javaagent:/Users/hudu/Environment/skywalking/skywalking-agent/skywalking-agent.jar
# 指定服务名字
-DSW_AGENT_NAME=服务名称
# 指定 skywalking 的 collector 服务的 IP 及端口
-DSW_AGENT_COLLECTOR_BACKEND_SERVICES=127.0.0.1:11800

-javaagent 必须绑定本机物理路径的 skywalking-agent.jar
具体效果参考下面的接入多个微服务

3.2、Skywalking 跨多个微服务跟踪

Skywalking 跨多个微服务跟踪,只需要每个微服务启动时添加 javaagent 参数即可。

-javaagent:/Users/hudu/Environment/skywalking/skywalking-agent/skywalking-agent.jar
-DSW_AGENT_NAME=服务名称
-DSW_AGENT_COLLECTOR_BACKEND_SERVICES=127.0.0.1:11800

测试:
启动微服务,接入 seata 的 order 和 stock 服务

微服务链路追踪组件 SkyWalking

微服务链路追踪组件 SkyWalking

请求一个接口进行测试http://localhost:8088/order/add,可以看到 skywalking 控制台中已经有服务记录,调用链路图如下所示。

微服务链路追踪组件 SkyWalking

四、Skywalking 持久化跟踪数据

默认使用的是 H2 内存数据库
config/application.yml

storage:
  selector: ${SW_STORAGE:mysql}
  mysql:
    properties:
    jdbcUrl: ${SW_JDBC_URL:"jdbc:mysql://localhost:3306/swtest?rewriteBatchedStatements=true"}
    dataSource.user: ${SW_DATA_SOURCE_USER:root}
    dataSource.password: ${SW_DATA_SOURCE_PASSWORD:root@1234}

创建 swtest 数据库
启动 skywalking 服务的时候会自动创建需要的表

oap-lib目录中添加 mysql-connector-java.jar 包

五、自定义 SkyWalking 链路追踪

如果我们希望对项目中的业务方法实现链路追踪,方便我们排查问题,可以使用如下的代码

5.1、引入依赖

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

5.2、@Trace 将方法加入追踪链路

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

微服务链路追踪组件 SkyWalking

5.3、加入 @Tags 或 @Tag

我们还可以为追踪链路增加其他额外的信息,比如记录参数和返回信息。实现方式:在方法上增加@Tag或者@Tags。

@Tag 注解中,key=方法名,value=returnedObj 返回值,arg[0] 参数

@GetMapping("/get/{id}")
@Trace
@Tags({@Tag(key="result",value = "returnedObj"),
  @Tag(key="param",value = "arg[0]")})
public Order get(@PathVariable Integer id) {
  return orderService.get(id);
}

可以看到方法参数和返回值都追踪到了。

微服务链路追踪组件 SkyWalking

微服务链路追踪组件 SkyWalking

六、性能分析

skywalking 的性能分析,在根据服务名称、端点名称,以及相应的规则建立了任务列表后,在调用了此任务列表的端点后。skywalking 会自动记录,剖析当前端口,生成剖析结果,具体流程如图:

微服务链路追踪组件 SkyWalking

微服务链路追踪组件 SkyWalking
然后请求服务至少三次,由于设置了采样次数

微服务链路追踪组件 SkyWalking

七、集成日志框架

官方配置地址

这里以 logback 为例

7.1、引入依赖

<!--配置-->
<dependency>
  <groupId>org.apache.skywalking</groupId>
 <artifactId>apm-toolkit-logback-1.x</artifactId>
 <version>8.11.0</version>
</dependency>

logback-spring.xml 配置

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <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>${CONSOLE_LOG_PATTERN}</Pattern>
            </layout>
        </encoder>
    </appender>
    <root level="INFO">
        <appender-ref ref="console" />
    </root>
</configuration>

添加 tid

微服务链路追踪组件 SkyWalking

通过 日志的 tid 去 skywalking 中查询接口

微服务链路追踪组件 SkyWalking

微服务链路追踪组件 SkyWalking

通过 gRpc 方式将日志反馈到 skywalking 中去

微服务链路追踪组件 SkyWalking

logback-spring.xml 中 添加

<!--日志配置-->
<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="console" />
 <appender-ref ref="grpc-log" />
</root>

此时可以看到 skywalking 中增加了日志信息。
微服务链路追踪组件 SkyWalking

注意事项

如果 Skywalking 与服务不在同一服务器内,需要进行配置的修改,否则日志无法上报。
skywalking-agent/config/agent.config配置文件中添加如下配置

plugin.toolkit.log.grpc.reporter.server_host=$[SW_GRPC_LOG_SERVER_HOST:192.168.33.62]
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]

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

配置名 解释 默认值
plugin.toolkit.log.transmit_formatted 是否以格式化或未格式化的格式传输记录的数据 true
plugin.toolkit.grpc.reporter.server_host 指定要向其报告日志数据的grpc服务器的主机 127.0.0.1
plugin.toolkit.grpc.reporter.server_port 指定要向其报告日志数据的grpc服务器的端口 11800
plugin.toolkit.log.grpc.reporter.max_message_size 指定grcp客户端要报告的日志数据的最大大小 10485760
plugin.toolkit.log.grpc.reporter.upstream_timeout 客户端向上游发送数据时将超时多长时间,单位秒 30

八、SkyWalking 告警功能

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

  1. 告警规则:它们定义了应该如何处罚度量告警,应该考虑什么条件
  2. Webhook(网络钩子):定义警告触发时,哪些服务终端需要被告知

8.1、告警规则

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-setting.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:告警消息

例如

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.

表示三分钟到十分钟之内,如果请求次数大于 5 次,并且有接口请求超过 1 秒,就进行报警

8.2、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,
    "tags": [{
        "key": "level",
        "value": "WARNING"
     }]
}, {
  "scopeId": 1,
  "scope": "SERVICE",
  "name": "serviceB",
  "id0": "23",
  "id1": "",
    "ruleName": "service_resp_time_rule",
  "alarmMessage": "alarmMessage yyy",
  "startTime": 1560524171000,
    "tags": [{
        "key": "level",
        "value": "CRITICAL"
    }]
}]
  • scopeId, scope. 所有范围都在 org.apache.skywalking.oap.server.core.source.DefaultScopeDefine 中定义
  • name. 目标范围实体名称。请按照实体名称定义
  • id0. 范围实体的 ID 与名称匹配。使用关系范围时,它是源实体 ID
  • id1. 使用关系范围时,它将是目标实体 ID。否则,它是空的
  • ruleName. 您在 中配置的规则名称alarm-settings.yml
  • alarmMessage. 报警消息
  • startTime. 告警时间以毫秒为单位,介于当前时间和 UTC 时间 1970 年 1 月 1 日午夜之间

官方文档地址

config/alarm-settings.yml配置中配置钩子

webhooks:
  - http://127.0.0.1:8088/alarm/notify

定义 AlarmMessage

import lombok.Data;
//import org.apache.skywalking.oap.server.core.analysis.manual.searchtag.Tag;

import java.util.List;

@Data
public class SwAlarmMessage {
    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;

    @Data
    public static class Tag {
        private String key;
        private String value;
    }
}

控制层代码

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

    Logger log = LoggerFactory.getLogger(this.getClass());

    /**
     * 接收Skywalking服务的告警通知并发送至邮箱
     * 必须是post请求
     * @param alarmList
     */
    @PostMapping("/notify")
    public void receive(@RequestBody List<SwAlarmMessage> alarmList){
//        SimpleMailMessage mailMessage = new SimpleMailMessage();
//        // 发送者邮箱
//        mailMessage.setFrom("from");
//        // 接收者邮箱
//        mailMessage.setTo("to");
//        // 主题
//        mailMessage.setSubject("主题");
//        // 邮件内容
//        String content = getContent(alarmList);
//        mailMessage.setText("content");
//        sender.send(mailMessage);

        String content = getContent(alarmList);
        log.info("告警邮箱已发送..."+content);

    }

    private String getContent(List<SwAlarmMessage> alarmList){
        StringBuilder sb = new StringBuilder();
        alarmList.forEach(message -> sb.append("scopeId: ").append(message.getScopeId())
                .append("\nscope: ").append(message.getScope())
                .append("\n目标 Scope 的实体类名称: ").append(message.getName())
                .append("\nScope 实体类的 ID: ").append(message.getId0())
                .append("\nid1: ").append(message.getId1())
                .append("\n告警规则名称: ").append(message.getRuleName())
                .append("\n告警消息内容: ").append(message.getAlarmMessage())
                .append("\n告警时间: ").append(message.getStartTime())
                .append("\n标签: ").append(message.getTags())
                .append("\n\n-----------------\n\n "));

        return sb.toString();
    }
}

api 网关配置

spring:
    gateway:
      # 路由规则
      routes:
        - id: alarm_route
          uri: lb://sw-alarm-server
          predicates:
            - Path=/alarm/**

请求接口,由于接口响应时间慢,skywalking 发送的告警。

微服务链路追踪组件 SkyWalking

微服务链路追踪组件 SkyWalking

八、Skywalking 高可用

Sykwalking 集群是集那个skywalking oap 作为一个服务注册到 nacos 上,只要 skywalking oap 服务没有全部宕机,保证有一个 skywalking oap 在运行,就能进行跟踪

搭建 skywalking oap 集群需要:

  1. 至少一个 Nacos(也可以是 nacos 集群)
  2. 至少一个 ElasticSearch/mysql(也可以是 es/mysql 集群)
  3. 至少 2 个 skywalking oap 服务
  4. 至少 1 个 UI(也可以是集群,多个,用 Nginx 代理统一入口)

8.1、修改 config/application.yml 文件

使用 Nacos 作为注册中心,默认为单机模式

微服务链路追踪组件 SkyWalking

微服务链路追踪组件 SkyWalking

8.2、配置 UI 服务 webapp/webapp.yml 文件中的 oap-service,填写多个地址

微服务链路追踪组件 SkyWalking

8.3、启动服务测试

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

-DSW_AGENT_COLLECTOR_BACKEND_SERVICES=192.168.33.61:11800,192.168.33.62:11800
本作品采用《CC 协议》,转载必须注明作者和本文链接
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!
未填写
文章
247
粉丝
18
喜欢
217
收藏
62
排名:731
访问:9753
私信
所有博文
社区赞助商