如何进行Java EE性能测试与调优
性能测试的目标
性能测试不同于功能测试,不是对与错的检验,而是快与慢的衡量。在进行真正的性能测试之前要先搞清楚目标:
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到你的测试环境中,就能重现比较慢点查询,加以改进。但是如果是并发用户或者网络等运行时环境的问题,你就很难重现。这时,如果你能通过日志看到那些关键的响应慢的方法,也许可以帮助你快点找到问题所在。下面的代码可以帮你做到这一点,仅供参考:
- import org.slf4j.Logger;
- public class TraceUtil {
- final Logger logger;
- final long threshold = 1000;
- private long begin;
- private long offtime = 0;
- private String threadInfo;
- private String targetId;
- public TraceUtil(Logger logger, Thread thread, String targetId, long begin) {
- this.logger = logger;
- this.threadInfo = thread.getId() + "-" + thread.toString();
- this.targetId = targetId;
- this.begin = begin;
- }
- public void trace(String targetEvent) {
- long duration = System.currentTimeMillis() - begin;
- long increment = duration - offtime;
- offtime = duration;
- float percentage = (float) increment / (float) duration * 100;
- if (duration > threshold && percentage > 20) {
- logger.error(
- "Response time is too large: [{}], {}/{} ({}), {}, {}",
- new String[] { threadInfo + "", increment + "",
- duration + "", percentage + "%", targetEvent,
- targetId });
- }
- }
- }
利用JVM的MXBean找到blocked的点
当你发现JVM占用的cpu很高,而且响应时间比较慢,很可能是被IO或者网络等慢速设备拖住了。也有可能是你的方法中某个同步点(同步方法或者对象)成为性能的瓶颈。这时候你可以利用JVM提供的monitor API来监控:
- <%@ page import="java.lang.management.*, java.util.*" %>
- <%!
- Map cpuTimes = new HashMap();
- Map cpuTimeFetch = new HashMap();
- %>
- <%
- out.println("Threads Monitoring");
- long cpus = Runtime.getRuntime().availableProcessors();
- ThreadMXBean threads = ManagementFactory.getThreadMXBean();
- threads.setThreadContentionMonitoringEnabled(true);
- long now = System.currentTimeMillis();
- ThreadInfo[] t = threads.dumpAllThreads(false, false);
- for (int i = 0; i < t.length; i++) {
- long id = t[i].getThreadId();
- Long idObj = new Long(id);
- long current = 0;
- if (cpuTimes.get(idObj) != null) {
- long prev = ((Long) cpuTimes.get(idObj)).longValue();
- current = threads.getThreadCpuTime(t[i].getThreadId());
- long catchTime = ((Long) cpuTimeFetch.get(idObj)).longValue();
- double percent = (double)(current - prev) / (double)((now - catchTime) * cpus * 1000);
- if (percent > 0 && prev > 0) {
- out.println("<li>" + t[i].getThreadName()+"#"+t[i].getThreadId() + " Time: " + percent + " (" + prev + ", " + current + ") ");
- String locked = t[i].getLockInfo()==null?"":t[i].getLockInfo().getClassName();
- out.println(" Blocked: (" + t[i].getBlockedTime() + ", " + t[i].getBlockedCount() + ", " + locked + ")</li>");
- }
- }
- cpuTimes.put(idObj, new Long(current));
- cpuTimeFetch.put(idObj, new Long(now));
- }
- %>
同步是性能的一大瓶颈
通过监控发现,大量线程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性能测试与调优的更多相关文章
- [java] JVM监控与调优
原文出处:http://www.cnblogs.com/zhguang/p/java-jvm-gc.html 光说不练假把式,学习Java GC机制的目的是为了实用,也就是为了在JVM出现问题时分 ...
- jvm系列(六):Java服务GC参数调优案例
本文介绍了一次生产环境的JVM GC相关参数的调优过程,通过参数的调整避免了GC卡顿对JAVA服务成功率的影响. 这段时间在整理jvm系列的文章,无意中发现本文,作者思路清晰通过步步分析最终解决问题. ...
- 一文读懂Java GC原理和调优
概述 本文介绍GC基础原理和理论,GC调优方法思路和方法,基于Hotspot jdk1.8,学习之后将了解如何对生产系统出现的GC问题进行排查解决 阅读时长约30分钟,内容主要如下: GC基础原理,涉 ...
- JAVA性能监控与调优参考文档链接
JAVA性能监控与调优参考文档链接 jdk8工具集 https://docs.oracle.com/javase/8/docs/technotes/tools/unix/index.htmlTroub ...
- jvm 命令使用调优 通过jstat、jmap对java程序进行性能调优
转载:http://blog.csdn.net/jerry024/article/details/8507589 转载: https://blog.csdn.net/zhaozheng7758/art ...
- 一文了解MySQL性能测试及调优中的死锁处理方法,你还看不明白?
一文了解MySQL性能测试及调优中的死锁处理方法,你还看不明白? 以下从死锁检测.死锁避免.死锁解决3个方面来探讨如何对MySQL死锁问题进行性能调优. 死锁检测 通过SQL语句查询锁表相关信息: ( ...
- java大数据量调优
从总体上来看,对于大型网站,比如门户网站,在面对大量用户访问.高并发请求方面,基本的解决方案集中在这样几个环节:1.首先需要解决网络带宽和Web请求的高并发,需要合理的加大服务器和带宽的投入,并且需要 ...
- 【java虚拟机】jvm调优原则
转自:https://www.cnblogs.com/xiaopaipai/p/10522794.html 合理规划jvm性能调优 JVM性能调优涉及到方方面面的取舍,往往是牵一发而动全身,需要全盘考 ...
- java 内存 垃圾回收调优
要了解Java垃圾收集机制,先理解JVM内存模式是非常重要的.今天我们将会了解JVM内存的各个部分.如何监控以及垃圾收集调优. Java(JVM)内存模型 正如你从上面的图片看到的,JVM内存被分成多 ...
随机推荐
- SSH框架整合开发具体解释(个人笔记)
一.创建数据库并设置编码. A) create database oa default character set utf8. 二.MyEclipseproject A) 在Myeclipse里创建w ...
- mysql trigger 触发器
创建触发器: CREATE [DEFINER = {user|CURRENT_USER}] TRIGGER trigger_name trigger_time trigger_event ON tbl ...
- 菜鸟学SSH(十三)——Spring容器IOC解析及简单实现
最近一段时间,“容器”两个字一直萦绕在我的耳边,甚至是吃饭.睡觉的时候都在我脑子里蹦来蹦去的.随着这些天一次次的交流.讨论,对于容器的理解也逐渐加深.理论上的东西终归要落实到实践,今天就借助Sprin ...
- 构造函数 (C++)
构造函数是一种可初始化其类的实例的成员函数. 构造函数具有与类相同的名称,没有返回值. 构造函数可以具有任意数量的参数,类可以具有任意数量的重载构造函数. 构造函数可以具有任何可访问性(公共.受保护或 ...
- python(35):多线程读取文件
多线程读取文件: # _*_coding:utf-8_*_ import time, threading, ConfigParser ''' Reader类,继承threading.Thread @_ ...
- 使用一层神经网络训练mnist数据集
import numpy as np import tensorflow as tf from tensorflow.examples.tutorials.mnist import input_dat ...
- 使用 Trace 将日志输入到文件中
工具没有好坏,只有适不适用.由于项目中用 Log4Net 过重,所以使用 Trace 代替了 Log4Net 输入一些简单的日志信息: 自定义监听文件 using System; using Syst ...
- button上传替换file上传按钮,并显示图片缩略图,纯jsp操作
1.jsp代码 <div class="inputBox"> <span id="tu" <c:if test="${pd = ...
- tongjiword,write / read file demo
1.tong ji letter demo mport sys def tongjiword(): fi =open(paht,'r') cont=fi.read() wl={} for line i ...
- jsp----标签编程(JSTL)
标签编程简介 JSP的开发是在HTML代码中嵌入了大量的Java代码,但是这样一来会使得JSP页面中充满了Java程序,修改或维护起来非常的不方便, 定义一个简单的标签----空标签 要想实现一个标签 ...