• 一次java性能调优总结


       我们的系统中新开发了一个数据抽取的功能,东西做完后,一看执行时间那叫一个恼火。参考同类系统同样功能的执行时间,目标:将本地数据处理时间压缩到5秒以内。

       

      第一步:

       要想知道哪个地方需要优化,仅凭感觉还是不够,我使用btrace寻找速度慢点原因。下面贴出这次使用的btrace代码:

    import static com.sun.btrace.BTraceUtils.name;  
    import static com.sun.btrace.BTraceUtils.print;  
    import static com.sun.btrace.BTraceUtils.println;  
    import static com.sun.btrace.BTraceUtils.probeClass;  
    import static com.sun.btrace.BTraceUtils.probeMethod;  
    import static com.sun.btrace.BTraceUtils.str;  
    import static com.sun.btrace.BTraceUtils.strcat;  
    import static com.sun.btrace.BTraceUtils.timeMillis;  
      
    import com.sun.btrace.annotations.BTrace;  
    import com.sun.btrace.annotations.Kind;  
    import com.sun.btrace.annotations.Location;  
    import com.sun.btrace.annotations.OnMethod;  
    import com.sun.btrace.annotations.TLS;  
      
    /** 
     * 监控方法耗时 
     *  
      */  
    @BTrace  
    public class PrintTimes {  
      
        /** 
         * 开始时间 
         */  
        @TLS  
        private static long startTime = 0;  
      
        /** 
         * 方法开始时调用 
         */  
        @OnMethod(clazz = "com.xxx.service.XXService", method = "/.+/")  
        public static void startMethod() {  
            startTime = timeMillis();  
        }  
      
        /** 
         * 方法结束时调用<br> 
         */  
        @SuppressWarnings("deprecation")  
        @OnMethod(clazz = "com.xxx.service.XXService", method = "/.+/", location = @Location(Kind.RETURN))  
        public static void endMethod() {  
      
            print(strcat(strcat(name(probeClass()), "."), probeMethod()));  
            print("  [");  
            print(strcat("Time taken : ", str(timeMillis() - startTime)));  
            println("]");  
        }  
    }

    本段代码会匹配 com.xxx.service.XXService 类中的所有方法,打印每个方法的执行时间,每调用一次会打印一次,不是总时间。更多BTrace内容请访问官网:https://kenai.com/projects/btrace

    第二步到了这一步已经知道了速度慢集中在哪些点。对于这个系统我可以做哪些工作来优化呢?

    1.代码方面调整
       a.并行化  (关于线程池线程数量的调整,请参考我的另外一篇关于"设置最优线程数"的文章)
       b.增加缓存
    c.插入操作执行频繁的地方,用原生sql进行批量插入(持久化层使用EclipseLink)
    d.避免大数据量表join操作
    2.参数调整 a.JVM内存参数 b.数据库连接池参数

    3.功能实现设计调整 (最不愿看到的)

    根据实际情况采取相应手段调整。

    第三步

      检测优化后系统该功能性能情况,如果有效则保留,否则恢复代码到本次优化之前的那个状态。

    第三步结束后,继续执行第一、二、三步。直到性能达到预期要求。

    根据对待优化代码进行分析,最后采用了并行化,增加缓存以及批量插入优化的操作。软件参数和功能设计方面不需要调整。

    --------------- 问题纪录 -------------

    在将插入操作改成批量插入时,日志报以下错误:

    Caused by: org.apache.tomcat.dbcp.dbcp.SQLNestedException: Cannot get a connection, pool error Timeout waiting for idle object
    14:45:03.821 [pool-1-thread-2] ERROR java.lang.Throwable -     at org.apache.tomcat.dbcp.dbcp.PoolingDataSource.getConnection(PoolingDataSource.java:114)
    14:45:03.822 [pool-1-thread-2] ERROR java.lang.Throwable -     at org.apache.tomcat.dbcp.dbcp.BasicDataSource.getConnection(BasicDataSource.java:1044)
    14:45:03.822 [pool-1-thread-2] ERROR java.lang.Throwable -     at org.eclipse.persistence.sessions.JNDIConnector.connect(JNDIConnector.java:123)
    14:45:03.822 [pool-1-thread-2] ERROR java.lang.Throwable -     ... 39 more
    14:45:03.823 [pool-1-thread-2] ERROR java.lang.Throwable - Caused by: java.util.NoSuchElementException: Timeout waiting for idle object

    有几个思路:
    1.数据库连接没有成功释放;(得到数据库连接池的监控数据,可以实时看到空闲连接的情况)
    2.数据库连接成功释放,但是由于多个线程同时抢占连接而导致有些线程抢不到连接。(这个情况考虑增大数据库连接池) 

    使用BTrace监控连接池发现只有获得连接没有释放连接操作,看来属于1。由于使用EclipseLink以为 entityManager.close()可以释放连接,经过查阅EclipseLink官网文档,原来是使用不当,下面是获取连接的详细信息,:

    JPA 2.0
    entityManager.getTransaction().begin();
    java.sql.Connection connection = entityManager.unwrap(java.sql.Connection.class);
    ...
    entityManager.getTransaction().commit();

    最后在finally将connection.close()。

  • 相关阅读:
    网页制作初期,必须的东西
    网页制作知识100问(五)
    打開新窗口
    [转]如何用Delphi开发网游外挂
    钩子技术
    [转]计算两点间的角度
    [转]快速寻找子位图的位置
    (转)Delphi读写UTF8、Unicode格式文本文件
    GridView中控件列使用方法小结
    ASP.NET2.0 生成Word 2007并下载方案
  • 原文地址:https://www.cnblogs.com/bobsha/p/6252878.html
Copyright © 2020-2023  润新知