主流的基于 Java Agent 技术栈的产品 Arthas和JVM-Sandbox等在执行 attach 到目标 JVM 时都存在 CPU 负载飙高的问题。
测试数据如下
arthas 执行attach 到目标JVM时
arthas 执行attach加载arthas-agent 对JVM cpu 造成的冲击,cpu飙升140%
arthas 执行 attach 瞬间对 JVM cpu 的冲击,cpu由42%飙升到140.2%
jvm-sandbox 执行attach 到目标JVM时
jvm-sandbox 执行 attach 瞬间对 JVM cpu 的冲击,cpu由41.9%飙升到133.3%
疑问1:基于 java-agent attach时存在CPU 飙高的问题,attach 时做了什么?
以 arthas 为例子,来看源码,找寻答案...
private static synchronized InetSocketAddress main(final Map featureMap,final Instrumentation inst) {
final String namespace = getNamespace(featureMap);
final String propertiesFilePath = getPropertiesFilePath(featureMap);
final String coreFeatureString = toFeatureString(featureMap);
try {
// 将Spy注入到BootstrapClassLoader
inst.appendToBootstrapClassLoaderSearch(new JarFile(new File(
getSandboxSpyJarPath(getSandboxHome(featureMap))
// SANDBOX_SPY_JAR_PATH
)));
// 构造自定义的类加载器,尽量减少Sandbox对现有工程的侵蚀
final ClassLoader agentLoader = loadOrDefineClassLoader(
namespace,
getSandboxCoreJarPath(getSandboxHome(featureMap))
// SANDBOX_CORE_JAR_PATH
);
// CoreConfigure类定义
final Class> classOfConfigure = agentLoader.loadClass(CLASS_OF_CORE_CONFIGURE);
// 反序列化成CoreConfigure类实例
final Object objectOfCoreConfigure = classOfConfigure.getMethod("toConfigure", String.class, String.class)
.invoke(null, coreFeatureString, propertiesFilePath);
// CoreServer类定义
final Class> classOfProxyServer = agentLoader.loadClass(CLASS_OF_PROXY_CORE_SERVER);
// 获取CoreServer单例
final Object objectOfCoreServer = classOfProxyServer
.getMethod("getInstance")
.invoke(null);
// CoreServer.isBind()
final boolean isBind = (Boolean) classOfProxyServer.getMethod("isBind").invoke(objectOfCoreServer);
// 如果未绑定,则需要绑定一个地址
if (!isBind) {
try {
classOfProxyServer
.getMethod("bind", classOfConfigure, Instrumentation.class)
.invoke(objectOfCoreServer, objectOfCoreConfigure, inst);
} catch (Throwable t) {
classOfProxyServer.getMethod("destroy").invoke(objectOfCoreServer);
throw t;
}
}
// 返回服务器绑定的地址
return (InetSocketAddress) classOfProxyServer
.getMethod("getLocal")
.invoke(objectOfCoreServer);
} catch (Throwable cause) {
throw new RuntimeException("sandbox attach failed.", cause);
}
}
主要是rasp-agent.jar 和 rasp-spy.jar 的加载和对象的初始化。
从表面上看不到实际的影响是哪些,我们需要对这个过程进行 CPU 诊断...
疑问2:attach 时 CPU 飙高的值是否与JVM负载相关?
多组 QPS 下的压测数据
疑问3:CPU 飙高有什么影响