SkyWalking快速入门

参考课程:2023深入理解SkyWalking微服务链路追踪实战_哔哩哔哩_bilibili

SkyWalking 主要用于分布式系统的性能监控和故障排查,它通过收集和分析各个服务之间的调用关系、性能指标等数据,帮助开发者和运维人员快速了解系统的运行状态,定位性能瓶颈和故障。常用于用户指标分析,性能指标分析,告警功能,服务依赖关系可视化


SkyWalking相关概念

基本了解

分布式调用链标准-openTracing

Span-节点

跟踪树结构

不同系统之间RPC,HTTP,MQ之间的调用是有区别的,那我们应该如何区分这些数据呢?

有一些特定的变量,SpanName SpanId traceId spanParentId

植入点:我们监控的地方,我们要尽可能零侵入进行代码采集

采样率:采集我们的信息,为了知道哪里出现了问题从而尽可能提升性能


Opentracing标准详解

我们要根据规范来设计我们的Tag的key和value

一个调用链是由多个Span组成的,span和span之间的关系是reference(调用)

标准调用结构图

分为父子关系和兄弟关系

父子关系是A和B,C

兄弟关系是F,G,H,我们按照顺序来进行调用,先F然后G然后H

Span节点必须包含的东西

OperationName:操作名称

BeiginTime:开始时间

EndTime:结束时间

SpanTag:是一组键值对 构成的Span的标签集合(key必须是String类型,value可以是String,Boolean和数字类型),这个的目的是为Span添加更多的描述信息

SpanLog:一组Span的日志集合 ,是键值对,记录日志信息

SpanContext:是一个上下文对 象,会从上一个节点传递到下一个节点,里面包含了traceIdSpanIdBaggage (这是一个跨Span集合 ,上一个节点往Baggage加信息下一个节点可以拿到,不要放太多信息不然会导致占用空间大影响效率),我们通过上下文对象去进行 跨进程 传递


OpenTacingApi

opentracing-specification-zh/specification.md at master · opentracing-contrib/opentracing-specification-zh · GitHub

一些基本API的使用


Tracer接口

Tracer接口用来创造Span,以及如何处理Inject和Extract,用于跨进行边界传递

创建一个新的Span

必填参数:OperationName,操作名

可选参数:

  • 零个或者多个关联(references )的SpanContext,如果可能,同时快速指定关系类型,ChildOf 还是 FollowsFrom
  • 一个可选的显性传递的开始时间BeginTime;如果忽略,当前时间被用作开始时间。
  • 零个或者多个tag

返回值 ,返回一个已经启动Span实例(已启动,但未结束。译者注:英语上started和finished理解容易混淆)

SpanContext上下文Inject(注入)到carrier

必填参数

  • SpanContext 实例
  • format (格式化)描述,一般会是一个字符串常量,但不做强制要求。通过此描述,通知Tracer实现,如何对SpanContext进行编码放入到carrier中。
  • carrier ,根据format 确定。Tracer实现根据format 声明的格式,将SpanContext序列化到carrier对象中

SpanContext上下文从carrier中Extract(提取)

必填参数

  • format (格式化)描述,一般会是一个字符串常量,但不做强制要求。通过此描述,通知Tracer实现,如何从carrier中解码SpanContext
  • carrier ,根据format 确定。Tracer实现根据format 声明的格式,从carrier中解码SpanContext

返回值 ,返回一个SpanContext实例,可以使用这个SpanContext实例,通过Tracer创建新的Span

注意,对于Inject(注入)和Extract(提取),format是必须的

Inject(注入)和Extract(提取)依赖于可扩展的format 参数。format 参数规定了另一个参数"carrier"的类型 ,同时约束了"carrier"中SpanContext是如何编码 的。所有的Tracer实现,都必须支持下面的format

  • Text Map: 基于字符串:字符串的map,对于key和value不约束字符集。
  • HTTP Headers : 适合作为HTTP头信息的,基于字符串:字符串的map。(RFC 7230.在工程实践中,如何处理HTTP头具有多样性,强烈建议tracer的使用者谨慎使用HTTP头的键值空间和转义符)
  • Binary : 一个简单的二进制大对象,记录SpanContext的信息

Span

Span结束后(span.finish()),除了通过Span获取SpanContext外,下列其他所有方法都不允许被调用

获取SpanSpanContext

不需要任何参数。

返回值Span构建时传入的SpanContext。这个返回值在Span结束后(span.finish()),依然可以使用

复写操作名(operation name)

必填参数

  • 新的操作名operation name ,覆盖构建Span时,传入的操作名。

结束Span

可选参数

  • 一个明确的完成时间;如果省略此参数,使用当前时间作为完成时间。

Span设置tag

必填参数

  • tag key,必须是string类型
  • tag value,类型为字符串,布尔或者数字

注意,OpenTracing标准包含**"standard tags,标准Tag"**,此文档中定义了Tag的标准含义。

Log结构化数据

必填参数

  • 一个或者多个键值对,其中键必须是字符串类型,值可以是任意类型。某些OpenTracing实现,可能支持更多的log值类型。

可选参数

  • 一个明确的时间戳。如果指定时间戳,那么它必须在span的开始和结束时间之内。

注意,OpenTracing标准包含**"standard log keys,标准log的键"**,此文档中定义了这些键的标准含义

设置一个baggage(随行数据)元素

Baggage元素是一个键值对集合,将这些值设置给给定的SpanSpanSpanContext,以及所有和此 Span****有直接或者间接关系的本地 Span**。** 也就是说,baggage元素随trace一起保持在带内传递。(译者注:带内传递,在这里指,随应用程序调用过程一起传递)

Baggage元素具有强大的功能,使得OpenTracing能够实现全栈集成(例如:任意的应用程序数据,可以在移动端创建它,显然的,它会一直传递了系统最底层的存储系统),同时他也会产生巨大的开销,请小心使用此特性。

再次强调,请谨慎使用此特性。每一个键值都会被拷贝到每一个本地和远程 的下级相关的span中,因此,总体上,他会有明显的网络和CPU开销

必填参数

  • baggage key, 字符串类型
  • baggage value, 字符串类型

获取一个baggage元素

必填参数

  • baggage key, 字符串类型

返回值 ,相应的baggage value,或者可以标识元素值不存在的返回值(译者注:如Null)


SpanContext

相对于OpenTracing中其他的功能,SpanContext更多的是一个"概念"。也就是说,OpenTracing实现中,需要重点考虑,并提供一套自己的API。 OpenTracing的使用者仅仅需要,在创建span、向传输协议Inject(注入)和从传输协议中Extract(提取)时,使用SpanContextreferences

OpenTracing要求,SpanContext不可变 的,目的是防止由于Span的结束和相互关系,造成的复杂生命周期问题。

遍历所有的baggage元素

遍历模型依赖于语言,实现方式可能不一致。在语义上,要求调用者可以通过给定的SpanContext实例,高效的遍历所有的baggage元素

NoopTracer

所有的OpenTracing API实现,必须提供某种方式的NoopTracer实现。NoopTracer可以被用作控制或者测试时,进行无害的inject注入(等等)。例如,在 OpenTracing-Java实现中,NoopTracer在他自己的模块中。

可选 API 元素

有些语言的OpenTracing实现,为了在串行处理中,传递活跃的SpanSpanContext,提供了一些工具类。例如,opentracing-go中,通过context.Context机制,可以设置和获取活跃的Span


原理和架构设计

原理和架构设计

1.自动采集&无侵入:我们使用插件化方式 JavaAegnt启动

2.跨进程传递Context:针对不同协议将信息加入到协议头里面,方便进行区分

3.TraceId的唯一性

4.性能影响:我们不能所有数据都采集这样子数据量太大了还影响效率,我们只采样必要数据

Agent和Plugin插件

Agent:我们项目启动时自动加载我们的插件进行字节码增强,我们的Agent里面由很多插件,分为自带插件和可选插件。我们要启动Agent的话就在JVM参数那指定一下就行了

Plugin插件:创建Span加入Trace调用链,数据传输时我们将数据加入到Header协议头。我们的Skywalking里面把很多的第三方调用组件封装起来了,所以够用


TraceSegment和TraceId原理

TraceSegment:

1.指的是一个进程中所有的Span的集合

2.如果多个线程协同产生同一个Trace(例如多个RPC调用不同的方法),它们只会共同创建一个TraceSegment

3.支持多入口,所以Skywalking去除了树节点RootSpan的概念,提出了三种Span模型

TraceId:

1.TraceId应该是全局唯一的

2.我们的TraceId是根据时间错+算法生成的,所以会有时间回拨问题

3.我们有个变量lastTimeStamp保存上次TraceId生成的时间,然后在生成TraceId前进行比较,如果CuurentTimeMills比lastTimeStamp时间小,说明时间回拨了,我们就不生成Id,这样来保证TraceId全局唯一

JavaAgent可以对字节码做静态修改和动态修改,我们的SkyWalklng是对字节码静态修改的


SkyWalking基本使用

图片介绍

服务和服务之间也可能存在各种调用

skywalking是以插件的形式实现相关东西

他能实现很多应用的无侵入式的监控

关键概念:

服务

服务实例

端点

这个就是服务,然后我们有9个服务实例

这个用户的URL请求地址我们称作端点


搭建OAP服务和UI服务

Downloads | Apache SkyWalking

去到download界面

Skywalking APM已经集成了 BoosterUI和Skywalking Website

下载Agents,下载我们自己需要进行代理的一个探针

这种探针才是用来监控我们自己的应用的,我们上面的那个是服务

skywalking是Java写的

三种启动命令

startup.sh

oapServic.sh

webappService.sh

tar -zxvf 开始解压

我们进入apache-skywalking-apm-bin的bin目录

oapService是直接启动

oapServiceInit是初始化启动

oapServiceNoInit是不初始化启动

我们启动

sh startup.sh

这样子就说明我们两个都启动成功了

我们还可以进入日志目录,看看我们是否有日志

opa.log是我们的服务端的日志

console.log是我们的web界面的一个日志

其实有4个日志,如果是两个日志就说明Java环境有问题

查看我们的日志

tail -f -n200 skywalking-oap-server.log

我们有内存型的数据库,这种数据库安全性不是太高

所以我们打算把日志存到我们的ES里面

我们看看我的的另一个日志skywalking-webapp

tail -f -n200 skywalking-webapp.log

启动失败了,因为我服务器里已经有8080的项目在用了

我们启动服务我们没有给它指定端口

我们看webapp目录里面其实它是一个SpringBoot项目

它的默认端口是8080

vim application.yml

然后我们把我们的端口改成18080

我们重新启动一下我们的webappService

sh webappService.sh

进入日志目录,重新看一下我们的日志

tail -f -n200 skywalking-webapp.log

成功了,我们的端口是18080

然后我们访问一下我们的18080端口

就进入了我们的skywalking界面


结构解析与设计目标

receiver Cluster

receiver Cluster是负责收集数据的

我们从每一个不同的监控服务中去获取相关信息,通过推送或者拉取去获取一些相关的数据,包括通过http,rpc等等各种不同的形式去收集

Aggregator集群

然后我们把数据给我们的Aggregator集群

它可以做我们的数据的保存

可以把我们的数据持久化存储到各个不同的服务器里面

Alram告警服务

还有一块就是我们的Alarm,我们的监控告警服务


JavaAgent监控SpringBoot应用

我们的Agent探针 是为了收集我们的对应服务的数据,然后上传到我们的skywalking服务器上去

我们把文件解压成skywalking-agent目录解压到我们的IDEA的工作目录中

这个是我们的JVM参数

-javaagent:探针java所在的位置


-DSW_AGENT_NAME=skywalking-demo


-DSW_AGENT_COLLECTOR_BACKEND_SERVICES=106.55.55.56:11800

-D表示我们的JVM参数

SW_AGENT_NAME是我们的代理的名字

SW_AGENT_COLLECTOR_BACKEND_SERVICES是我们的服务上传到什么地方去

之前我们的服务HTTP的端口是12800,grpc的端口是11800

我们重新启动我们的SpringBoot项目,发现上面打印了一堆日志

这就是帮我们找到我们的skywalking插件

然后我们的服务就出来了


ES持久化存储

我们的Skywalking默认是在内存型数据库h2存储的,我们这里有数据只是因为我们的skywalking没有重启过

我们重启后这些数据就没有了

我们进入application.yml文件

我们有个storage

我们有个selector,下面有个es相关配置

你看我们默认选中的是h2

我们下面有h2的配置信息,有mysql的配置信息

因为我们只是用来持久化存储,所以我们不用关心太多的配置信息

我们只用关心

clusterNodes:我们的ES的连接地址

user:用户名

password:密码

看看我们是否配置了用户名和密码

我们默认是不支持mysql的,我们要把mysql的驱动包复制到这个目录下来,然后我们才能成功连接


SpringCloud全链路追踪

我不只希望他记录我们的微服务之间的信息

我们还想他记录更多的信息

这个服务访问了数据库,访问了redis,访问了mq等等信息我都给他体现

这里没有网关

skywalking默认我们使用这个SpringCloud的这个情况下,它是没有那种直接支持我们的网关的那种能力的

我们目录里面有已经支持的插件plugins和可选支持的插件optional-plugins

这个可选的插件其实没有把我们的网关的插件引进去

我们搜gateway版本

然后把jar包弄进去

我们的SpringCloud是依赖于webfulx,所以我们要把webfulx引入进去

把这两个jar包粘贴到我们的plugins里面

看看我们的Skywalking界面

我们这会有数据库,缓存,和mq的数据


日志采集GRPC导出logback日志

我们要把我们的日志弄到我们的ES里面去

但是我们单纯的存储这些日志的话,这些日志和我们的链路追踪是没有关系的

看不出我们的日志到底是属于哪条链路的

所以我们希望我们对我们的日志格式做一个定制化

我们有个链路追踪ID,我们希望他能够在这里体现出来

我们要引入依赖

然后我们加上我们的logback相关配置

我们重新启动项目,这时候变成了TID:N/A,这是因为我们还没开始链路追踪

我们不是请求发过来,我们是不会帮我们追踪的

利用grpc把日志信息输出到我们的oap服务

我们是info级别的我们用grpc-log来追加进去

或者我们可以只把警告和错误日志追踪上去


Webhook实现告警通知

通过修改alram-setting.yml文件的配置规则

告警规则

我们弄一下我们的alarm-settings.yml文件

我们触发报警后,我们就会自动调用我们的webhooks里面的这个请求地址

这里有告警信息

然后我们配置的url那个地方我们会把报警通知发过去

教程是写了个Controller来进行输出和接收

你看我们的接收类型是List<AlramMessage>


告警通知消息通知到钉钉机器人

记得我们要找对应版本的官方文档

看看官方文档,这个alram警告通知支持微信,钉钉,飞书通知

我们弄个钉钉机器人

url

secret密钥

我们把配置粘贴进来

这样我们告警信息就能进到钉钉了


自定义追踪-细粒追踪Service方法

我们之前追踪的是各个服务之间也就是Controller和Controller之间

我们想细致化到Service和Service这种具体方法之间的调用

引入依赖

这样我们就能访问skywalking中给我们暴露的API了

TraceContext方法

我们通过TraceContext的方法来往追踪上下文对象中绑定key/value

可以从从上下文获取数据

Trace注解

我们用个Trace注解来表示当前的这个方法是我们要用来追踪的

tag注解

我们可以通过tag注解来放我们的key和value

如果value是returnedObj,说明这个value是这个方法的返回对象

tags注解

里面有多tag


相关推荐
二十七剑1 小时前
jvm中各个参数的理解
java·jvm
东阳马生架构2 小时前
JUC并发—9.并发安全集合四
java·juc并发·并发安全的集合
计算机小白一个3 小时前
蓝桥杯 Java B 组之岛屿数量、二叉树路径和(区分DFS与回溯)
java·数据结构·算法·蓝桥杯
孤雪心殇3 小时前
简单易懂,解析Go语言中的Map
开发语言·数据结构·后端·golang·go
White graces3 小时前
正则表达式效验邮箱格式, 手机号格式, 密码长度
前端·spring boot·spring·正则表达式·java-ee·maven·intellij-idea
菠菠萝宝3 小时前
【Java八股文】10-数据结构与算法面试篇
java·开发语言·面试·红黑树·跳表·排序·lru
不会Hello World的小苗3 小时前
Java——链表(LinkedList)
java·开发语言·链表
Allen Bright3 小时前
【Java基础-46.3】Java泛型通配符详解:解锁类型安全的灵活编程
java·开发语言
柃歌3 小时前
【UCB CS 61B SP24】Lecture 7 - Lists 4: Arrays and Lists学习笔记
java·数据结构·笔记·学习·算法
柃歌4 小时前
【UCB CS 61B SP24】Lecture 4 - Lists 2: SLLists学习笔记
java·数据结构·笔记·学习·算法