Skywalking启动加载过程

本次讲解版本:apache-skywalking-apm-8.5.0
1 Skywalking整体架构
 

 
主要组成:UI(数据显示)、Storage(存储层)、Agent(客户端数据收集)、OAP(服务端数据接受处理)
 
2 源码解析如下
首先skywalking用的是javaagent技术,入口为:org.apache.skywalking.apm.agent.SkyWalkingAgent#premain如下:
下面主要概括为三个步骤:
1 从agent.config中加载配置到Properties中
 
2 加载插件并放到容器当中  统一返回AbstractClassEnhancePluginDefine定义,并做了三种分类
 
3 创建一个修改字节码的对象(借助的是byteBuddy这个包。。。。)
-- 过滤非必要的包名,如net.bytebuddy.、org.slf4j.等
-- 加载插件,进行插件匹配对应的match,然后对字节码处理重写Transformer#transform, 修改字节码,并且根据插件加一层拦截器
---- 增强静态方法,增强实例方法        主要的方式是拿到对应的插件的具体实现,找到要增强的静态、实例方法名
---- 然后判断是否需要进行增强,插入对应的插件实现,然后实现插件的增强逻辑即可
 
启动所有的服务,比如JVM状况监控服务JVMService,然后执行prepare、startup、onComplet
-- 举例JVMService:分别对应准备获取jvm服务资源、开启两个异步线程(一个生产者、一个消费者),监控系统状态
public class SkyWalkingAgent {
    public static void premain(String agentArgs, Instrumentation instrumentation) throws PluginException {
        final PluginFinder pluginFinder;
        try {
            // 1 从agent.config中加载配置到Properties中
            SnifferConfigInitializer.initializeCoreConfig(agentArgs);
        } catch (Exception e) {
            // try to resolve a new logger, and use the new logger to write the error log here
            LogManager.getLogger(SkyWalkingAgent.class)
                    .error(e, "SkyWalking agent initialized failure. Shutting down.");
            return;
        } finally {
            // refresh logger again after initialization finishes
            LOGGER = LogManager.getLogger(SkyWalkingAgent.class);
        }
 
 
        try {
            // 2 加载插件并放到容器当中  统一返回AbstractClassEnhancePluginDefine定义,并做了三种分类
            pluginFinder = new PluginFinder(new PluginBootstrap().loadPlugins());
        } catch (AgentPackageNotFoundException ape) {
            LOGGER.error(ape, "Locate agent.jar failure. Shutting down.");
            return;
        } catch (Exception e) {
            LOGGER.error(e, "SkyWalking agent initialized failure. Shutting down.");
            return;
        }
 
 
        // 3 创建一个修改字节码的对象(借助的是byteBuddy这个包。。。。)
        final ByteBuddy byteBuddy = new ByteBuddy().with(TypeValidation.of(Config.Agent.IS_OPEN_DEBUGGING_CLASS));
        // -- 并且过滤非必要的包名
        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.isSynthetic()));
        // -- 加载插件
        JDK9ModuleExporter.EdgeClasses edgeClasses = new JDK9ModuleExporter.EdgeClasses();
        try {
            agentBuilder = BootstrapInstrumentBoost.inject(pluginFinder, instrumentation, agentBuilder, edgeClasses);
        } catch (Exception e) {
            LOGGER.error(e, "SkyWalking agent inject bootstrap instrumentation failure. Shutting down.");
            return;
        }
 
 
        try {
            agentBuilder = JDK9ModuleExporter.openReadEdge(instrumentation, agentBuilder, edgeClasses);
        } catch (Exception e) {
            LOGGER.error(e, "SkyWalking agent open read edge in JDK 9+ failure. Shutting down.");
            return;
        }
 
 
        if (Config.Agent.IS_CACHE_ENHANCED_CLASS) {
            try {
                agentBuilder = agentBuilder.with(new CacheableTransformerDecorator(Config.Agent.CLASS_CACHE_MODE));
                LOGGER.info("SkyWalking agent class cache [{}] activated.", Config.Agent.CLASS_CACHE_MODE);
            } catch (Exception e) {
                LOGGER.error(e, "SkyWalking agent can't active class cache.");
            }
        }
        // 凡是buildMatch命中的类
        agentBuilder.type(pluginFinder.buildMatch())
                    // 对字节码处理重写Transformer#transform, 修改字节码,并且根据插件加一层拦截器
                    // 增强静态方法,增强实例方法        主要的方式是拿到对应的插件的具体实现,找到要增强的静态、实例方法名
                    // -- ,然后判断是否需要进行增强,插入对应的插件实现,然后实现插件的增强逻辑即可
                    .transform(new Transformer(pluginFinder))
                    .with(AgentBuilder.RedefinitionStrategy.RETRANSFORMATION)
                    .with(new RedefinitionListener())
                    .with(new Listener())
                    .installOn(instrumentation);
 
 
        try {
            // 4 启动所有的服务,比如JVM状况监控服务JVMService,然后执行prepare、startup、onComplete
            // -- 举例JVMService:分别对应准备获取jvm服务资源、开启两个异步线程(一个生产者、一个消费者),监控系统状态
            ServiceManager.INSTANCE.boot();
        } catch (Exception e) {
            LOGGER.error(e, "Skywalki·ng agent boot failure.");
        }
 
 
        Runtime.getRuntime()
                .addShutdownHook(new Thread(ServiceManager.INSTANCE::shutdown, "skywalking service shutdown thread"));
    }
 
上面分为1、2、3、4步骤,下面我们来拆解一下这些步骤。
1 从agent.config中加载配置到Properties中
SnifferConfigInitializer.initializeCoreConfig(agentArgs);
步骤:SnifferConfigInitializer.initializeCoreConfig=>loadConfig()从/config/agent.config加载流信息=>用Properties解析
 
public static void initializeCoreConfig(String agentOptions) {
    // 将/config/agent.config的文件加载进文件流,然后用Properties读取出来
    AGENT_SETTINGS = new Properties();
    try (final InputStreamReader configFileStream = loadConfig()) {
        AGENT_SETTINGS.load(configFileStream);
        for (String key : AGENT_SETTINGS.stringPropertyNames()) {
            String value = (String) AGENT_SETTINGS.get(key);
            AGENT_SETTINGS.put(key, PropertyPlaceholderHelper.INSTANCE.replacePlaceholders(value, AGENT_SETTINGS));
        }
    ............
}
 
----------------------------------------------------------------------------------------
private static InputStreamReader loadConfig() throws AgentPackageNotFoundException, ConfigNotFoundException {
    // 先看下系统有没文件路径,如果没有就用默认路径
    String specifiedConfigPath = System.getProperty(SPECIFIED_CONFIG_PATH);
    File configFile = StringUtil.isEmpty(specifiedConfigPath) ? new File(
        AgentPackagePath.getPath(), DEFAULT_CONFIG_FILE_NAME) : new File(specifiedConfigPath);
    // 然后解析路径返回文件输入流
    if (configFile.exists() && configFile.isFile()) {
        try {
            LOGGER.info("Config file found in {}.", configFile);
 
            return new InputStreamReader(new FileInputStream(configFile), StandardCharsets.UTF_8);
        } catch (FileNotFoundException e) {
            throw new ConfigNotFoundException("Failed to load agent.config", e);
        }
    }
    throw new ConfigNotFoundException("Failed to load agent.config.");
}
 
2 加载插件并放到容器当中  统一返回AbstractClassEnhancePluginDefine定义,并做了三种分类
pluginFinder = new PluginFinder(new PluginBootstrap().loadPlugins());
loadPlugins()加载插件 => new PluginFinder(xxxx)根据插件类型放入不同的地方,有些是过滤,有些是增强
 
public List<AbstractClassEnhancePluginDefine> loadPlugins() throws AgentPackageNotFoundException {
    // 初始化一个默认的类加载器
    AgentClassLoader.initDefaultLoader();
 
    PluginResourcesResolver resolver = new PluginResourcesResolver();
    // 获取所有的插件资源,skywalking是从自己定义的 skywalking-plugin.def 文件中拉取的。
    // 使用的ClassLoader.getResources()加载 skywalking-plugin.def资源
    // -- getResources参考链接:https://www.jianshu.com/p/a132142da801
    List<URL> resources = resolver.getResources();
 
 
    if (resources == null || resources.size() == 0) {
        LOGGER.info("no plugin files (skywalking-plugin.def) found, continue to start application.");
        return new ArrayList<AbstractClassEnhancePluginDefine>();
    }
    // 扫描出上面的资源,并放入PluginCfg.pluginClassList列表中
    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();
    // 扫描上面加载出来的列表,并通过反射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());
        }
    }
    plugins.addAll(DynamicPluginLoader.INSTANCE.load(AgentClassLoader.getDefault()));
    return plugins;
}
 
public PluginFinder(List<AbstractClassEnhancePluginDefine> plugins) {
    for (AbstractClassEnhancePluginDefine plugin : plugins) {
        ClassMatch match = plugin.enhanceClass();
        // 根据插件类型放入不同的地方,有些是过滤,有些是增强
        if (match == null) {
            continue;
        }
 
        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);
        }
 
 
        if (plugin.isBootstrapInstrumentation()) {
            bootstrapClassMatchDefine.add(plugin);
        }
    }
}
 
3 创建一个修改字节码的对象(借助的是byteBuddy这个包。。。。)
-- 过滤非必要的包名,如net.bytebuddy.、org.slf4j.等
-- 加载插件,进行插件匹配对应的match,然后对字节码处理重写Transformer#transform, 修改字节码,并且根据插件加一层拦截器
---- 增强静态方法,增强实例方法        主要的方式是拿到对应的插件的具体实现,找到要增强的静态、实例方法名
---- 然后判断是否需要进行增强,插入对应的插件实现,然后实现插件的增强逻辑即可
public ElementMatcher<? super TypeDescription> buildMatch() {
    ElementMatcher.Junction judge = new AbstractJunction<NamedElement>() {
        @Override
        public boolean matches(NamedElement target) {
            return nameMatchDefine.containsKey(target.getActualName());
        }
    };
    // 排除所有接口
    judge = judge.and(not(isInterface()));
    for (AbstractClassEnhancePluginDefine define : signatureMatchDefine) {
        ClassMatch match = define.enhanceClass();
        // 从加载的插件中对应的实现类,如果是过滤的插件则放进来匹配过滤,调用插件的过滤方法
        if (match instanceof IndirectMatch) {
            judge = judge.or(((IndirectMatch) match).buildJunction());
        }
    }
    return new ProtectiveShieldMatcher(judge);
}
 
@Override
public DynamicType.Builder<?> transform(final DynamicType.Builder<?> builder,
                                        final TypeDescription typeDescription,
                                        final ClassLoader classLoader,
                                        final JavaModule module) {
    List<AbstractClassEnhancePluginDefine> pluginDefines = pluginFinder.find(typeDescription);
    if (pluginDefines.size() > 0) {
        DynamicType.Builder<?> newBuilder = builder;
        EnhanceContext context = new EnhanceContext();
        for (AbstractClassEnhancePluginDefine define : pluginDefines) {
            // 修改字节码,并且根据插件加一层拦截器
            DynamicType.Builder<?> possibleNewBuilder = define.define(
                    typeDescription, newBuilder, classLoader, context);
            if (possibleNewBuilder != null) {
                newBuilder = possibleNewBuilder;
            }
        }
        if (context.isEnhanced()) {
            LOGGER.debug("Finish the prepare stage for {}.", typeDescription.getName());
        }
 
 
        return newBuilder;
    }
 
 
    LOGGER.debug("Matched class {}, but ignore by finding mechanism.", typeDescription.getTypeName());
    return builder;
}
备注:匹配和字节码增强下一期细讲!!!!!!!!!!!!!!!!!!!
 
4 启动所有的服务,比如JVM状况监控服务JVMService,然后执行prepare、startup、onComplete
-- 举例JVMService:分别对应准备获取jvm服务资源、开启两个异步线程(一个生产者、一个消费者),监控系统状态 ServiceManager.INSTANCE.boot();
public void boot() {
    bootedServices = loadAllServices();
 
    prepare();
    startup();
    onComplete();
}
 
举例JVMService实现如下(对应service都实现了@DefaultImplementor注解):
@Override
public void prepare() throws Throwable {
    sender = ServiceManager.INSTANCE.findService(JVMMetricsSender.class);
}
@Override
public void boot() throws Throwable {
    collectMetricFuture = Executors.newSingleThreadScheduledExecutor(
        new DefaultNamedThreadFactory("JVMService-produce"))
                                   .scheduleAtFixedRate(new RunnableWithExceptionProtection(
                                       this,
                                       new RunnableWithExceptionProtection.CallbackWhenException() {
                                           @Override
                                           public void handle(Throwable t) {
                                               LOGGER.error("JVMService produces metrics failure.", t);
                                           }
                                       }
                                   ), 0, 1, TimeUnit.SECONDS);
    sendMetricFuture = Executors.newSingleThreadScheduledExecutor(
        new DefaultNamedThreadFactory("JVMService-consume"))
                                .scheduleAtFixedRate(new RunnableWithExceptionProtection(
                                    sender,
                                    new RunnableWithExceptionProtection.CallbackWhenException() {
                                        @Override
                                        public void handle(Throwable t) {
                                            LOGGER.error("JVMService consumes and upload failure.", t);
                                        }
                                    }
                                ), 0, 1, TimeUnit.SECONDS);
}
@Override
public void onComplete() throws Throwable {
}
 
更多待续~~~~~~~~~~~~~~~~~~~~~~~~~~~~
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值