项目源码注释地址:https://github.com/ChuckChen123/skywalking-java/tree/chuck_learn
源起
最近项目中需要用到 SkyWalking 来进行分布式链路跟踪,但是因为需求里不仅需要进行链路跟踪,还需要对业务链路进行跟踪,所以需要对 SkyWalking 底层源码进行二次开发来满足业务链路跟踪的需求,正好可以了解一下 SkyWalking 的架构和设计。
SkyWalking 简介
根据官方文档介绍,SkyWalking 是一个分布式系统的应用程序性能监控工具,专为微服务、云原生架构和基于容器(Docker、K8s、Mesos)架构而设计。提供分布式追踪、服务网格遥测分析、度量聚合和可视化一体化解决方案。
SkyWalking 的整体架构分为上、下、左、右四部分:
- 上部分 Agent:负责从应用中,收集链路信息,发送给 SkyWalking OAP 服务器。目前支持 SkyWalking、Zikpin、Jaeger 等提供的 Tracing 数据信息,这篇博客要介绍的就是这个部分,名为 SkyWalking Agent 的 Java SDK;
- 下部分 SkyWalking OAP:负责接收 Agent 发送的 Tracing 数据信息,然后分析(Analysis Core),存储到外部存储器(Storage),最终提供查询(Query)功能;
- 右部分 Storage:Tracing 数据存储。目前支持 ES、MySQL、Sharding Sphere、TiDB、H2 多种存储器。而目前采用的推荐存储器为 ES;
- 左部分 SkyWalking UI:负责提供控制台,查看链路等等。
我们将从 SkyWalking Agent 的启动流程作为入口开始学习,这样可以总览 SkyWalking Agent 的所有组件和功能。
SkyWalking Java Agent 入口
在寻找 SkyWalking Java Agent 的入口之前,我们先要了解 Java 的字节码增强技术,SkyWalking 就是基于此项技术实现无侵入式的链路追踪的,而 Java 的字节码增强技术又分为两类:
- 静态代理:静态代理是在程序加载运行之前对程序的字节码进行修改完成字节码增强,它修改的字节码只要符合字节码规范和保证程序可以运行,没有其他任何我限制,所以这种代理方式的可操作性特别高;
- 动态代理:动态代理是程序运行中进行动态的字节码修改,与静态代理相比,动态代理的局限性就很多,因为程序已经运行起来了,所以对于目标类,不能增加父类,不能增加接口,不能调整 Field,只能像 JDK 的代理,构造类之后进行替换原类,或者 CGLib,构造子类后对原类进行替换。
SkyWalking 就是基于 Bytebuddy 框架的静态代理实现的,Java 的静态代理的入口是 premain() 方法,我们只需要在源码中搜索 premain 就可以找到 SkyWalking 的入口类 SkyWalkingAgent。
启动流程
SkyWalking 的启动流程主要分为五个步骤:
- 加载配置信息
- 加载插件
- 配置 byteBuddy 字节码增强
- 微内核启动服务
- 注册关闭钩子
接下来我们依次来看 SkyWalking 是怎么执行各个步骤的,其中第 2 项和第 4 项为 SkyWalking 的核心。
加载配置信息
流程
配置信息的来源有三个渠道:Properties 配置文件、系统环境变量和 -javaagent 命令行参数,而它们的优先级跟它们的加载方式正好相反:命令行参数 > 系统环境变量 > Properties 配置文件。
对于 SkyWalking Java Agent 读取配置文件的具体实现,我将通过另外的文章进行详细解析。
加载插件
流程
SkyWalking Java Agent 的插件加载流程主要由两个类来完成,PluginBootstrap 负责读取和实例化所有插件,PluginFinder 负责将插件分为三类,方便后续配置 ByteBuddy 时方便分类处理。
PluginBootstrap 中读取配置的能力来自于 PluginResourceResolver,它会读取 resource 目录下的 skywalking-plugin.def 文件,实例化的能力则来自于 PluginCfg,它会读取文件流,将配置文件中的类封装成为 PluginDefine。
配置 byteBuddy 字节码增强
流程
可以看到,1、2 步主要做 ByteBuddy 的一些基础的配置,3,4 步做 Bootstrap 的注入,也就是对 JVM 中的相关类做增强,第 5 步是判断是否需要保存修改后的字节码,第 6 步是重点,这一步就是处理 SkyWalking Java Agent 的一系列框架的插件和我们自己的插件的位置,这里对我们关注的类进行了配置增强。
微内核启动服务
流程
SkyWalking Java Agent 服务的启动流程是比较简单的,它是直接通过 Java 自带的 SPI 机制,将所有实现了服务接口(BootService)的类实例化出来,然后进行一定规则的筛选,最后按顺序调用每个服务的生命周期方法(prepare()、boot()、onComplete()),将所有的服务初始化和启动。
总结
今天我们简要的浏览了一遍 SkyWalking Java Agent 的启动流程,但仅仅了解这些还是不够的,我们需要更深入的去了解它,后续我将会从每个步骤去进行对应的源码分析,让我们一起来探索 SkyWalking 是如何实现无侵入的链路追踪的吧!
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于