架构师训练营第 1 期第 7 周作业
问题:
性能压测的时候,随着并发压力的增加,系统响应时间和吞吐量如何变化,为什么?
用你熟悉的编程语言写一个 Web 性能压测工具,输入参数:URL,请求总次数,并发数。输出参数:平均响应时间,95% 响应时间。用这个测试工具以 10 并发、100 次请求压测 www.baidu.com。
解1:
图1
图2
如上图1为性能压测的时候随着并发压力的增加,系统响应吞吐量的变化曲线,解释如下:
系统刚开始资源充足,随着并发的增大,系统的吞吐量(TPS)线性增大,见图种a-b段;
当并发增大到一定大小,系统资源消耗增大,不足以支撑系统的吞吐量与并发数呈线性增长的态势,支撑系统的吞吐量增长变缓,见图b-c段;
当并发继续增大,系统资源消耗慢慢耗尽,此时系统吞吐量不增反降,直到系统资料耗尽,到系统奔溃点后,系统吞吐量为0. 这个阶段曲线见图c-d段;
如上图2为性能压测的时候随着并发压力的增加,系统响应时间的变化曲线,解释如下:
系统刚开始资源充足,随着并发的增大,系统的响应时间比较块而且稳定,见图种a-b段;
当并发增大到一定大小,系统资源消耗增大,不足以支撑系统的吞吐量与并发数呈线性增长的态势,这个阶段系统响应时间随着并发的增大逐渐增大,见图b-c段;
当并发继续增大,系统资源消耗慢慢耗尽,此时系统吞吐量不增反降,响应时间也急剧增大,直到系统资料耗尽,到系统奔溃点后,系统吞吐量为0,系统没有了响应。 这个阶段曲线见图c-d段;
解2:
本题用java来实现
程序实现用3个类来实现本功能:
TestResult.java:单个线程执行压测后测试结果类
LoadThread.java:压测线程类,实现Runable接口
MyLoadTestMain:压测主程序类,程序入口;
代码如下:
package org.yege.algorithm.loadtest;/** * 测试结果类 */public class TestResult { private boolean isSuccess;//是否成功,true;成功,false:失败 private long finishTime;//成功完成时间,单位ms public boolean isSuccess() { return isSuccess; } public void setSuccess(boolean success) { isSuccess = success; } public long getFinishTime() { return finishTime; } public void setFinishTime(long finishTime) { this.finishTime = finishTime; } @Override public String toString() { return "TestResult{" + "isSuccess=" + isSuccess + ", finishTime=" + finishTime + '}'; }}
package org.yege.algorithm.loadtest;import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;import java.net.HttpURLConnection;import java.net.URL;import java.net.URLConnection;import java.util.List;/** * 并发压测线程类 */public class LoadThread implements Runnable{ private List<TestResult> testResults;//测试结果集 private String loadUrl;//测试url public LoadThread(List<TestResult> testResults, String loadUrl) { this.testResults = testResults; this.loadUrl = loadUrl; } public void run() { TestResult testResult=new TestResult(); long startTime=System.currentTimeMillis(); try { URL url = new URL(loadUrl); URLConnection urlConnection = url.openConnection(); HttpURLConnection connection = (HttpURLConnection) urlConnection; BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream())); String urlString = ""; String current; while((current = in.readLine()) != null) { urlString += current; } testResult.setSuccess(true); }catch(IOException e) { testResult.setSuccess(false); } long endTime=System.currentTimeMillis(); long cha=endTime-startTime; testResult.setFinishTime(cha); testResults.add(testResult); //System.out.println(testResult.toString()); } public List<TestResult> getTestResults() { return testResults; } public void setTestResults(List<TestResult> testResults) { this.testResults = testResults; } public String getLoadUrl() { return loadUrl; } public void setLoadUrl(String loadUrl) { this.loadUrl = loadUrl; }}
package org.yege.algorithm.loadtest;import java.text.SimpleDateFormat;import java.util.*;/** * @author 业哥 * java版Web性能压测工具 * 需求: * 1.用java编程语言写一个 Web 性能压测工具, * 2.输入参数:URL,请求总次数,并发数。 * 3.输出参数:平均响应时间,95% 响应时间。 * 4.用这个测试工具以 10 并发、100 次请求压测 * * */public class MyLoadTestMain { /** * @param args * args[0]:参数1:并发数 * args[1]:参数2:总请求数 * args[2]:参数3:待压测url链接 */ public static void main(String[] args) { if(args==null||args.length!=3){ System.err.println("参数为空,或者参数个数小于3"); return; } int n1;//args[0]:参数1:并发数 int n2;//args[1]:参数2:总请求数 String loadUrl=args[2];//args[2]:待压测url链接 try { n1=Integer.parseInt(args[0]); n2=Integer.parseInt(args[1]); }catch (Exception ex){ System.err.println(ex.getMessage()); return; } if(n2<n1){ System.err.println("参数【总请求数】小于了参数【并发数】"); return; } //计算需要n1个并发请求的次数 int count=n2/n1;//eg:n2=100,n1=10,count=10 List<TestResult> testResults=new ArrayList<TestResult>(); SimpleDateFormat sdf =new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS"); //执行n2次总请求【以count次并发请求(每次n1个并发请求)】 for(int i=0;i<count;i++){ List<TestResult> subTestResults=new ArrayList<TestResult>(); for(int j=0;j<n1;j++){ Runnable runnable=new LoadThread(subTestResults,loadUrl); runnable.run(); } while (true){ if(subTestResults.size()==n1){ testResults.addAll(subTestResults); System.out.println(sdf.format(new Date())+":已经完成"+testResults.size()+"个请求"); break; } } } //计算平均响应时间 long totalTime=0; long successRequet=0; for(TestResult testResult:testResults){ if(testResult.isSuccess()){ successRequet++; totalTime+=testResult.getFinishTime(); } } double t=totalTime; double s=successRequet; double perQuestTime =t/s; //计算95%响应时间 Collections.sort(testResults, new Comparator<TestResult>() { public int compare(TestResult o1, TestResult o2) { if(o1.getFinishTime()>o2.getFinishTime()){return 1;} if(o1.getFinishTime()==o2.getFinishTime()){return 0;} if(o1.getFinishTime()<o2.getFinishTime()){return -1;} return -1; } }); int off= (int)(testResults.size()*0.95); long per95QuestTime=testResults.get(off).getFinishTime(); System.out.println("【本次测试】单次并发数:"+n1+",总请求数:"+n2+",测试url:"+loadUrl+""); System.out.println("【本次测试】平均响应时间:"+perQuestTime+"ms,95% 响应时间:"+per95QuestTime+"ms"); }}
测试结果截图1:
测试结果截图2:
测试结果截图3:
测试结果截图4:
业哥
架构即未来! 2018.02.19 加入
还未添加个人简介
评论