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 执行时间。

相关推荐
ZhengEnCi7 分钟前
JPA-SQL 语句使用完全指南-自动生成vs手动编写的智能选择策略
java·spring boot·sql
毕设源码-钟学长18 分钟前
【开题答辩全过程】以 菜谱分享平台为例,包含答辩的问题和答案
java·eclipse
可DRAK鸦|・ω・`)27 分钟前
docker后端jar包本地构建镜像
java·docker·容器·jar
代码不停1 小时前
JavaEE初级——Thread多线程
java·jvm·java-ee
xxxxxxllllllshi1 小时前
Cookie、Session、JWT、SSO,网站与 APP 登录持久化与缓存
java·开发语言·jvm·数据结构·缓存·面试
郑重其事,鹏程万里1 小时前
commons-io
java
爱吃烤鸡翅的酸菜鱼1 小时前
从零掌握贪心算法Java版:LeetCode 10题实战解析(上)
java·算法
计算机徐师兄2 小时前
Java基于SpringBoot的农场管理系统小程序【附源码、文档说明】
java·微信小程序·小程序·农场管理系统小程序·java农场管理系统小程序·java农场管理系统微信小程序·农场管理微信小程序
草字2 小时前
uniapp 打开横竖屏。usb调试时可以横竖屏切换,但是打包发布后却不行?
java·前端·uni-app
Cg136269159743 小时前
多态的定义
java·开发语言