本次讲解版本:apache-skywalking-apm-8.5.0
1 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 {
}
更多待续~~~~~~~~~~~~~~~~~~~~~~~~~~~~