java实现性能监控方案

一、性能监控:
要监控应用的性能,首先列出性能监控点(比如方法执行耗时,sql执行耗时等等监控),然后输出要关注的信息,最终根据信息进行数据分析得出性能瓶颈后进行持续优化改进,不同应用、不同场景下,监控点不尽相同,要关注的信息如何获取却是每个工程师都要思考的问题。

在接触javassist与javaagent之前,有过几个方案,但发布了几版后发现实现方式太low、成本高、效率低等不足,其中包括:代码中嵌入日志、使用spring管理应用并使用aop、修改jar包源代码增加日志。

二、字节码插桩技术实现更高效的应用性能监控,什么是字节码插桩技术:
javaagent 是java1.5之后引⼊的特性,其主要作⽤是在class 被加载之前对其拦截,插⼊字节码。

javassist:编辑和创建字节码的类库,其主要的优点,在于简单,⽽且快速。直接使⽤java编码的形式。

基于javaagent和javassist实现字节码插桩技术。

三、demo实现方法执行耗时监控

 public class TimeAgent {
      public static void premain(String args, Instrumentation instrumentation) {
        System.out.println("传入参数:"+args);
        instrumentation.addTransformer(new ClassFileTransformer() {
            public byte[] transform(ClassLoader loader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) 
throws IllegalClassFormatException {
                if (!"com/apm/agent/TimeServiceImpl".equals(className)) {
                    return null;
                }
                try {
                    //javassist 编辑改造字节码
                    ClassPool classPool = new ClassPool();
                    classPool.insertClassPath(new LoaderClassPath(loader));

                    CtClass ctClass = classPool.get("com.apm.agent.TimeServiceImpl");
                    CtMethod method = ctClass.getDeclaredMethod("hello");
                    method.addLocalVariable("beginTime",CtClass.longType);
                    method.addLocalVariable("endTime", CtClass.longType);
                    method.insertBefore("System.out.println(System.currentTimeMillis());");
                    method.insertBefore("long beginTime = System.currentTimeMillis();");
                    method.insertAfter("long endTime = System.currentTimeMillis();\n"+
                            " System.out.println(endTime-beginTime);");

                    return ctClass.toBytecode();
                } catch (NotFoundException e) {
                    e.printStackTrace();
                } catch (CannotCompileException e) {
                    e.printStackTrace();
                } catch (IOException e) {
                    e.printStackTrace();
                }
                return null;
            }
        });
    }
}  
public class TimeServiceImpl {

    public TimeServiceImpl() {}

    //有一次必须向上一层抛出,如果用try{}catch(){}捕获异常,则会抛出异常
//    java.lang.VerifyError: (class: com/apm/agent/TimeServiceImpl, method: hello signature:
// (Ljava/lang/String;)V) Register pair 3/4 contains wrong type
    public void hello(String hello) throws InterruptedException {
        {  // 开始时间
            Thread.sleep(3000);
            // 结束时间
        }
    }
}


public class TimeAgentTest {

    public static void main(String[] args) throws InterruptedException {
        System.out.println("执行main方法");
        TimeServiceImpl timeService = new TimeServiceImpl();
        timeService.hello("");
    }
}

编辑MANIFEST.MF文件


image.png

设置JVM启动参数


image.png

执行TimeAgentTest.main()方法,输出结果:
传入参数:helloworld
执行main方法
1554281967837
3001

你可能感兴趣的:(java实现性能监控方案)