目录

Life in Flow

知不知,尚矣;不知知,病矣。
不知不知,殆矣。

X

Apache SkyWalking

布式架构下的排查问题复杂性

分布式应用架构的运维和诊断的过程变得越来越复杂,例如:接口诊断困难、应用性能诊断复杂、架构分析复杂等难题,传统的监控工具并无法满足,分布式链路系统由此诞生

核心:将一次请求分布式调用,使用 GPS 定位串起来,记录每个调用的耗时、性能等日志,并通过可视化工具展示出来

APM 系统(Application Performance Management)

  • 讲到分布式的链路追踪系统,不得不说说它的前世今生了,APM 系统是可以帮助系统的行为做性能分析的工具
  • APM 系统,它是由谷歌公开的论文提到的,可以说谷歌还是很强的!而到后面,许多的技术公司就基于这边论文的原理,开发出来很多出色的 APM 框架,比如:skywalking、zipkin 等等

SkyWalking

  • Skywalking 是什么

  • 市场上同类解决方案

    • Zipkin 是由 Twitter 开源的链路分析分析工具,在 SpringCloud sleuth 得到了广泛的使用,具有轻量,部署简单的特点
    • Pinpoint 是由韩国人开发的链路追踪应用监控分析工具,基于字节码方式注入。具有支持多种插件,UI 功能强大,接入端没有代码侵入
    • Skywalking 是由国人开发的链路追踪应用监控分析工具,基于字节码方式注入。具有支持多种插件,UI 功能强大,接入端没有代码侵入,现已加入 Apache 孵化器
    • CAT 是大众点评开源的链路追踪分析工具,具有对应用监控的分析、日志的采集、监控报警一系列的监控平台
    项目 Cat Zipkin Skywalking
    链路追踪可视化
    聚合报表 良好 中等
    服务的依赖图 良好 良好
    埋点方式 入侵式 入侵式 非入侵式,字节码增强
    VM 监控指标 没有
    存储机制 MySQL、本地文件 内存、es、MySQL、等 H2、es、MySQL、TIDB 等
    支持语言 java/.net 丰富 丰富
    社区支持 国内 国外主流 apache 支持
    知名使用者 美团、携程 京东、阿里定制不开源 华为、小米
    APM
    开发基础 eBay cal Google Dapper Google Dapper
    支持 webflux 不支持 支持 支持
    GitHub 下载量 12.3k 12.2k 19.3k

Apache Skywalking 特点和整体架构组件

  • Skywalking 特点

    • 具有多种监控手段,可以通过语言探针来获取监控数据
    • 具有多种语言的自动探针。它包括了 Java、.net、node.js 等
    • 具有轻量有高效的特点,不占用大量的服务器资源
    • 清晰的模块化,UI、存储、集群管理都有许多种机制供选择
    • 支持告警,具有优秀的可视化解决方案
    • 可以在多种环境下运行,例如:像注册中心,Eureka 和 RPC 框架 SpringCloud dubbo
  • Skywalking 整体架构

    • 可以分为:上、下、左、右四个部分
    • 上部分(skywalking-agent):这一部分负责从应用程序中收集链路信息,然后把链路信息发送给 skywalking OAP 处理器
    • 下部分(skywalking OAp):负责接收从 skywalking-agent 发送过来的 Tracing 数据信息,然后把数据信息给 Analysis Core 进行分析,把分析到的数据存储到外部的存储器当中,最后面把数据信息给 Query Core 提供查询数据的功能
    • 左部分(Skywalking UI):负责给用户查看链路等信息

  • 部署组件介绍
    • 数据存储(H2/mysql/ElasticSearch)
    • Skywalking-OAP-Server
    • Skywalking UI
    • Skywalking-Agent(项目引入)

阿里云 docker 安装

 1# 1.先安装yml
 2yum install -y yum-utils device-mapper-persistent-data lvm2
 3
 4# 2.设置阿里云镜像
 5sudo yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
 6
 7# 3.查看可安装的docker版本
 8yum list docker-ce --showduplicates | sort -r
 9
10#4. 安装docker
11yum -y install docker-ce-20.10.10-3.el7
12
13#5. 查看docker版本
14docker -v
15
16#6. 启动docker
17systemctl start docker
18
19#7. 查看docker 启动状态
20systemctl status docker
21
22#查看端口占用命令安装
23yum install -y lsof

Skywalking 部署:数据存储 ElasticSearch

  • Elasticsearch 是⼀个开源,是⼀个基于 Apache Lucene 库构建的 RESTFul 搜索引擎. Elasticsearch 是在 Solr 之后⼏年推出的。
  • 它提供了⼀个分布式,多租户能⼒的全⽂搜索引擎,具有 HTTP Web 界⾯(REST)和⽆架构 JSON ⽂档
  • Elasticsearch 的官⽅客户端库提供 Java,Groovy,PHP,Ruby,Perl,Python,.NET 和 JavaScript。

docker 部署 ES7

 1# 创建配置文件目录、数据持久化目录
 2[root@localhost ~]# mkdir -p /mydata/es/config
 3[root@localhost ~]# mkdir -p /mydata/es/data
 4[root@localhost ~]# chmod 777 -R /mydata/es
 5
 6# 创建配置文件并开启远程连接
 7[root@localhost ~]# echo "http.host: 0.0.0.0" >> /mydata/es/config/elasticsearch.yml
 8
 9# 启动运行
10docker run -d --name xdclass_es7 -p 9200:9200 -p 9300:9300 \
11  -e "discovery.type=single-node" -e ES_JAVA_OPTS="-Xms512m -Xmx512m" \
12  -v /mydata/es/config/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml \
13  -v /mydata/es/data:/usr/share/elasticsearch/data \
14  -v /mydata/es/plugins:/usr/share/elasticsearch/plugins elasticsearch:7.6.2
15
16参数说明
17-e "discovery.type=single-node" 设置为单节点
18-e ES_JAVA_OPTS="-Xms512m -Xmx512m" 设置ES的初始内存和最大内存,否则过大启动不了ES
19
20注意:这时候会提示权限不够需要开启权限:chmod 777 -R /mydata/es
21     登录http://ip:9200/_cat/nodes?v=true&pretty
22     记得开放网络安全组 9200 9300
23
24# 访问验证
25http://192.168.10.25:9200/_cat/nodes?v=true&pretty

Skywalking 部署:数据存储 OAP-Server

1docker run --name xd_oap --restart always -d -e TZ=Asia/Shanghai -p 12800:12800 -p 11800:11800 --link xdclass_es7 -e SW_STORAGE=elasticsearch7 -e SW_STORAGE_ES_CLUSTER_NODES=xdclass_es7:9200 apache/skywalking-oap-server:8.5.0-es7
2
3参数:
4--link <name or id>:alias ,添加到另一个容器的链接,可以添加别名或者不加
5–link后面的参数和elasticsearch容器名一致;
6SW_STORAGE=elasticsearch7 是固定的,使用es7;
7SW_STORAGE_ES_CLUSTER_NODES:xdclass_es7也可改为es服务器部署的Ip地址,比如ip:9200

Skywalking 部署:数据存储 UI

 1# 安装ui
 2docker run -d --name xdclass_skywalking-ui \
 3--restart=always \
 4-e TZ=Asia/Shanghai \
 5-p 8080:8080 \
 6--link xd_oap \
 7-e SW_OAP_ADDRESS=xd_oap:12800 \
 8apache/skywalking-ui:8.5.0
 9
10# SkyWalking UI界面访问地址
11http://192.168.10.25:8080/
12
13# 查看ElasticSearch全部索引
14http://192.168.10.25:9200/_cat/indices?v=true&pretty

Apache Skywalking 常见概念和指标

  • 服务(Service)

    • 比如商品微服务
  • 实例(Instance)

    • 比如 机器 1(192.12.41.4)
  • 端点(Endpoint)

    • 比如商品微服务对外提供的接口 /api/v1/product/list,就是端点
  • 用户的满意程度 Service Apdex

    • 全称 Application Performance Index,最大值就是 1, 是一个不断优化的方向

    • 分 3 个指标,T 值代表着用户对应用性能满意的响应时间界限或者说是“门槛”,假如 T 是 0.5 秒

      • 满意:这样的响应时间让用户感到很愉快,响应时间少于 T 秒钟; 0.5 秒内
      • 容忍:慢了一点,但还可以接受,继续这一应用过程,响应时间 T~4T 秒; 0.5~2 秒内
      • 失望:太慢了,受不了了,用户决定放弃这个应用,响应时间超过 4T 秒; 多于 2 秒
  • SLA

    • 服务等级协议,全称:service level agreement,为保障服务的性能和可用性,
    • 9 越多代表全年服务可用时间越长服务更可靠,停机时间越短
11年 = 365天 = 8760小时
2
399.9 = 8760 * 0.1% = 8760 * 0.001 = 8.76小时
4
599.99 = 8760 * 0.0001 = 0.876小时 = 0.876 * 60 = 52.6分钟
6
799.999 = 8760 * 0.00001 = 0.0876小时 = 0.0876 * 60 = 5.26分钟
8
9从以上看来,全年停机5.26分钟才能做到99.999%,即5个9
  • CPM

    • 全称 call per minutes,是吞吐量(Throughput)指标,每分钟请求调用的次数
  • RT

    • Response Time 表示请求响应时间,对于人来说,响应时间最好不要超过 2 秒
  • Percent Response 百分位数统计

    • 表示采集样本中某些值的占比,Skywalking 有 “p50、p75、p90、p95、p99” 一些列值
    • 比如 “p99:360” 表示 99% 请求的响应时间在 360ms 以内

Skywalking RocketBot 整体界面的介绍

Skywalking ui 控制栏

  • 仪表盘:查看被监控服务的运行状态
  • 拓扑图:以拓扑图的方式展现服务的关系
  • 追踪:以接口的列表方式展现
  • 性能剖析:对端点进行采样分析
  • 日志:可查看服务日志
  • 告警:触发告警的告警列表,包括了服务的失败率,超时等待

展示栏(Global 全局维度)

  • Global、Service、Instance、Endpoint 不同展示面板
  • Services load:服务每分钟请求数
  • Slow Services:慢响应服务,单位 ms
  • Un-Health services(Apdex): Apdex 性能指标,1 为满分
  • Slow Endpoint:慢响应端点,单位 ms
  • Global Response Latency:百分比响应延时,不同百分比的延时时间,单位 ms
  • Global Heatmap:服务响应时间热力分布图,根据时间段内不同响应时间的数量显示颜色深度;
  • 底部栏:展示数据的时间区间,点击可以调整

展示栏(Service 服务维度)

  • Service Apdex(数字):当前服务的评分
  • Service Apdex(折线图):不同时间的 Apdex 评分
  • Service Avg Response Times:平均响应延时,单位 ms
  • Service Response Time Percentile:百分比响应延时
  • Successful Rate(数字):请求成功率
  • Successful Rate(折线图):不同时间的请求成功率
  • Servce Load(数字):每分钟请求数
  • Servce Load(折线图):不同时间的每分钟请求数
  • Servce Instances Load:每个服务实例的每分钟请求数

展示栏(Instance 服务维度,不过对于监控 CPU、内存等,Promethus 是个更好的选择)

  • Service instance load:当前实例的每分钟请求数
  • Service Instance Successful Rate:当前实例的请求成功率
  • Service Instance Latency:当前实例的响应延时
  • JVM CPU:jvm 占用 CPU 的百分比
  • JVM Memory:JVM 内存占用大小,单位 m
  • JVM GC Time:JVM 垃圾回收时间,包含 YGC 和 OGC
  • JVM GC Count:JVM 垃圾回收次数,包含 YGC 和 OGC
  • JVM Thread Count:JVM 线程数

追踪

  • 左侧:接口列表,请求为红色表示异常,蓝色表示正常
  • 右侧:追踪列表,API 的各个连接点按照端点的先后顺序和时间排序

性能剖析

  • 新建任务:新建需要分析的端点
  • 左侧列表:对任务进行采样
  • 右侧:每个端点的链路信息


SpringBoot 整合分布式链路追踪 SkyWalking

必须是 JDK11,不然探针将失效
jdk-11.0.1
apache-skywalking-apm-8.5.0
SQL 文件:shop.sql
源码:xdclass-sky.zip

 1###  数据库名字:xdclass_sky_shop
 2SET NAMES utf8mb4;
 3SET FOREIGN_KEY_CHECKS = 0;
 4
 5-- ----------------------------
 6-- Table structure for product
 7-- ----------------------------
 8DROP TABLE IF EXISTS `product`;
 9CREATE TABLE `product` (
10  `id` bigint NOT NULL,
11  `title` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL COMMENT '商品标题',
12  `detail` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL COMMENT '详情',
13  `img` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL COMMENT '图片',
14  `amount` decimal(16,0) DEFAULT NULL COMMENT '现价',
15  PRIMARY KEY (`id`)
16) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
17
18-- ----------------------------
19-- Records of product
20-- ----------------------------
21BEGIN;
22INSERT INTO `product` VALUES (1, '商用短链平台-海量数据项目大课', '打造最佳简历项目的,短链平台大课项目', 'https://file.xdclass.net/video/2022/71-HLSJCL/05.jpeg', 66);
23INSERT INTO `product` VALUES (2, '新一代AlibabaCloud全家桶实战', '高并发分布式项目', 'https://file.xdclass.net/video/2022/71-HLSJCL/05.jpeg', 88);
24INSERT INTO `product` VALUES (3, '小滴课堂永久会员', '观看全部IT专题视频,永久有效', 'https://file.xdclass.net/video/2022/banner/03.jpeg', 999);
25INSERT INTO `product` VALUES (4, '架构大课训练营', '全方位提升综合能力,存储、网络、架构、解决方案', 'https://file.xdclass.net/video/2022/72-ShardingJDBC/banner.jpeg', 79);
26COMMIT;
27
28SET FOREIGN_KEY_CHECKS = 1;

引入依赖

 1<dependency>
 2			<groupId>mysql</groupId>
 3			<artifactId>mysql-connector-java</artifactId>
 4			<version>8.0.26</version>
 5		</dependency>
 6
 7		<dependency>
 8			<groupId>com.baomidou</groupId>
 9			<artifactId>mybatis-plus-boot-starter</artifactId>
10			<version>3.4.1</version>
11		</dependency>

application.properties

1server.port=8081
2#==============================???????========================================
3spring.datasource.driver-class-name =com.mysql.cj.jdbc.Driver
4spring.datasource.url=jdbc:mysql://192.168.10.25:3306/xdclass_sky_shop?useUnicode=true&characterEncoding=utf-8&useSSL=false&&allowPublicKeyRetrieval=true
5spring.datasource.username =root
6spring.datasource.password =123456

开发接口

  • 商品列表接口
  • 商品详情接口

model

 1package net.xdclass.xdclasssky.model;
 2
 3import com.baomidou.mybatisplus.annotation.TableName;
 4import lombok.Data;
 5
 6import java.math.BigDecimal;
 7
 8@TableName("product")
 9@Data
10public class ProductDO {
11
12    private Long id;
13
14    /**
15     * 商品标题
16     */
17    private String title;
18
19    /**
20     * 详情
21     */
22    private String detail;
23
24    /**
25     * 图片
26     */
27    private String img;
28
29    /**
30     * 现价
31     */
32    private BigDecimal amount;
33
34    // set、get方法
35}

model:工具类 jsondata

 1package net.xdclass.xdclasssky.model;
 2
 3import lombok.AllArgsConstructor;
 4import lombok.Data;
 5import lombok.NoArgsConstructor;
 6
 7@Data
 8@NoArgsConstructor
 9@AllArgsConstructor
10public class JsonData {
11    private int code;
12    private Object object;
13    private String msg;
14
15    public static JsonData buildSuccess(Object data) {
16        return new JsonData(0, data, "");
17    }
18}

mapper

1package net.xdclass.xdclasssky.mapper;
2
3import com.baomidou.mybatisplus.core.mapper.BaseMapper;
4import net.xdclass.xdclasssky.model.ProductDO;
5
6public interface ProductMapper extends BaseMapper<ProductDO> {
7}

service:interface

1package net.xdclass.xdclasssky.mapper;
2
3import com.baomidou.mybatisplus.core.mapper.BaseMapper;
4import net.xdclass.xdclasssky.model.ProductDO;
5
6public interface ProductMapper extends BaseMapper<ProductDO> {
7}

service:Impl

 1package net.xdclass.xdclasssky.service.impl;
 2
 3import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 4import net.xdclass.xdclasssky.mapper.ProductMapper;
 5import net.xdclass.xdclasssky.model.ProductDO;
 6import net.xdclass.xdclasssky.service.ProductService;
 7import org.springframework.beans.factory.annotation.Autowired;
 8import org.springframework.stereotype.Service;
 9
10import java.util.List;
11
12@Service
13public class ProductServiceImpl implements ProductService {
14
15    @Autowired
16    private ProductMapper productMapper;
17
18    @Override
19    public List<ProductDO> list() {
20        return productMapper.selectList(new QueryWrapper<>());
21    }
22
23    @Override
24    public ProductDO findDetailById(long productId) {
25        return productMapper.selectOne(new QueryWrapper<ProductDO>().eq("id",productId));
26    }
27
28
29}

controller

 1package net.xdclass.xdclasssky.controller;
 2
 3import net.xdclass.xdclasssky.model.JsonData;
 4import net.xdclass.xdclasssky.model.ProductDO;
 5import net.xdclass.xdclasssky.service.ProductService;
 6import org.springframework.beans.factory.annotation.Autowired;
 7import org.springframework.web.bind.annotation.GetMapping;
 8import org.springframework.web.bind.annotation.PathVariable;
 9import org.springframework.web.bind.annotation.RequestMapping;
10import org.springframework.web.bind.annotation.RestController;
11
12import java.util.List;
13
14@RestController
15@RequestMapping("/api/product/v1")
16public class ProductController {
17
18    @Autowired
19    private ProductService productService;
20
21    /**
22     * 查看商品列表接口
23     *
24     * @return
25     */
26    @GetMapping("list")
27    public JsonData list() {
28
29        List<ProductDO> list = productService.list();
30        return JsonData.buildSuccess(list);
31    }
32
33    /**
34     * 查看商品详情
35     *
36     * @param productId
37     * @return
38     */
39    @GetMapping("/detail/{product_id}")
40    public JsonData detail(@PathVariable("product_id") long productId) {
41        ProductDO productDO = productService.findDetailById(productId);
42        return JsonData.buildSuccess(productDO);
43    }
44}

XdclassSkyApplication

 1package net.xdclass.xdclasssky;
 2
 3import org.mybatis.spring.annotation.MapperScan;
 4import org.springframework.boot.SpringApplication;
 5import org.springframework.boot.autoconfigure.SpringBootApplication;
 6
 7@SpringBootApplication
 8@MapperScan("net.xdclass.xdclasssky.mapper")
 9public class XdclassSkyApplication {
10
11	public static void main(String[] args) {
12		SpringApplication.run(XdclassSkyApplication.class, args);
13	}
14
15}

测试接口 API

1http://192.168.10.88:8081/api/product/v1/list
2http://192.168.10.88:8081/api/product/v1/detail/1

Skywalking Agent(探针)

  • 什么 SkyWalking 探针

    • 探针表示集成到目标系统中的代理或 SDK 库,即收集并格式化数据, 并发送到后端 包括链路追踪和性能指标
  • Skywalking-Agent 的安装和使用

skywalking-agen 目录文件的介绍

  • logs:skywalking agent 的相关运行日志
  • bootstrap-plugins:插件包
  • optional-plugins:插件包(可供选择的插件包,如果需要生效则需要拷贝到 plugins 包下)
  • plugins:插件包(生效的插件包,支持多个框架链路追踪)
  • optional-reporter-plugins:插件包
  • activations:插件包
  • config: 配置文件
  • skywalking-agent.jar:agent 代理的 jar 包(主要是这个!)

skywalking-agent 的使用方式

  • 优先级:探针-> JVM 配置-> 环境变量配置 -> agent.config(优先级低)
  • 第一种-javaagent:/path/to/skywalking-agent.jar={config1}={value1},{config2}={value2}
1-javaagent:../skywalking-agent.jar=agent.service_name=XdclassApp,collector.backend_service=127.0.0.1:11800
  • 第二种:-Dskywalking.[option1]=[value2]
1-javaagent: ../skywalking-agent.jar -Dskywalking.agent.service_name=XdclassApp -Dskywalking.collector.backend_service=127.0.0.1:11800
  • agent.service_name:客户端服务名,在 apm 系统中显示的服务名称
  • collector.backend_service:SW 上传的服务地址

IDEA 编辑器配置 Skywalking-Agent 链路采集

  • agent.service_name:客户端服务名,在 apm 系统中显示的服务名称

  • collector.backend_service:SW AOPServer 的地址上传的服务地址

    1
    

路径中不要出现中文目录

-javaagent:D:\Project\agent\skywalking-agent.jar -Dskywalking.agent.service_name=XdclassShop -Dskywalking.collector.backend_service=192.168.10.25:11800

访问 RocketBot 页面 http://192.168.10.25:8080/

批量请求脚本
http://192.168.10.88:8081/api/product/v1/list
http://192.168.10.88:8081/api/product/v1/detail/1

 1#!/bin//bash                                                                                                                                                              
 2##防火墙HTTP访问测试脚本                                                                                                                                                  
 3echo -e "请输入网址[默认:http://127.0.0.1]"                                                                                                                               
 4read url                                                                                                                                                                  
 5if [[ -z $url ]];then                                                                                                                                                     
 6        url='http://127.0.0.1'                                                                                                                                            
 7fi                                                                                                                                                                        
 8                                                                                                                                                                          
 9echo -e "请输入访问次数[默认:50]"                                                                                                                                         
10read sum                                                                                                                                                                  
11if [[ -z $sum ]];then
12        sum=50
13else
14        if [[ $sum -lt 1 ]];then
15                echo "访问次数设置错误"
16                exit 1
17        fi
18fi
19echo -e "请输入超时时间[默认:5]"
20read out
21if [[ -z "$out" ]];then
22        out=5
23fi
24if [[ $out -ge 1 || $out -le 50 ]];then
25        echo "超时时间设置符合预期"
26else
27         echo "好像不太符合作者的预期喔"
28         exit 1
29fi
30echo -e "输入数据请求超时时间[默认:10]"
31read data
32if [[ -z  $data ]];then
33        data=10
34else
35        if [[ $data -ge 1 || $data -le 30 ]];then
36                echo "数据请求超时时间设置符合预期"
37        else
38                echo "数据请求时间设置不符合预期"
39                exit 1
40        fi
41fi
42echo -e "请输入访问间隔时间[默认:0]"
43read jg
44if [[ -z $jg ]];then
45        jg=0
46else
47        if [[ $jg -ge 0 ]];then
48                echo "设置符合预期"
49        else
50                echo "间隔时间设置不符合预期"
51                exit "1"
52        fi
53fi
54log='./visit.log'
55cmd_file='./cmd.log'
56rm -f $log $cmd_file 
57start_time=`date "+%s"`
58for((i=1;i<=$sum;i++));do
59        cmd="curl --connect-timeout $out -m $data  $url"
60        echo -e "正在执行[$cmd];执行时间[`date`]" | tee -a $cmd_file
61        $cmd > /dev/null
62        if [[ "$?" -eq "0" ]];then
63                echo -e "第[${i}]次访问[$url]  访问时间[`date`]  访问结果: [成功]" | tee -a $log
64        else
65                echo -e "第[${i}]次访问[${url}] 访问时间[`date`] 访问结果: [失败]" | tee -a $log
66        fi
67        sleep $jg
68done
69end_time=`date "+%s"`
70time=`expr $end_time - $start_time`
71c=`cat $log | grep "成功" | wc -l`
72s=`cat $log | grep "失败" | wc -l`
73echo -e "测试完成,测试结果如下:
74本次访问URL: [$url]
75本次访问总数: [$sum]
76访问成功次数: [$c]
77访问失败次数: [$s]
78访问日志文件: [$cmd_file]
79访问结果日志: [$log]
80测试过程耗时: [$time]秒"

定义 SkyWalking 链路追踪配置实战

  • 什么是 TraceId

    • 用来标识一条请求链路,一条请求链路中包含一个 Trace ID,多个 Span ID
  • 背景

    • 对业务代码进行链路追踪,方便排查问题
    • 比如,某个接口请求耗时慢,想对业务接口方法进行追踪
    • controller->service 方法,记录业务方法加入到链路中,记录入参、返回值等
  • 缺点

    • 代码有侵入性

添加依赖

1<dependency>
2			<groupId>org.apache.skywalking</groupId>
3			<artifactId>apm-toolkit-trace</artifactId>
4			<version>8.5.0</version>
5		</dependency>
  • 业务方法添加注解
    POJO 记得重写 toString 方法
 1public class ProductServiceImpl implements ProductService {
 2
 3    @Autowired
 4    private ProductMapper productMapper;
 5
 6    @Override
 7    public List<ProductDO> list() {
 8        return test();
 9    }
10
11    @Trace
12    @Tags(
13            {       //arg[1] 代表第二个参数
14                    @Tag(key = "test-output", value = "returnedObj")
15            }
16    )
17    public List<ProductDO> test() {
18        try {
19            TimeUnit.SECONDS.sleep(1);
20        } catch (InterruptedException e) {
21            throw new RuntimeException(e);
22        }
23        return productMapper.selectList(new QueryWrapper<>());
24    }
25
26
27    @Override
28    @Trace
29    @Tags(
30            {       //arg[1] 代表第二个参数
31                    @Tag(key = "findDetailById-input", value = "arg[0]"),
32                    @Tag(key = "findDetailById-output", value = "returnedObj")
33            }
34    )
35    public ProductDO findDetailById(long productId) {
36        return productMapper.selectOne(new QueryWrapper<ProductDO>().eq("id",productId));
37    }
38}

入参

返回值

SkyWalking-RocketBot 性能剖析

性能剖析

  • 新建任务:新建需要分析的端点
  • 左侧列表:对任务进行采样
  • 右侧:每个端点的链路信息
  • 性能分析:可以查看对应方法的调用栈,找出问题点
    • 直接定位到代码方法和代码行
  • 注意:一个服务在监控持续时间内只能设置一个端点监控任务

链路追踪-日志和 RPC 上报

添加依赖

1<dependency>
2			<groupId>org.apache.skywalking</groupId>
3			<artifactId>apm-toolkit-logback-1.x</artifactId>
4			<version>8.5.0</version>
5		</dependency>

src/main/resources/logback.xml

 1<?xml version="1.0" encoding="UTF-8"?>
 2<configuration>  
 3    <!-- 控制台输出 -->
 4    <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
 5        <encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
 6            <layout class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.TraceIdPatternLogbackLayout">
 7                <Pattern>%d{yyyy-MM-dd HH🇲🇲ss.SSS} [%tid] [%thread] %-5level %logger{36} -%msg%n</Pattern>
 8            </layout>
 9        </encoder>
10    </appender>
11
12    <!--系统操作日志-->
13    <root level="INFO">  
14        <appender-ref ref="console"/> 
15    </root>
16</configuration>

代码打印日志

 1import org.slf4j.Logger;
 2import org.slf4j.LoggerFactory;
 3
 4Logger logger = LoggerFactory.getLogger(ProductController.class);
 5
 6logger.info("分布式链路追踪测试测试!!!");
 7
 8
 9### 控制台输出  TID TraceID
102023-10-09 18:18:33.931 [TID:2166b89c7dd243e199b0f3157301385c.64.16968467138960001] [http-nio-8081-exec-1] INFO  n.x.x.controller.ProductController -分布式链路追踪测试测试!!!

将日志上传到 skywalking oap-server 中,查看更方便(日志打印输出到 aop-server)

src/main/resources/logback.xml 中追加 <!-- skywalking grpc 日志收集上报服务端 8.4.0版本后支持 -->

 1<?xml version="1.0" encoding="UTF-8"?>
 2<configuration>  
 3    <!-- 控制台输出 -->
 4    <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
 5        <encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
 6            <layout class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.TraceIdPatternLogbackLayout">
 7                <Pattern>%d{yyyy-MM-dd HH🇲🇲ss.SSS} [%tid] [%thread] %-5level %logger{36} -%msg%n</Pattern>
 8            </layout>
 9        </encoder>
10    </appender>
11
12    <!-- skywalking grpc 日志收集上报服务端 8.4.0版本后支持 -->
13    <appender name="grpc-log" class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.log.GRPCLogClientAppender">
14        <encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
15            <layout class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.mdc.TraceIdMDCPatternLogbackLayout">
16                <Pattern>%d{yyyy-MM-dd HH🇲🇲ss.SSS} [%tid] [%thread] %-5level %logger{36} -%msg%n</Pattern>
17            </layout>
18        </encoder>
19    </appender>
20
21    <!--系统操作日志-->
22    <root level="INFO">  
23        <appender-ref ref="console"/> 
24        <appender-ref ref="grpc-log"/> 
25    </root>
26</configuration>

skywaling agent 默认是上传到本地的 oap,如果 oap server 地址不是本地,则需要单独配置 oapserver 地址

  • agent 文件夹里面 config 配置

D:\Project\new\apache-skywalking-apm-bin\agent\config\agent.config

 1#日志数据的grpc服务器的主机
 2plugin.toolkit.log.grpc.reporter.server_host=${SW_GRPC_LOG_SERVER_HOST:192.168.10.25} 
 3#日志数据的grpc服务器的端口
 4plugin.toolkit.log.grpc.reporter.server_port=${SW_GRPC_LOG_SERVER_PORT:11800}
 5#日志数据的最大大小
 6plugin.toolkit.log.grpc.reporter.max_message_size=${SW_GRPC_LOG_MAX_MESSAGE_SIZE:10485760}
 7#发送数据时将超时多长时间。单位是秒
 8plugin.toolkit.log.grpc.reporter.upstream_timeout=${SW_GRPC_LOG_GRPC_UPSTREAM_TIMEOUT:30}
 9
10#下面是正式:不加中文注释
11plugin.toolkit.log.grpc.reporter.server_host=${SW_GRPC_LOG_SERVER_HOST:192.168.10.25}
12plugin.toolkit.log.grpc.reporter.server_port=${SW_GRPC_LOG_SERVER_PORT:11800}
13plugin.toolkit.log.grpc.reporter.max_message_size=${SW_GRPC_LOG_MAX_MESSAGE_SIZE:10485760}
14plugin.toolkit.log.grpc.reporter.upstream_timeout=${SW_GRPC_LOG_GRPC_UPSTREAM_TIMEOUT:30}

重启 idea 项目会在 D:\Project\new\apache-skywalking-apm-bin\agent\logs\ 目录下生成 skywalking-api.log 文件

  • 监控业务相关接口性能,超过阈值则触发告警功能
  • 通过调用 webhook 接口进行触发,具体的 webhook 接口地址可以自行定义路径
    • 注意:要 OAP Server 的网络可以触发的 webhook 接口
  • 开发人员可以在 webhook 接口中编写告警方式,比如邮件、短信等,就是一个 http 接口

链路追踪-告警模块和 WebHook

  • 监控业务相关接口性能,超过阈值则触发告警功能
  • 通过调用 webhook 接口进行触发,具体的 webhook 接口地址可以自行定义路径
    • 注意:要 OAP Server 的网络可以触发的 webhook 接口
  • 开发人员可以在 webhook 接口中编写告警方式,比如邮件、短信等,就是一个 http 接口

  • Apache Skywalking 默认的告警规则配置

    • 安装目录下的 config 文件夹下 alarm-settings.yml 文件

    • 默认内置多个规则

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

      • metrics-name 脚本中的度量名称
      • threshold 阈值
      • op 比较操作符,可以设定 >,<,=
      • period 多久检查一次当前的指标数据是否符合告警规则,单位分钟
      • count 达到多少次后,触发告警消息
      • silence-period 在多久时间之内,忽略相同的告警消息,在时间 T 触发了某告警,那么在(T+10)这个时间段,不会再次触发相同告警
      • message 告警消息内容
      • webhooks 配置告警产生时的触发的调用地址

开启 oap-server 的告警 webhook 接口
1、oap-server 规则触发,发送消息到 SpringBoot 项目的自定义 web-hook
2、SpringBoot 项目的自定义 web-hook
记得重启 oap-server 服务读取最新的配置文件 /skywalking/config/alarm-settings.yml

 1### 不需要修改容器端口!!!
 2# 进入aop-server容器修改配置文件
 3# oap-server容器配置文件的路径
 4bash-5.0# vi /skywalking/config/alarm-settings.yml
 5
 6# 1、查看容器映射端口情况
 7[root@localhost ~]# docker port xd_oap
 811800/tcp -> 0.0.0.0:11800
 911800/tcp -> [::]:11800
1012800/tcp -> 0.0.0.0:12800
1112800/tcp -> [::]:12800
12
13# 2、停止运行容器
14[root@localhost ~]# docker stop xd_oap
15
16# 4、查看容器完整的hash_of_the_container数值
17[root@localhost ~]# docker inspect xd_oap | grep Id
18        "Id": "3a9a248620fc6fffa815491b13652188732ab716bedc41f36192cfec04393f35",
19
20# 5、进到/var/lib/docker/containers 目录下找到与全 Id 相同的目录,修改 其中的hostconfig.json 和 config.v2.json文件
21
22[root@localhost ~]# vim /var/lib/docker/containers/3a9a248620fc6fffa815491b13652188732ab716bedc41f36192cfec04393f35/hostconfig.json
23"PortBindings":{"8081/tcp":[{"HostIp":"","HostPort":"8081"}]}
24[root@localhost ~]# vim /var/lib/docker/containers/3a9a248620fc6fffa815491b13652188732ab716bedc41f36192cfec04393f35/config.v2.json
25"ExposedPorts":{"8081/tcp":{},"80/tcp":{}}
26
27# 6、重启docker
28[root@localhost ~]# systemctl restart docker
29
30# 7、启动容器
31[root@localhost ~]# docker start xd_oap
32xd_oap
33[root@localhost ~]# docker port xd_oap
348081/tcp -> 0.0.0.0:8081
358081/tcp -> [::]:8081
3611800/tcp -> 0.0.0.0:11800
3711800/tcp -> [::]:11800
3812800/tcp -> 0.0.0.0:12800
3912800/tcp -> [::]:12800
40
41# 8、修改oap-server容器配置文件的路径
42docker exec -it xd_oap /bin/bash
43bash-5.0# vi /skywalking/config/alarm-settings.yml
44#webhooks:
45#  - http://127.0.0.1/notify/
46#  - http://127.0.0.1/go-wechat/
47   - http://127.0.0.1:8081/webhook/
48
49# 9、重启容器
50[root@localhost ~]# docker restart xd_oap

src/main/java/net/xdclass/xdclasssky/model/AlarmMessage.java

 1package net.xdclass.xdclasssky.model;
 2
 3import lombok.Data;
 4
 5@Data
 6public class AlarmMessage {
 7    private int scopeId;
 8    private String scope;
 9    private String name;
10    private String id0;
11    private String id1;
12    private String ruleName;
13    private String alarmMessage;
14    private long startTime;
15    private transient int period;
16    private transient boolean onlyAsCondition;
17
18}

src/main/java/net/xdclass/xdclasssky/controller/CallbackController.java

 1package net.xdclass.xdclasssky.controller;
 2
 3import net.xdclass.xdclasssky.model.AlarmMessage;
 4import org.springframework.web.bind.annotation.GetMapping;
 5import org.springframework.web.bind.annotation.PostMapping;
 6import org.springframework.web.bind.annotation.RequestBody;
 7import org.springframework.web.bind.annotation.RestController;
 8
 9import java.util.ArrayList;
10import java.util.List;
11@RestController
12public class CallbackController {
13    private List<AlarmMessage> messageList = new ArrayList<>();
14
15    /**
16     * 要跟 oap-server 暴露的接口保持一致  (Spingboot项目自定义的webhook地址)
17     *  - http://192.168.10.88:8081/webhook/
18     * @param alarmMessageList
19     */
20    @PostMapping("/webhook")
21    public void  webhook(@RequestBody List<AlarmMessage> alarmMessageList){
22        System.out.println("收到消息:" +alarmMessageList);
23        messageList = alarmMessageList;
24    }
25
26    /**
27     * 临时接口方便查看
28     * @return
29     */
30    @GetMapping("/show")
31    public List<AlarmMessage> show(){
32        return messageList;
33    }
34}

测试请求路径

  • 修改睡眠时间为 2 秒,模拟接口响应慢

控制台收到消息

1收到消息:[AlarmMessage(scopeId=2, scope=SERVICE_INSTANCE, name=927a70eb91d745aab7d9bfa28657ef4b@192.168.10.88 of XdclassShop, id0=WGRjbGFzc1Nob3A=.1_OTI3YTcwZWI5MWQ3NDVhYWI3ZDliZmEyODY1N2VmNGJAMTkyLjE2OC4xMC44OA==, id1=, ruleName=service_instance_resp_time_rule, alarmMessage=Response time of service instance 927a70eb91d745aab7d9bfa28657ef4b@192.168.10.88 of XdclassShop is more than 1000ms in 2 minutes of last 10 minutes, startTime=1696859365690, period=0, onlyAsCondition=false)]

整合钉钉报警

application.properties

1server.port=8081
2spring.datasource.driver-class-name =com.mysql.cj.jdbc.Driver
3spring.datasource.url=jdbc:mysql://192.168.10.25:3306/xdclass_sky_shop?useUnicode=true&characterEncoding=utf-8&useSSL=false&&allowPublicKeyRetrieval=true
4spring.datasource.username =root
5spring.datasource.password =123456
6dingtalk.robot.webhook = https://oapi.dingtalk.com/robot/send?access_token=ed1d4c0432899cdc43fd874c117869695f1bed7fa5e74b37efcc4d763ae1b623

src/main/java/net/xdclass/xdclasssky/service/DingTalkRobotService.java

 1package net.xdclass.xdclasssky.service;
 2
 3import org.springframework.beans.factory.annotation.Value;
 4import org.springframework.http.HttpEntity;
 5import org.springframework.http.HttpHeaders;
 6import org.springframework.http.MediaType;
 7import org.springframework.stereotype.Service;
 8import org.springframework.web.client.RestTemplate;
 9
10@Service
11public class DingTalkRobotService {
12
13    @Value("${dingtalk.robot.webhook}")
14    private String webhook;
15
16    private RestTemplate restTemplate = new RestTemplate();
17
18    public void sendMessage(String message) {
19        HttpHeaders headers = new HttpHeaders();
20        headers.setContentType(MediaType.APPLICATION_JSON);
21
22        String payload = "{\"msgtype\":\"text\",\"text\":{\"content\":\"" + message + "\"}}";
23        HttpEntity<String> entity = new HttpEntity<>(payload, headers);
24
25        restTemplate.postForEntity(webhook, entity, String.class);
26    }
27}

src/main/java/net/xdclass/xdclasssky/controller/CallbackController.java

 1package net.xdclass.xdclasssky.controller;
 2
 3import net.xdclass.xdclasssky.model.AlarmMessage;
 4import net.xdclass.xdclasssky.service.DingTalkRobotService;
 5import org.springframework.beans.factory.annotation.Autowired;
 6import org.springframework.web.bind.annotation.GetMapping;
 7import org.springframework.web.bind.annotation.PostMapping;
 8import org.springframework.web.bind.annotation.RequestBody;
 9import org.springframework.web.bind.annotation.RestController;
10
11import java.util.ArrayList;
12import java.util.List;
13@RestController
14public class CallbackController {
15    private List<AlarmMessage> messageList = new ArrayList<>();
16
17    @Autowired
18    private DingTalkRobotService dingTalkRobotService;
19
20    /**
21     * 要跟 oap-server 暴露的接口保持一致   (Spingboot项目自定义的webhook地址)
22     *  - http://192.168.10.88:8081/webhook/
23     * @param alarmMessageList
24     */
25    @PostMapping("/webhook")
26    public void  webhook(@RequestBody List<AlarmMessage> alarmMessageList){
27        System.out.println("收到消息:" +alarmMessageList);
28        dingTalkRobotService.sendMessage(alarmMessageList.get(0).getAlarmMessage());
29        messageList = alarmMessageList;
30    }
31
32    /**
33     * 临时接口方便查看
34     * @return
35     */
36    @GetMapping("/show")
37    public List<AlarmMessage> show(){
38        return messageList;
39    }
40}

jar 方式打包运行整合 Skywalking

  • 项目打包

    • SpringBoot 项目和 SpringCloud 项目都一样,jar 方式运行

    • 通过 Java -jar 加入参数

    • 项目打包

      1mvn install
      
  • 例子

    1java -jar -javaagent:/Users/xdclass/Desktop/agent/skywalking-agent.jar -Dskywalking.agent.service_name=XdclassShop -Dskywalking.collector.backend_service=127.0.0.1:11800 xdclass-sky-0.0.1-SNAPSHOT.jar
    

作者:Soulboy