SkyWalking java-agent 是如何工作的,自己实现一个监控sql执行耗时的agent

Apache SkyWalking 是一个开源的应用性能监控 (APM) 工具,支持分布式系统的追踪、监控和诊断。SkyWalking Agent 是其中的一个重要组件,用于在服务端应用中收集性能数据和追踪信息,并将其发送到 SkyWalking 后端服务器进行处理和展示。

SkyWalking Agent 的工作原理

  1. 启动时加载 Agent

    SkyWalking Agent 通过 Java Agent 机制,在 JVM 启动时加载。用户需要在启动应用时添加 -javaagent 参数,指定 SkyWalking Agent 的 JAR 文件。

    复制代码
    java -javaagent:/path/to/skywalking-agent.jar -jar your-application.jar
  2. 字节码增强

    SkyWalking Agent 使用字节码增强技术(基于字节码操作库如 ASM)来修改应用程序的类文件,以插入监控代码。这些代码会在方法调用、数据库访问、HTTP 请求等关键点收集性能数据。

  3. 拦截方法调用

    通过字节码增强,Agent 拦截应用程序中的特定方法调用(如 HTTP 请求、数据库查询等)。在方法开始前、方法结束后和异常抛出时,Agent 会记录相关信息。

  4. 收集性能数据和追踪信息

    拦截的方法调用会生成追踪数据,这些数据包括:

    • 方法执行的开始时间和结束时间
    • 方法执行的耗时
    • 调用链上下文信息(如 Trace ID、Span ID)
    • 方法的输入输出参数和异常信息
  5. 数据缓冲和发送

    收集到的数据会暂时存储在 Agent 的内存中,并定期批量发送到 SkyWalking 后端服务器。为了减少对应用程序性能的影响,数据发送通常是异步进行的。

  6. 后端处理和展示

    SkyWalking 后端服务器接收到数据后,会对其进行处理、存储,并在 Web UI 中展示。用户可以通过 Web UI 查看服务的调用链、性能指标、错误信息等。

SkyWalking Agent 的关键组件

  • Agent Core:负责 Agent 的初始化、配置加载和生命周期管理。
  • Plugin System:SkyWalking Agent 提供了插件系统,支持不同类型的 middleware、framework 的插件,如 HTTP、Dubbo、Spring、MyBatis 等。这些插件定义了如何拦截特定的框架方法,收集性能数据。
  • Tracing Context:管理调用链上下文,包括 Trace ID 和 Span ID 的生成和传递。
  • Reporter:负责将收集到的数据发送到 SkyWalking 后端服务器。

自己实现一个java agent

Java Agent 是 Java Instrumentation API 的一个强大功能,它允许你在运行时修改 Java 应用程序的行为。它们通常用于性能分析、监控和修改应用程序的执行。

自己实现一个 实现一个 Java Agent 来监控 JDBC SQL 执行时间

步骤 1:创建 Java Agent

  1. 创建 Agent 类:
    该类将实现 premain 方法来进行类的插桩。
java 复制代码
import java.lang.instrument.Instrumentation;
import java.lang.instrument.ClassFileTransformer;
import java.security.ProtectionDomain;

public class SqlTimingAgent {
    public static void premain(String agentArgs, Instrumentation inst) {
        System.out.println("SQL Timing Agent loaded");
        inst.addTransformer(new SqlTimingTransformer());
    }
}
  1. 创建 Transformer 类:
    该类将对 java.sql.Statementjava.sql.PreparedStatementexecute* 方法进行插桩。
java 复制代码
import java.lang.instrument.ClassFileTransformer;
import java.security.ProtectionDomain;
import java.lang.instrument.IllegalClassFormatException;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;

public class SqlTimingTransformer implements ClassFileTransformer {
    @Override
    public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
        if (className.equals("java/sql/Statement") || className.equals("java/sql/PreparedStatement")) {
            return transformSQLClass(className, classfileBuffer);
        }
        return classfileBuffer;
    }

    private byte[] transformSQLClass(String className, byte[] classfileBuffer) {
        try {
            ClassPool cp = ClassPool.getDefault();
            CtClass cc = cp.get(className.replace("/", "."));
            for (CtMethod m : cc.getDeclaredMethods()) {
                if (m.getName().startsWith("execute")) {
                    addTiming(m);
                }
            }
            return cc.toBytecode();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return classfileBuffer;
    }

    private void addTiming(CtMethod method) throws Exception {
        method.addLocalVariable("startTime", CtClass.longType);
        method.insertBefore("startTime = System.currentTimeMillis();");
        method.insertAfter("System.out.println(\"SQL Execute Time: \" + (System.currentTimeMillis() - startTime) + \" ms\");");
    }
}

步骤 2:创建 Manifest 文件

创建一个 MANIFEST.MF 文件来指定代理类。

java 复制代码
Manifest-Version: 1.0
Premain-Class: SqlTimingAgent

步骤 3:将 Agent 打包为 JAR

编译你的代理类和 Transformer 类,并将它们与 manifest 文件一起打包到 JAR 文件中。

java 复制代码
javac SqlTimingAgent.java SqlTimingTransformer.java
jar cfm SqlTimingAgent.jar MANIFEST.MF SqlTimingAgent.class SqlTimingTransformer.class

步骤 4:使用 Java Agent

在启动 Java 应用程序时使用 -javaagent 选项指定代理 JAR 文件。

java 复制代码
java -javaagent:SqlTimingAgent.jar -jar YourApplication.jar
复制代码

示例解释

  • SqlTimingAgent

    • premain 方法在 JVM 启动时被调用,添加 SqlTimingTransformer 作为类文件转换器。
  • SqlTimingTransformer

    • 该类实现了 ClassFileTransformer 接口,对 java.sql.Statementjava.sql.PreparedStatement 类进行转换。
    • transform 方法中,检查类名是否是 StatementPreparedStatement,并调用 transformSQLClass 方法。
    • transformSQLClass 方法使用 Javassist 库修改类的字节码,对 execute* 方法添加时间记录代码。
  • 字节码修改

    • execute* 方法开始前记录当前时间。
    • 在方法结束后,计算并输出 SQL 执行时间。

通过这些步骤,你可以创建和使用 Java Agent 来监控 JDBC SQL 执行时间。

相关推荐
会编程的林俊杰1 小时前
SpringBoot项目启动时的依赖处理
java·spring boot·后端
一叶飘零_sweeeet1 小时前
深度拆解汽车制造系统设计:用 Java + 设计模式打造高扩展性品牌 - 车型动态生成架构
java·设计模式·工厂设计模式
王家羽翼-王羽2 小时前
nacos 3.1.0 运行主类报错 com.alibaba.cloud.nacos.logging.NacosLoggingAppRunListener
java
wbzuo2 小时前
Clip:Learning Transferable Visual Models From Natural Language Supervision
论文阅读·人工智能·transformer
影子24012 小时前
oralce创建种子表,使用存储过程生成最大值sql,考虑并发,不考虑并发的脚本,plsql调试存储过程,java调用存储过程示例代码
java·数据库·sql
武子康2 小时前
Java-172 Neo4j 访问方式实战:嵌入式 vs 服务器(含 Java 示例与踩坑)
java·服务器·数据库·sql·spring·nosql·neo4j
程序猿DD3 小时前
深入探索剖析 JVM 的启动过程
java
AI即插即用3 小时前
即插即用涨点系列 (八):AMDNet 详解!AAAI 2025 SOTA,MLP 融合多尺度分解(MDM)与 AMS 的涨点新范式。
人工智能·pytorch·深度学习·目标检测·计算机视觉·transformer
Arva .3 小时前
ConcurrentHashMap 的线程安全实现
java·开发语言