写点什么

架构师训练营 - 作业 7

发布于: 2020 年 07 月 22 日
架构师训练营 - 作业 7

1.性能压测的时候,随着并发压力的增加,系统响应时间和吞吐量如何变化,为什么?

性能压测时,在性能测试,负载测试和压力测试时,系统响应时间变化如下图

性能压测时,在性能测试,负载测试和压力测试时,系统吞吐量变化如下图

由图可见,在性能测试阶段,系统响应时间近似不变,吞吐量近似于线性上升,在负载测试阶段,响应时间明显增大,吞吐量上升趋势减缓,在压力测试阶段,响应时间急剧增大,吞吐量下降直至系统崩溃。


其原因为:在性能测试阶段, 系统硬软件资源尚未完全被使用,可以通过增加系统软硬件资源的方式来响应不断增加的并发情求,在负载测试阶段,由于系统资源已经几乎完全被占用,所以会出现并发请求排队,系统线程调度等耗费,造成并发请求响应时间延长,吞吐量上升趋势减缓,到了压力测试阶段,由于系统资源耗尽,出现了大量并发请求拥堵等待,系统响应时间急剧增大,吞吐量下降直至系统不可用。


2.用你熟悉的语言编写一个 web 性能压测工具,输入参数:URL,请求总次数,并发数。输出参数:平均响应时间,95%响应时间。用这个测试工具以 10 并发,100 次请求压测 www.baidu.com。


代码如下:

import java.util.Map;import java.util.concurrent.ConcurrentHashMap;import java.util.concurrent.atomic.AtomicInteger;import java.net.URL;import java.net.URLConnection;import java.time.Instant;import java.time.temporal.ChronoUnit;import java.net.HttpURLConnection;import java.io.BufferedReader;import java.io.InputStreamReader;import java.io.IOException;
public class TestPerformance implements Runnable{ public static Map<String, Long> map = new ConcurrentHashMap<String, Long>(); //每个线程的执行次数 private int totalCount; //测试访问网站的URL private String urlString; //记录多线程的总执行次数,保证高并发下的原子性 public static AtomicInteger atomicInteger = new AtomicInteger(0); public TestPerformance(int totalCount, String urlString) { this.totalCount = totalCount; this.urlString = urlString; } @Override public void run() { int count = 0; while (count < totalCount) { count++; atomicInteger.getAndIncrement(); Instant now = Instant.now(); testConnectWebSite(); long used = ChronoUnit.MILLIS.between(now, Instant.now()); System.out.println("线程ID与对应的执行次数:" + Thread.currentThread().getId() + "--->" + count+" , 耗时"+used+"ms"); map.put("线程ID与对应的执行次数:" + Thread.currentThread().getId() + "--->" + count,used); } } public void testConnectWebSite(){ try { URL url = new URL(urlString); //连接网站 URLConnection urlConnection = url.openConnection(); HttpURLConnection connection = null; if(!(urlConnection instanceof HttpURLConnection)) { System.out.println("请输入正确 URL 地址"); return; } connection = (HttpURLConnection) urlConnection; BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream())); //打印网站输出内容,用于验证网站可正常访问 String contents = ""; String current; while((current = in.readLine()) != null) { contents += current; } System.out.println(contents); } catch(IOException e) { e.printStackTrace(); } }}
复制代码


import java.util.Collections;import java.util.Comparator;import java.util.LinkedList;import java.util.List;import java.util.Map;import java.util.Map.Entry;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.TimeUnit;
public class StressTester {
public void doTest(int threadSize,int totalCount, String urlString) throws InterruptedException{ if (threadSize<1){ System.out.println("线程并发数量不能小于1"); return; } if (totalCount<1){ System.out.println("线程运行次数不能小于1"); return; } if ((urlString == null)||(urlString.equals(""))){ System.out.println("测试连接网站URL不能为空"); return; } //创建线程池 ExecutorService executorService = Executors.newFixedThreadPool(threadSize); //让线程池中的每一个线程都开始工作 for (int j = 0; j < threadSize; j++) { //执行线程 executorService.execute(new TestPerformance(totalCount,urlString)); } //等线程全部执行完后关闭线程池 executorService.shutdown(); executorService.awaitTermination(Integer.MAX_VALUE, TimeUnit.DAYS); List<Map.Entry<String, Long>> sortedEntryList = sortEntryByEntryValue(TestPerformance.map); if (sortedEntryList.size()>1) { System.out.println("Performance test result show below:===================="); System.out.println("平均响应时间为:"+calculateAvgResponTime(sortedEntryList)+"ms"); System.out.println("95%请求响应时间为:"+calculateSpecifiedPercentageResponTime(sortedEntryList, 0.95)+"ms"); return; } System.out.println("未能获取测试数据"); } //按照Entry的value(每次连接测试网站响应时间)大小排序并按照升序将Entry顺序放入list中 public LinkedList<Entry<String,Long>> sortEntryByEntryValue(Map<String, Long> map){ LinkedList<Map.Entry<String,Long>> list = new LinkedList<Map.Entry<String,Long>>(map.entrySet()); Comparator<Map.Entry<String,Long>> comparator = Comparator.comparing(Map.Entry::getValue); Collections.sort(list,comparator); return list; } //根据按照Entry的value(每次连接测试网站响应时间)大小排序的list计算平均响应时间 public Double calculateAvgResponTime(List<Map.Entry<String, Long>> list){ return list.stream().mapToLong(Map.Entry::getValue).average().getAsDouble(); } //根据按照Entry的value(每次连接测试网站响应时间)大小排序的list和给定百分比计算百分比响应时间(即) public Long calculateSpecifiedPercentageResponTime(List<Map.Entry<String, Long>> list,double percentage){ return list.get(new Long(Math.round(list.size()*percentage)).intValue()-1).getValue();
} //模拟测试入口类 public static void main(String[] args) throws InterruptedException{ new StressTester().doTest(10, 100, "http://www.baidu.com"); }
}
复制代码


测试结果:


平均响应时间为:48.593ms

95%请求响应时间为: 95ms


用户头像

还未添加个人签名 2020.05.13 加入

还未添加个人简介

评论

发布
暂无评论
架构师训练营 - 作业 7