skywalking源码分析第十三篇一agent端微内核架构

原理图

启动流程

  • SnifferConfigInitializer.initialize负责基于agent.config配置文件解析Config

  • PluginBootstrap.loadPlugin基于PluginBootstrap插件引导程序加载插件[AbstractClassEnhancePluginDefine]集合

  • 通过PluginFinder将插件分类

  • 基于IS_OPEN_DEBUGGING_CLASS配置将被增强类写至磁盘

  • 忽略对特定包的增强[如javassist,net.bytebuddy.等等]

  • 基于PluginFinder对字节码进行增强,并装载至instrumentation

  • 启动agent端基于SPI的所有BootService

BootService默认启动集合

TraceSegmentServiceClient
ContextManager
SamplingService
GRPCChannelManager
JVMService
ServiceAndEndpointRegisterClient
ContextManagerExtendService
CommandService
CommandExecutorService
OperationNameFormatService

PluginBootstrap.loadPlugins加载插件流程:

  • 构建AgentClassLoader(指定加载目录plugins和activations)
  • 通过PluginResourcesResolver加载所有的skywalking-plugin.def文件
  • 通过PluginCfg解析skywalking-plugin.def文件中定义的插件并转成PluginDefine集合
  • Class.forName将所有PluginDefine定义的插件实例化为AbstractClassEnhancePluginDefine

PluginFinder实例化流程

  • 将插件加载器构建的插件集合分类
  • nameMatchDefine: 存入所有按插件名称匹配的插件
  • signatureMatchDefine: 存入nameMatchDefine之外的其他插件[注解,签名]等
  • bootstrapClassMatchDefine: 存入bootstrap-plugins包目录下定义的插件
    在这里插入图片描述

源码分析一SkyWalkingAgent.premain

  • 通过agent.config文件初始化配置Config类
  • 加载plugins和activations目录下所有skywalking-plugin.def定义的插件
  • 通过Transformer定义字节码拦截和增强逻辑,并安装至instrumentation,使字节码增强逻辑生效
  • 通过SPI启动所有BootService
public static void premain(String agentArgs, Instrumentation instrumentation) throws PluginException, IOException {
    final PluginFinder pluginFinder;
    ...... 删除其他代码
    ${AGENT_PACKAGE_PATH}/config/agent.config 初始化配置
    SnifferConfigInitializer.initialize(agentArgs);
    加载插件 [根据名称]分类注入 finder  skywalking-plugin.def   PluginBootstrap插件引导程序类
    pluginFinder = new PluginFinder(new PluginBootstrap().loadPlugins());
    ...... 删除其他代码

    基于配置存储被代理增强类类到debug目录
    final ByteBuddy byteBuddy = new ByteBuddy()
        .with(TypeValidation.of(Config.Agent.IS_OPEN_DEBUGGING_CLASS));
    构建 AgentBuilder 配置ElementMatcher先忽略对指定目录的字节码插桩
    AgentBuilder agentBuilder = new AgentBuilder.Default(byteBuddy)
        .ignore(
            nameStartsWith("net.bytebuddy.")
                .or(nameStartsWith("org.slf4j."))
                .or(nameStartsWith("org.groovy."))
                .or(nameContains("javassist"))
                .or(nameContains(".asm."))
                .or(nameContains(".reflectasm."))
                .or(nameStartsWith("sun.reflect"))
                .or(allSkyWalkingAgentExcludeToolkit())
                .or(ElementMatchers.<TypeDescription>isSynthetic()));

    
    ...... 删除jdk9相关
    字节码注入 每当一个类进行加载  需要代理建造者判断type是否合适,合适就通过Transformer增强
    agentBuilder
        找到元素匹配ElementMatchers需要拦截的类对应的插件拦截器 [将所有插件的匹配规则都搂进来]
        .type(pluginFinder.buildMatch())
        代理插件的增强  设置 Java 类的修改逻辑  定义transformer,每有一个类加载时,触发transformer逻辑,对类进行匹配和修改。
        .transform(new Transformer(pluginFinder))
        redefinition策略,描述agent如何控制已经被agent 加载到内存里面的类 采用了重新定义 这里读者自行了解下类型重定义与类型重定基底(等bytebuddy知识)
        .with(AgentBuilder.RedefinitionStrategy.RETRANSFORMATION)
         Java 类的修改情况回调
        .with(new Listener())
        .installOn(instrumentation);

    启动 grpc jvm监控等顶级组件
    ServiceManager.INSTANCE.boot();
    ...... 删除其他代码
    注册关闭挂钩
    Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
        @Override public void run() {
            ServiceManager.INSTANCE.shutdown();
        }
    }, "skywalking service shutdown thread"));
}

源码分析一PluginBootstrap.loadPlugins

  • 实例化加载plugins和activations目录类加载器AgentClassLoader
  • 通过skywalking-plugin.def解析获取所有的插件定义PluginDefine
  • 通过插件定义集合实例化所有的插件集合[AbstractClassEnhancePluginDefine]

public List<AbstractClassEnhancePluginDefine> loadPlugins() throws AgentPackageNotFoundException {
    PluginBootstrap对应的skywalking类加载器,加载plugins和activations目录
    AgentClassLoader.initDefaultLoader();
    PluginResourcesResolver resolver = new PluginResourcesResolver();
    获得skywalking-plugin.def插件定义路径数组
    List<URL> resources = resolver.getResources();
    ...... 删除其他代码
    获得插件定义类( org.skywalking.apm.agent.core.plugin.PluginDefine )数组。
    for (URL pluginUrl : resources) {
        try {
            PluginCfg.INSTANCE.load(pluginUrl.openStream());
        } catch (Throwable t) {
            logger.error(t, "plugin file [{}] init failure.", pluginUrl);
        }
    }
    List<PluginDefine> pluginClassList = PluginCfg.INSTANCE.getPluginClassList();
    创建类增强插件定义(AbstractClassEnhancePluginDefine )对象数组并通过class.forName添加插件
    List<AbstractClassEnhancePluginDefine> plugins = new ArrayList<AbstractClassEnhancePluginDefine>();
    for (PluginDefine pluginDefine : pluginClassList) {
        try {
            logger.debug("loading plugin class {}.", pluginDefine.getDefineClass());
            AbstractClassEnhancePluginDefine plugin =
                (AbstractClassEnhancePluginDefine)Class.forName(pluginDefine.getDefineClass(),
                    true,
                    // 此时可以读到插件的类定义
                    AgentClassLoader.getDefault())
                    .newInstance();
            plugins.add(plugin);
        } catch (Throwable t) {
            logger.error(t, "load plugin [{}] failure.", pluginDefine.getDefineClass());
        }
    }
    所有增强类的插件加载到这里 类似于aop类已经注入容器 这里所有插件即将放入finder
    plugins.addAll(DynamicPluginLoader.INSTANCE.load(AgentClassLoader.getDefault()));
    return plugins;
}

源码分析一PluginFinder实例化

  • 将获取到的插件集合分成三类
  • 按类名称匹配的插件nameMatchDefine
  • 按签名插件匹配的插件signatureMatchDefine[ 如注解 继承]
  • 引导类插件bootstrapClassMatchDefine[ bootstrap-plugins包目录下的插件]
public PluginFinder(List<AbstractClassEnhancePluginDefine> plugins) {
    for (AbstractClassEnhancePluginDefine plugin : plugins) {
        ClassMatch match = plugin.enhanceClass();
        名称插件
        if (match instanceof NameMatch) {
            NameMatch nameMatch = (NameMatch)match;
            LinkedList<AbstractClassEnhancePluginDefine> pluginDefines = nameMatchDefine.get(nameMatch.getClassName());
            if (pluginDefines == null) {
                pluginDefines = new LinkedList<AbstractClassEnhancePluginDefine>();
                nameMatchDefine.put(nameMatch.getClassName(), pluginDefines);
            }
            pluginDefines.add(plugin);
        } else {
            其他签名插件 如注解 继承等
            signatureMatchDefine.add(plugin);
        }
        引导类插件: bootstrap-plugins包目录下的插件
        if (plugin.isBootstrapInstrumentation()) {
            bootstrapClassMatchDefine.add(plugin);
        }
    }
}

源码分析一Transformer增强逻辑

  • 当源目标类被加载时通过Transformer完成增强
  • 找出所有匹配目标类的插件AbstractClassEnhancePluginDefine
  • 通过插件AbstractClassEnhancePluginDefine.define完成类增强逻辑
private static class Transformer implements AgentBuilder.Transformer {
    private PluginFinder pluginFinder;

    Transformer(PluginFinder pluginFinder) {
        this.pluginFinder = pluginFinder;
    }
    /**
     *
     * @param builder 字节码探针处理器
     * @param typeDescription加载时候对应的源类的元信息
     * @param classLoader
     * @param module  这个是java9的特性
     * @return
     */
    @Override
    public DynamicType.Builder<?> transform(DynamicType.Builder<?> builder, TypeDescription typeDescription,
        ClassLoader classLoader, JavaModule module) {
        所有适合该类的插件[ElementMatchers.match]
        List<AbstractClassEnhancePluginDefine> pluginDefines = pluginFinder.find(typeDescription);

        if (pluginDefines.size() > 0) {
            DynamicType.Builder<?> newBuilder = builder;
            增强上下文
            EnhanceContext context = new EnhanceContext();
            for (AbstractClassEnhancePluginDefine define : pluginDefines) {
                通过DynamicType.Builder对象,定义如何拦截需要修改的Java类 
                bytebuddy的动态agent逻辑
                DynamicType.Builder<?> possibleNewBuilder = define.define(typeDescription, newBuilder, classLoader, context);
                在增强的基础上在增强,后一个插件是在前一个已经修改的字节码上继续修改
                if (possibleNewBuilder != null) {
                    newBuilder = possibleNewBuilder;
                }
            }
            return newBuilder;
        }
        return builder;
    }
}

总结

  • agent端同服务端采用微内核架构
  • 通过扫描所有的skywalking-plugin.def完成插件的载入和字节码增强功能
  • 借助jdk提供的javaagent功能实现字节码插桩

扩展点一ClassMatch匹配机制

类名称作用
NameMatch基于完整的类名进行匹配
IndirectMatch间接匹配接口
ClassAnnotationMatch基于类注解进行匹配,可设置同时匹配多个
HierarchyMatch基于父类 / 接口进行匹配,可设置同时匹配多个
MethodAnnotationMatch基于方法注解进行匹配,可设置同时匹配多个

扩展点一Config配置类

  • 多个配置子类,基于agent.config初始化该类
  • 可以对Agent,Jvm,日志,Plugin等功能增加特性配置
  • 在这里插入图片描述

扩展点一BootService一览

名称作用
TraceSegmentServiceClient核心功能:trace上报
ContextManagerTraceContext核心处理入口,负责span,Trace的创建,传播
SamplingService全采样还是采样阈值控制服务
GRPCChannelManager基于BACKEND_SERVICE配置管理OapServer的GrpcChannel
JVMService核心功能:Metrics指标上报
ServiceAndEndpointRegisterClient核心服务注册信息同步以及Dictionary字典维护
ContextManagerExtendService工具类:TracerContext创建工具
CommandService命令管理服务
CommandExecutorService消费命令管理服务存在的命令
OperationNameFormatService端点格式化工具
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值