性能测试的目标

性能测试不同于功能测试,不是对与错的检验,而是快与慢的衡量。在进行真正的性能测试之前要先搞清楚目标:

1. 在确定的硬件条件下,可以支持的并发数越大越好,响应时间越快越好。具体需要达到的并发数是多大,要求的响应时间是多快,由产品经理来提出。

2. 在确定的硬件条件下,测试得到最大并发数和相应的响应时间之后。如果增加硬件投入,可以得到怎样的性能提升回报? (系统扩展性和伸缩性测试,Scalability)

这里的硬件条件包括:cpu,memery,I/O,network bandwidth。

性能测试中的基准测试 Benchmarking

与功能测试相似,性能测试也要设计测试用例,不同的是在正式开始你的业务测试用例之前你要先进行一下基准测试。为什么呢?其实就是先要量一下你的硬件的能力,不然,如果你的测试结果不好,你怎么知道是硬件慢还是你的软件的问题。这些硬件测试包括:

1. 网络带宽测试, 你可以通过copy大文件的方式测试你的网络的最大带宽是多少。

2. cpu,你可以利用比较复杂的算法来衡量cpu的快慢

3. memery,这个不用测试,你知道memery的大小

4. IO, 也可以通过copy大文件来测试

这些基准测试用例在后面的调优过程中,还可以用来衡量你修改之后真的变好了吗。

设计你的业务测试用例

比较理想的测试用例就是要尽可能模仿真实世界的情况,这往往做不到,尤其是对于新产品来说。你可以先录制一些用户最常用,最典型的case作为起点。

另外,对于并发的概念需要搞清楚。并发用户,通常是指同时在线的用户,这些用户可以能在用你的系统的不同的功能,注意并不是说大家都在做同一件事情。对某一个事务并发请求是指某一个request的并发调用。

对于后一种并发,你往往需要计算在用户量最大的时候,大概大家都集中的在干哪一件事情,这个请求一定要够快才好。

设计好这两种测试用例以后,在后面的调优过程中,他们就成了衡量你的改进的成效的衡量的标尺。

性能调优

性能调优要从底层开始,基本上要从OS开始,到JVM,Cache,Buffer Pool, SQL,DB Schema, 算法。

一次不要改的太多,改一点,测一下,这可是个慢功夫,需要有耐心。

在执行测试的时候还要注意,要遵循相同的过程,系统需要在重启之后先热身再开始真正的测试,不然你会发现你的测试结果很不一样,琢磨不定。

还有,要注意你的客户端的能力,比如JMeter,很需要内存,别因为客户端不行,误以为是你的系统的问题,那就太乌龙了。

在测试调优的时候,需要借助一些监控工具比如JConsole,来监控系统的状况,找到系统的瓶颈,所谓瓶颈,就是最慢的那个部分,也常表现为100%被占满。比如你的内存或者cpu被用尽了。如果cpu和内存还没有用尽,说明他们在等某个资源。这时候需要用profile工具去寻找,比如JProfile,YourKit。

利用性能监控日志

因为性能的问题不是很容易重现,当product环境中遇到性能问题的时候,如果是数据的问题,也许当你把product 数据copy到你的测试环境中,就能重现比较慢点查询,加以改进。但是如果是并发用户或者网络等运行时环境的问题,你就很难重现。这时,如果你能通过日志看到那些关键的响应慢的方法,也许可以帮助你快点找到问题所在。下面的代码可以帮你做到这一点,仅供参考:

  1. import org.slf4j.Logger;
  2. public class TraceUtil {
  3. final Logger logger;
  4. final long threshold = 1000;
  5. private long begin;
  6. private long offtime = 0;
  7. private String threadInfo;
  8. private String targetId;
  9. public TraceUtil(Logger logger, Thread thread, String targetId, long begin) {
  10. this.logger = logger;
  11. this.threadInfo = thread.getId() + "-" + thread.toString();
  12. this.targetId = targetId;
  13. this.begin = begin;
  14. }
  15. public void trace(String targetEvent) {
  16. long duration = System.currentTimeMillis() - begin;
  17. long increment = duration - offtime;
  18. offtime = duration;
  19. float percentage = (float) increment / (float) duration * 100;
  20. if (duration > threshold && percentage > 20) {
  21. logger.error(
  22. "Response time is too large: [{}], {}/{} ({}), {}, {}",
  23. new String[] { threadInfo + "", increment + "",
  24. duration + "", percentage + "%", targetEvent,
  25. targetId });
  26. }
  27. }
  28. }

利用JVM的MXBean找到blocked的点

当你发现JVM占用的cpu很高,而且响应时间比较慢,很可能是被IO或者网络等慢速设备拖住了。也有可能是你的方法中某个同步点(同步方法或者对象)成为性能的瓶颈。这时候你可以利用JVM提供的monitor API来监控:

  1. <%@ page import="java.lang.management.*, java.util.*" %>
  2. <%!
  3. Map cpuTimes = new HashMap();
  4. Map cpuTimeFetch = new HashMap();
  5. %>
  6. <%
  7. out.println("Threads Monitoring");
  8. long cpus = Runtime.getRuntime().availableProcessors();
  9. ThreadMXBean threads = ManagementFactory.getThreadMXBean();
  10. threads.setThreadContentionMonitoringEnabled(true);
  11. long now = System.currentTimeMillis();
  12. ThreadInfo[] t = threads.dumpAllThreads(false, false);
  13. for (int i = 0; i < t.length; i++) {
  14. long id = t[i].getThreadId();
  15. Long idObj = new Long(id);
  16. long current = 0;
  17. if (cpuTimes.get(idObj) != null) {
  18. long prev = ((Long) cpuTimes.get(idObj)).longValue();
  19. current = threads.getThreadCpuTime(t[i].getThreadId());
  20. long catchTime = ((Long) cpuTimeFetch.get(idObj)).longValue();
  21. double percent = (double)(current - prev) / (double)((now - catchTime) * cpus * 1000);
  22. if (percent > 0 && prev > 0) {
  23. out.println("<li>" + t[i].getThreadName()+"#"+t[i].getThreadId() + " Time: " + percent + " (" + prev + ", " + current + ") ");
  24. String locked = t[i].getLockInfo()==null?"":t[i].getLockInfo().getClassName();
  25. out.println(" Blocked: (" + t[i].getBlockedTime() + ", " + t[i].getBlockedCount() + ", " + locked + ")</li>");
  26. }
  27. }
  28. cpuTimes.put(idObj, new Long(current));
  29. cpuTimeFetch.put(idObj, new Long(now));
  30. }
  31. %>

同步是性能的一大瓶颈

通过监控发现,大量线程block在一个同步方法上,这样cpu也使不上劲。当你发现性能上不去,IO和网络等慢速设备也不是问题的时候,你就得检查一下是否在某个关键点上使用了同步(synchronizae)。有时候也许是你应用的第三方的jar里面的某个方法是同步的,这种情况下,你就很难找到问题所在。只能在编写代码的时候看一下你引用的方法是否是同步的。

参考阅读

1. Java run-time monitoring 系列文章,比较系统的讲解了jvm的监控

2. Performance Tuning the JVM for Running Tomcat:本文列举了tomcat性能相关的几个关键的jvm 参数

3. 一本系统讲解Java性能的书:Java Performance

4. insideApps,一个事务级别的JavaEE的性能监控开源软件。它希望可以寄存在product环境中,在不影响系统性能的前提下,监控和分析产品的性能。想法很不错。

5. ManageEngine, 一个很强大的监控软件,有免费版。

原文链接:http://ctomentoring.blog.51cto.com/4445779/794813

如何进行Java EE性能测试与调优的更多相关文章

  1. [java] JVM监控与调优

    原文出处:http://www.cnblogs.com/zhguang/p/java-jvm-gc.html   光说不练假把式,学习Java GC机制的目的是为了实用,也就是为了在JVM出现问题时分 ...

  2. jvm系列(六):Java服务GC参数调优案例

    本文介绍了一次生产环境的JVM GC相关参数的调优过程,通过参数的调整避免了GC卡顿对JAVA服务成功率的影响. 这段时间在整理jvm系列的文章,无意中发现本文,作者思路清晰通过步步分析最终解决问题. ...

  3. 一文读懂Java GC原理和调优

    概述 本文介绍GC基础原理和理论,GC调优方法思路和方法,基于Hotspot jdk1.8,学习之后将了解如何对生产系统出现的GC问题进行排查解决 阅读时长约30分钟,内容主要如下: GC基础原理,涉 ...

  4. JAVA性能监控与调优参考文档链接

    JAVA性能监控与调优参考文档链接 jdk8工具集 https://docs.oracle.com/javase/8/docs/technotes/tools/unix/index.htmlTroub ...

  5. jvm 命令使用调优 通过jstat、jmap对java程序进行性能调优

    转载:http://blog.csdn.net/jerry024/article/details/8507589 转载: https://blog.csdn.net/zhaozheng7758/art ...

  6. 一文了解MySQL性能测试及调优中的死锁处理方法,你还看不明白?

    一文了解MySQL性能测试及调优中的死锁处理方法,你还看不明白? 以下从死锁检测.死锁避免.死锁解决3个方面来探讨如何对MySQL死锁问题进行性能调优. 死锁检测 通过SQL语句查询锁表相关信息: ( ...

  7. java大数据量调优

    从总体上来看,对于大型网站,比如门户网站,在面对大量用户访问.高并发请求方面,基本的解决方案集中在这样几个环节:1.首先需要解决网络带宽和Web请求的高并发,需要合理的加大服务器和带宽的投入,并且需要 ...

  8. 【java虚拟机】jvm调优原则

    转自:https://www.cnblogs.com/xiaopaipai/p/10522794.html 合理规划jvm性能调优 JVM性能调优涉及到方方面面的取舍,往往是牵一发而动全身,需要全盘考 ...

  9. java 内存 垃圾回收调优

    要了解Java垃圾收集机制,先理解JVM内存模式是非常重要的.今天我们将会了解JVM内存的各个部分.如何监控以及垃圾收集调优. Java(JVM)内存模型 正如你从上面的图片看到的,JVM内存被分成多 ...

随机推荐

  1. HTTP模块SuperAgent

    superagent它是一个强大并且可读性很好的轻量级ajaxAPI,是一个关于HTTP方面的一个库,而且它可以将链式写法玩的出神入化. var superagent = require('super ...

  2. 菜鸟教程之工具使用(四)——借助JRebel使Tomcat支持热部署

    JRebel是一个J2EE热部署的工具.使用它可以减少浪费8-18%的开发时间在项目的构建和部署上.虽然Java也提供了HotSpot的JVM,但是如果你修改的类中有方法名称变动的话,HotSpot就 ...

  3. Linux系统性能监控之6个vmstat和6个iostat命令

    这篇文章主要介绍一些Linux性能检测相关的命令. vmstat和iostat的两个命令可以运行在主流的Linux/Unix操作系统上. 如果vmstat和iostat命令不能再你的电脑上运行,请安装 ...

  4. matlab问题集总

    每次更新一点,慢慢增加 nargin nargin是用来判断输入变量个数的函数,这样就可以针对不同的情况执行不同的功能.通常可以用他来设定一些默认值,如下面的函数. 例子,函数test1的功能是输出a ...

  5. 21、uwp UI自动化测试(WinAppDriver)

    使用 UI自动化测试的好处就是在代码逻辑中写好 case 后,来实现 “一劳永逸” 的作用,并且自动化测试能够模拟人工达不到要求,比如快速切换页面.快速点击按钮等,对于提高软件的稳定性很有帮助. 安装 ...

  6. [整理]Unity3D游戏开发之Lua

    原文1:[Unity3D]Unity3D游戏开发之Lua与游戏的不解之缘(上) 各位朋友,大家好,我是秦元培,欢迎大家关注我的博客,我地博客地址是blog.csdn.net/qinyuanpei.如果 ...

  7. nginx源码分析:打开监听套接字的流程

    问题源于在分析nginx的源码时,找了半天没有找到nginx是怎么把监听套接字读事件添加到事件循环中的,后经过仔细的分析,终于搞明白,于是记录一下. 在上一篇module机制中介绍了nginx添加mo ...

  8. Python爬取新浪微博评论数据,写入csv文件中

    因为新浪微博网页版爬虫比较困难,故采取用手机网页端爬取的方式 操作步骤如下: 1. 网页版登陆新浪微博 2.打开m.weibo.cn 3.查找自己感兴趣的话题,获取对应的数据接口链接 4.获取cook ...

  9. goto语句的升级版,setjmp,longjmp

    我们知道goto语句是不能跳过函数的,但是在我么C语言的应用中,在不使用汇编的情况下,遇到需要跳出深层循环比如检错机制的时候,有确实想要跨函数跳转,有没有上面办法可以做到呢? 这就是今天要讲的两个库函 ...

  10. oracle中for循环

    DECLARE );-- 定义一个字符串变量str BEGIN .. loop -- INSERT INTO FW_TEST(NAME) VALUES('bbb' + i);DECODE('1','' ...