本次讲解版本:apache-skywalking-apm-8.5.0


1 Skywalking整体架构


 


Skywalking启动加载过程_skywalking


 


主要组成:UI(数据显示)、Storage(存储层)、Agent(客户端数据收集)、OAP(服务端数据接受处理)


 


2 源码解析如下


首先skywalking用的是javaagent技术,入口为:org.apache.skywalking.apm.agent.SkyWalkingAgent#premain如下:


下面主要概括为三个步骤:


1



 



2



 



3



-- 过滤非必要的包名,如net.bytebuddy.、org.slf4j.等



-- 加载插件,进行插件匹配对应的match,然后对字节码处理重写Transformer#transform, 修改字节码,并且根据插件加一层拦截器



---- 增强静态方法,增强实例方法        主要的方式是拿到对应的插件的具体实现,找到要增强的静态、实例方法名



---- 然后判断是否需要进行增强,插入对应的插件实现,然后实现插件的增强逻辑即可



 



4 启动所有的服务,比如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
 

 -- 过滤非必要的包名,如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 {
 
 
 

  }


更多待续~~~~~~~~~~~~~~~~~~~~~~~~~~~~