性能测试的指标
1)响应时间(Response Time):从用户角度评价系统的处理速度。反映了服务器端的处理速度。
经验参考标准:(2秒,5秒,10秒)即:2秒之内,体验非常好,2~5秒之间,可以接受,5-10秒体验一般,10秒以上体验很差。
2)吞吐量/吞吐率(IO)。
硬盘的IO、网络的IO、cpu,内存、请求处理能力、打开页面数量。
3)事务的处理能力 –TPS(Transaction per second)。
吞吐率
我们一般使用单位时间内服务器处理的请求数来描述其并发处理能力。称之为吞吐率(Throughput),单位是 “req/s”。吞吐率特指Web服务器单位时间内处理的请求数。
另一种描述,吞吐率是,单位时间内网络上传输的数据量,也可以指单位时间内处理客户请求数量。它是衡量网络性能的重要指标。通常情况下,吞吐率“字节数/秒”来衡量。当然你也可以用“请求数/秒”和“页面数/秒”来衡量。其实不管一个请求还是一个页面,它的本质都是在网络上传输的数据,那么用来表述数据的单位就是字节数。
吞吐量/吞吐率
吞吐量,是指在一次性能测试过程中网络上传输的数据量的总和。
对于交互式应用来说,吞吐量指标反映的是服务器承受的压力,在容量规划的测试中,吞吐量是一个重点关注的指标,因为它能够说明系统级别的负载能力,另外,在性能调优过程中,吞吐量指标也有重要的价值。如一个大型工厂,他们的生产效率与生产速度很快,一天生产10W吨的货物,结果工厂的运输能力不行,就两辆小型三轮车一天拉2吨的货物,比喻有些夸张,但我想说明的是这个运输能力是整个系统的瓶颈。
提示,用吞吐量来衡量一个系统的输出能力是极其不准确的,用个最简单的例子说明,一个水龙头开一天一夜,流出10吨水;10个水龙头开1秒钟,流出0.1吨水。当然是一个水龙头的吞吐量大。你能说1个水龙头的出水能力是10个水龙头的强?所以,我们要加单位时间,看谁1秒钟的出水量大。这就是吞吐率。
意义:
1)吞吐量的限制是性能瓶颈的一种重要表现形式,因此,有针对地对吞吐量设计测试,可以协助尽快定位到性能冰晶所在的位置
2) 80%系统的性能瓶颈都是由吞吐量制约
3)并发用户和吞吐量瓶颈之间存在一定的关联
4) 通过不断增加并发用户数和吞吐量观察系统的性能瓶颈。然后,从网络、数据库、应用服务器和代码本身4个环节确定系统的性能瓶颈。
事务处理能力 TPS (Transaction Per Second)
就是用户某一步或几步操作的集合。不过,我们要保证它有一个完整意义。比如用户对某一个页面的一次请求,用户对某系统的一次登录,淘宝用户对商品的一次确认支付过程。这些我们都可以看作一个事务。那么如何衡量服务器对事务的处理能力。又引出一个概念—-TPS
每秒钟系统能够处理事务或交易的数量,它是衡量系统处理能力的重要指标。
点击率可以看做是TPS的一种特定情况。点击率更能体现用户端对服务器的压力。TPS更能体现服务器对客户请求的处理能力。
每秒钟用户向web服务器提交的HTTP请求数。这个指标是web 应用特有的一个指标;web应用是“请求-响应”模式,用户发一个申请,服务器就要处理一次,所以点击是web应用能够处理的交易的最小单位。如果把每次点击定义为一个交易,点击率和TPS就是一个概念。容易看出,点击率越大。对服务器的压力也越大,点击率只是一个性能参考指标,重要的是分析点击时产生的影响。
需要注意的是,这里的点击不是指鼠标的一次“单击”操作,因为一次“单击”操作中,客户端可能向服务器发现多个HTTP请求。
性能测试的核心原理
1、基于协议(网络分布式架构:网络协议)
2、多线程(目的是模拟用户负载)
3、模拟真实场景(所有用户同时在线?用户访问随时间而不同…)
前两个是技术层面,能用工具解决。所有工具只能帮我们解决1/3的问题。
但后一个最重要,需要时间和经验的积累、透彻深入的测试逻辑框架。
java实现性能测试
性能测试不同于功能测试,不需要针对所有功能测试,而是针对核心功能来测试。
实例:针对论坛登录和发帖两个核心功能来实现
//未测试,见邓强老师视频
public class TestMain implements Runnable {
private static int threadCount=50;//50个线程,即50个用户
private int iterationCount=20;//每个用户的发帖数量
private int pacingTime=0;//unit:millisecond
private int thinkTime=0;//unit:millisecond
public void run() {
PhpwindPost pwPost=new PhpwindPost();
pwPost.doLogin();//登录1次
for(int i=0;i<iterationCount;i++){//发帖20次
pwPost.doPost(this.thinkTime);//每发一个帖子暂停的时间
try{Thread.sleep(pacingTime);} catch(Exception e){}
}
}
public static void main(String[] args) {
Runnable request=new TestMain();
for(int i=0;i<threadCount;i++){
Thread thread=new Thread(request);
thread.start();//开启多线程
}
Handler handler=new Handler();
Requestor requestor=new Requestor();
String source=requestor.sendGet("http://localhost/phpwind/","UTF-8");
List links=handler.correlate(source,"<a href=\"","\"");
for(int i=0;i<links.size();i++){
System.out.println(links.get(i).toString());
}
}
}
public class PhpwindPost {
private String host="moggie";
private int port=80;
private MultiThreadedHttpConnectionManager connectionManager=
new MultiThreadedHttpConnectionManager();
private HttpClient client=new HttpClient(connectionManager);
//下载的控件HttpClient(Apache的开源框架)
public PhpWindPost(){
client.getHostConfiguration().setHost(host,port);
}
public void doLogin() {
PostMethod login=new PostMethod("/phpwind/login.php?");
NameValuePair step=new NameValuePair("step","2");
NameValuePair lgt=new NameValuePair("lgt","0");
NameValuePair pwuser=new NameValuePair("pwuser","denny");
NameValuePair pwpwd=new NameValuePair("pwpwd","123456");
login.setRequestBody(new NameValuePair[]{step,lgt,pwuser,pwpwd});
try{
client.executeMethod(login);
}
catch(Exception e){
e.printStackTrace();
}
finally{
login.releaseConnection();
}
}
public void doPost(int thinkTime) {
long startTime=System.currentTimeMillis();
PostMethod correlate=new PostMethod("/phpwind/post.php?fid=29");
String verifyCode="";
try{
client.executeMethod(correlate);
String source=new String(correlate.getResponseBody(),"UTF-8");
verifyCode=new Handler().correlate
(source,"name=\"verify\" value=\"","\" />",1);
}
catch(Exception e){
}
finally{
correlate.releaseConnection();
}
//获取当天日期,并以yyyy-mm-dd进行格式化
SimpleDateFormat formatter=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
Date date=new Date();
String createtime=formatter.format(date.getTime());
//组合Post请求
PostMethod post=new PostMethod("/phpwind/post.php?");
NameValuePair verify=new NameValuePair("verify",verifyCode);
NameValuePair atc_title=new NameValuePair("atc_title",new Handler().
getRandom(10000,9999999,7)+":Subject on"+createTime);
NameValuePair atc_content=new NameValuePair("atc_content",new Handler().
getRandom(10000,9999999,7)+":Sent by Java code automatically on"+createTime);
NameValuePair step_2=new NameValuePair("step","2");
NameValuePair pid=new NameValuePair("pid","");
NameValuePair action=new NameValuePair("action","new");
NameValuePair fid=new NameValuePair("fid","29");
login.setRequestBody(new NameValuePair[]{verify,atc_title,atc_content,step_2
,pid,action,fid});
try{
client.executeMethod(post);
}
catch(Exception e){
}
finally{
post.releaseConnection();
}
try{
Thread.sleep(thinkTime);
}catch(Exception e){}
long endTime=System.currentTimeMillis();
System.out.println("Response Time:"+(endTime-startTime)+"Milliseconds");
}
}