100.Skywalking调用链
# 01.调用工具链
- https://blog.csdn.net/weixin_39866487/article/details/111581322
- https://blog.csdn.net/weixin_38004638/article/details/115975798
# 1.1 调用用工具链对比
1.CAT
- 是一个更综合性的平台,提供的监控功能最全面,国内几个大厂生产也都在使用。
- 但研发进度及版本更新相对较慢。
2.Zipkin
- 由Twitter开源,调用链分析工具,基于spring-cloud-sleuth得到广泛使用,非常轻量,使用部署简单。
3.Skywalking
- 专注于链路和性能监控,国产开源,埋点无侵入,UI功能较强。
- 能够加入Apache孵化器,设计思想及代码得到一定认可,后期应该也会有更多的发展空间及研发人员投入。
- 目前使用厂商最多,版本更新较快。
4.Pinpoint
- 专注于链路和性能监控,韩国研发团队开源,埋点无侵入,UI功能较强
- 但毕竟是小团队,不知道会不会一直维护着,目前版本仍在更新中
# 1.2 前言
- 在微服务架构中,一次请求往往涉及到多个模块,多个中间件,多台机器的相互协作才能完成。
- 这一系列调用请求中,有些是串行的,有些是并行的,那么如何确定这个请求背后调用了哪些应用,哪些模块,哪些节点及调用的先后顺序?
- 如果有用户反馈某个页面很慢,我们知道这个页面的请求调用链是 A -----> C -----> B -----> D,此时如何定位可能是哪个模块引起的问题。
- 每个服务 Service A,B,C,D 都有好几台机器,怎么知道某个请求调用了服务的具体哪台机器呢?
- 排查问题难度大,周期长
- 特定场景难复现
- 系统性能瓶颈分析较难
分布式调用链就是为了解决以上几个问题而生
# 1.3 调用链的作用
- 自动采取数据
- 分析数据产生完整调用链:有了请求的完整调用链,问题有很大概率可复现
- 数据可视化:每个组件的性能可视化,能帮助我们很好地定位系统的瓶颈,及时找出问题所在
# 02.调用链标准
# 2.1 分布式调用链标准
OpenTracing 规范
- 为了解决不同的分布式追踪系统 API 不兼容的问题,诞生了 OpenTracing 规范
- OpenTracing 是一个轻量级的标准化层,它位于应用程序/类库和追踪或日志分析程序之间
OpenTracing 的数据模型,主要有以下三个
1)Trace
:一个完整请求链路- 一次下单的完整请求就是一个 Trace, 显然对于这个请求来说,必须要有一个全局标识来标识这一个请求
- 一个完整请求链路的追踪ID(traceid)用于查出本次请求调用的所有服务,每一次服务调用的跨度ID(spanid)用来记录调用顺序
2)Span
:一次调用过程(需要有开始时间和结束时间)- 每一次调用就称为一个 Span,每一次调用都要带上全局的 TraceId, 这样才可把全局 TraceId 与每个调用关联起来
- 上游服务parenetid用来记录调用的层级关系
3)SpanContext
:Trace 的全局上下文信息, 如里面有traceId- 这个 TraceId 就是通过 SpanContext 传输的,既然要传输显然都要遵循协议来调用。
- 调用时间timestamp,把请求发出、接收、处理的时间都记录下来,计算业务处理耗时和网络耗时,然后用可视化界面展示出来每个调用链路,性能,故障
我们把传输协议比作车,把 SpanContext 比作货,把 Span 比作路应该会更好理解一些
# 2.2 调用链图解
理解了这三个概念,接下来我看看分布式追踪系统如何采集统一图中的微服务调用链
- 有了这些信息,Collector 收集的每次调用的信息如下
以上实现看起来确实简单,但有以下几个问题需要我们仔细思考一下
- 怎么自动采集 span 数据:自动采集,对业务代码无侵入
- 如何跨进程传递 context
- traceId 如何保证全局唯一
- 请求量这么多采集会不会影响性能
# 03.SkyWalking结构设计
# 3.1 skywalking的工作机制
skywalking的工作机制,需要三块协同
- 第一块是skywalking server:负责接收、存储并展示,所以server模块包含一个展示web子模块;
- 第二块是agent:负责代理微服务并收集需要的信息,转发给server;
- 第三块便是微服务本身:需要在启动时指定agent,以便生成代理类;
# 3.2 SkyWalking 核心模块介绍
1)Skywalking Agent
- 链路数据采集tracing(调用链数据)和metric(指标)信息并上报,上报通过HTTP或者gRPC方式发送数据到Skywalking Collector
2)Skywalking Collector
- 链路数据收集器,对agent传过来的tracing和metric数据进行整合分析通过Analysis Core模块处理并落入相关的数据存储中
- 同时会通过Query Core模块进行二次统计和监控告警
3)Storage
- Skywalking的存储,支持以ElasticSearch、Mysql、TiDB、H2等主流存储作为存储介质进行数据存储,H2仅作为临时演示单机用。
4)SkyWalking UI
- Web可视化平台,用来展示落地的数据,目前官方采纳了RocketBot作为SkyWalking的主UI
# 04.SkyWalking原理
# 4.1 自动采集 span 数据
- SkyWalking 采用了插件化 + javaagent 的形式来实现了 span 数据的自动采集
- 这样可以做到对代码的 无侵入性,插件化意味着可插拔,扩展性好
# 4.2 跨进程传递 context
- 我们知道数据一般分为 header 和 body, 就像 http 有 header 和 body
- RocketMQ 也有 MessageHeader,Message Body, body 一般放着业务数据
- 所以不宜在 body 中传递 context,应该在 header 中传递 context
# 4.3 traceId保证全局唯一
- 要保证全局唯一 ,我们可以采用分布式或者本地生成的 ID
- 使用分布式话需要有一个发号器,每次请求都要先请求一下发号器,会有一次网络调用的开销
- 所以 SkyWalking 最终采用了本地生成 ID 的方式,它采用了大名鼎鼎的 snowflow 算法,性能很高
- 时间回拨
- 每个 id,都会记录一下生成 id 的时间(lastTimestamp),如果发现当前时间比上一次生成 id 的时间(lastTimestamp)还小
- 那说明发生了时间回拨,此时会生成一个随机数来作为 traceId。
# 4.4 全部采集性能如何
如果对每个请求调用都采集,那毫无疑问数据量会非常大,其实没有必要
我们可以设置采样频率,只采样部分数据,
SkyWalking 默认设置了 3 秒采样 3 次
,其余请求不采样如果上游有携带 Context
过来(说明上游采样了),则下游强制采集数据。这样可以保证链路完整。
# 05.Skywalking Agent原理
使用Skywalking的时候,并没有修改程序中任何一行 Java 代码,这里便使用到了 Java Agent 技术,我们接下来展开对Java Agent 技术的学习。
# 5.1 Java Agent
Java Agent 是从 JDK1.5 开始引入的,算是一个比较老的技术了。
我们常用的命令之一就是 java 命令,而 Java Agent 本身就是 java 命令的一个参数(即 -javaagent)。
-javaagent 参数之后需要指定一个 jar 包,这个 jar 包需要同时满足下面两个条件
- 第一:在 META-INF 目录下的 MANIFEST.MF 文件中
必须指定 premain-class 配置项
。 - 第二:premain-class 配置项指定的类
必须提供了 premain() 方法
。- 在 Java 虚拟机启动时,执行 main() 函数之前,虚拟机会先找到 -javaagent 命令指定 jar 包
- 然后执行premain-class 中的 premain() 方法。
- 用一句概括其功能的话就是:main() 函数之前的一个拦截器。
- 第一:在 META-INF 目录下的 MANIFEST.MF 文件中
使用 Java Agent 的步骤大致如下
1)定义一个 MANIFEST.MF 文件,在其中添加 premain-class 配置项
2)创建 premain-class 配置项指定的类,并在其中实现 premain() 方法,方法签名如下
public static void premain(String agentArgs, Instrumentation inst){ //... }
1
2
3
3)将 MANIFEST.MF 文件和 premain-class 指定的类一起打包成一个 jar 包
4)使用 -javaagent 指定该 jar 包的路径即可执行其中的 premain() 方法
# 5.2 探针
- 在 SkyWalking中,探针表示集成到目标系统中的代理或SDK库,它负责收集遥测数据,包括链路追踪和性能指标。
- 根据目标系统的技术栈,探针可能有差异巨大的方式来达到以上功能。
- 但从根本上来说都是一样的,即
收集并格式化数据,并发送到后端
。
# 5.3 服务自动打点代理
对于最终用户来说他们不需要修改代码(至少在绝大多数情况下),只是被代理给修改了,这种做法通常叫做"在运行时操作代码"。
底层原理就是自动打点代理利用了虚拟机提供的用于修改代码的接口来动态加入打点的代码,如通过 javaagent premain 来修改 Java 类。
此外, 我们说大部分自动打点代理是基于虚拟机的,但实际上你也可以在编译期构建这样的工具。