架构师训练营 第七周 课后练习
发布于: 2020 年 07 月 21 日
作业
用你熟悉的编程语言写一个web性能压测工具,输入参数:URL、请求总次数、并发数。输出参数:平均响应时间,95%响应时间。用这个测试工具以10并发、100次请求压测 https://www.baidu.com。
源代码结构
图1 源代码结构
源代码
package com.xianyanyang.concurrence;import org.apache.http.client.methods.CloseableHttpResponse;import org.apache.http.client.methods.HttpGet;import org.apache.http.impl.client.CloseableHttpClient;import org.apache.http.impl.client.HttpClientBuilder;import java.io.IOException;import java.util.Collection;import java.util.HashMap;import java.util.LinkedHashMap;import java.util.Map;import java.util.concurrent.CountDownLatch;import java.util.stream.Collectors;/** * 性能压测服务 */public class PerformancePressureMeasurement { /** * 压测地址 */ private String targetUrl; /** * 请求总次数 */ private int requestAmountCount; /** * 并发数 */ private int threadNumber; /** * 构造函数 * * @param targetUrl 压测地址 * @param requestAmountCount 请求总次数 * @param threadNumber 并发数 */ public PerformancePressureMeasurement(String targetUrl, int requestAmountCount, int threadNumber) { this.targetUrl = targetUrl; this.requestAmountCount = requestAmountCount; this.threadNumber = threadNumber; } /** * 运行并发线程 */ public void runThread() { CountDownLatch countDownLatch = null; try { countDownLatch = new CountDownLatch(1); for (int i = 0; i < threadNumber; i++) { new Thread(new Run(countDownLatch)).start(); } } catch (Exception e) { System.out.println("请求失败"); } finally { if (countDownLatch != null) { countDownLatch.countDown(); } } } /** * 批量运行并发线程 * * @return 响应时间排序列表(从小到大) */ public Collection<Long> batchRunThread() { System.out.println("开始进行对[" + targetUrl + "]的压测,请求总次数为[" + requestAmountCount + "],并发数为[" + threadNumber + "]"); Map<Integer, Long> times = new HashMap<>(); long allStartTime = System.currentTimeMillis(); for (int i = 1; i <= requestAmountCount; i++) { long startTime = System.currentTimeMillis(); this.runThread(); long endTime = System.currentTimeMillis(); long cost = endTime - startTime; // System.out.println("第" + i + "次请求" + " ended at: " + endTime + ", cost: " + cost + " ms."); times.put(i, cost); } long allEndTime = System.currentTimeMillis(); long allCost = allEndTime - allStartTime; System.out.println("压测结果为:"); System.out.println("-- 总耗时" + allCost + "ms"); System.out.println("-- 平均响应时间" + allCost / 100 + "ms"); LinkedHashMap<Integer, Long> sortedMap = times.entrySet() .stream() .sorted(Map.Entry.comparingByValue()) .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (e1, e2) -> e1, LinkedHashMap::new)); sortedMap.entrySet().forEach(entry -> System.out.println("第" + entry.getKey() + "次耗时" + entry.getValue() + "ms")); return sortedMap.values(); } /** * 线程类 */ private class Run implements Runnable { private final CountDownLatch startLatch; public Run(CountDownLatch startLatch) { this.startLatch = startLatch; } @Override public void run() { try { startLatch.await(); doGet(targetUrl); } catch (Exception e) { e.printStackTrace(); } } } private void doGet(String url) { CloseableHttpClient httpClient = HttpClientBuilder.create().build(); HttpGet httpGet = new HttpGet(url); CloseableHttpResponse response = null; try { response = httpClient.execute(httpGet); System.out.println(response.getStatusLine()); } catch (IOException e) { e.printStackTrace(); } finally { try { assert response != null; response.close(); httpClient.close(); } catch (IOException e) { e.printStackTrace(); } } }}
单元测试用例
package com.xianyanyang.concurrence;import junit.framework.TestCase;import java.util.Collection;public class PerformancePressureMeasurementTest extends TestCase { private PerformancePressureMeasurement performancePressureMeasurement; private String targetUrl = "https://www.baidu.com/"; private int requestAmountCount = 100; private int threadNumber = 10; @Override public void setUp() { performancePressureMeasurement = new PerformancePressureMeasurement(targetUrl, requestAmountCount, threadNumber); } public void testBatchRunThread() { Collection<Long> times = performancePressureMeasurement.batchRunThread(); Object[] timesArray = times.toArray(); Object percent = timesArray[94]; System.out.println("-- 95%响应时间" + percent + "ms"); }}
单元测试结果
"D:\Program Files\Java\jdk-10\bin\java.exe" -ea -Didea.test.cyclic.buffer.size=1048576 "-javaagent:D:\Program Files\JetBrains\IntelliJ IDEA 2018.1.5\lib\idea_rt.jar=63834:D:\Program Files\JetBrains\IntelliJ IDEA 2018.1.5\bin" -Dfile.encoding=UTF-8 -classpath "D:\Program Files\JetBrains\IntelliJ IDEA 2018.1.5\lib\idea_rt.jar;D:\Program Files\JetBrains\IntelliJ IDEA 2018.1.5\plugins\junit\lib\junit-rt.jar;D:\Program Files\JetBrains\IntelliJ IDEA 2018.1.5\plugins\junit\lib\junit5-rt.jar;E:\book\architect-design\target\test-classes;E:\book\architect-design\target\classes;F:\repository\org\apache\commons\commons-collections4\4.4\commons-collections4-4.4.jar;F:\repository\org\apache\commons\commons-math3\3.6.1\commons-math3-3.6.1.jar;F:\repository\org\apache\httpcomponents\httpclient\4.5.10\httpclient-4.5.10.jar;F:\repository\org\apache\httpcomponents\httpcore\4.4.9\httpcore-4.4.9.jar;F:\repository\commons-codec\commons-codec\1.11\commons-codec-1.11.jar;F:\repository\commons-logging\commons-logging\1.2\commons-logging-1.2.jar;F:\repository\junit\junit\4.13\junit-4.13.jar;F:\repository\org\hamcrest\hamcrest-core\1.3\hamcrest-core-1.3.jar" com.intellij.rt.execution.junit.JUnitStarter -ideVersion5 -junit3 com.xianyanyang.concurrence.PerformancePressureMeasurementTest,testBatchRunThread开始进行对[https://www.baidu.com/]的压测,请求总次数为[100],并发数为[10]压测结果为:-- 总耗时359ms-- 平均响应时间3ms第76次耗时0ms第3次耗时1ms第6次耗时1ms第10次耗时1ms第12次耗时1ms第13次耗时1ms第18次耗时1ms第20次耗时1ms第21次耗时1ms第22次耗时1ms第23次耗时1ms第24次耗时1ms第26次耗时1ms第27次耗时1ms第29次耗时1ms第31次耗时1ms第32次耗时1ms第35次耗时1ms第36次耗时1ms第37次耗时1ms第39次耗时1ms第40次耗时1ms第41次耗时1ms第43次耗时1ms第45次耗时1ms第47次耗时1ms第49次耗时1ms第61次耗时1ms第62次耗时1ms第64次耗时1ms第65次耗时1ms第66次耗时1ms第69次耗时1ms第75次耗时1ms第84次耗时1ms第87次耗时1ms第90次耗时1ms第93次耗时1ms第95次耗时1ms第4次耗时2ms第5次耗时2ms第11次耗时2ms第14次耗时2ms第17次耗时2ms第19次耗时2ms第25次耗时2ms第28次耗时2ms第30次耗时2ms第34次耗时2ms第38次耗时2ms第42次耗时2ms第44次耗时2ms第46次耗时2ms第48次耗时2ms第51次耗时2ms第54次耗时2ms第55次耗时2ms第58次耗时2ms第60次耗时2ms第63次耗时2ms第67次耗时2ms第68次耗时2ms第71次耗时2ms第73次耗时2ms第74次耗时2ms第77次耗时2ms第81次耗时2ms第83次耗时2ms第86次耗时2ms第88次耗时2ms第91次耗时2ms第94次耗时2ms第1次耗时3ms第7次耗时3ms第8次耗时3ms第15次耗时3ms第16次耗时3ms第33次耗时3ms第70次耗时3ms第79次耗时3ms第82次耗时3ms第96次耗时3ms第97次耗时3ms第98次耗时3ms第100次耗时3ms第2次耗时4ms第80次耗时4ms第89次耗时4ms第9次耗时5ms第52次耗时5ms第57次耗时6ms第78次耗时6ms第53次耗时9ms第85次耗时9ms第72次耗时14ms第50次耗时16ms第56次耗时28ms第59次耗时33ms第99次耗时34ms第92次耗时39ms-- 95%响应时间16msProcess finished with exit code 0
注意点
在计算百分位响应时间的时候需要先把之前的所有的请求响应时间进行从小到大的排序后再取对应的百分位时间数据。
划线
评论
复制
发布于: 2020 年 07 月 21 日阅读数: 140
版权声明: 本文为 InfoQ 作者【且听且吟】的原创文章。
原文链接:【http://xie.infoq.cn/article/cf8a056946c5996caad0c47bf】。未经作者许可,禁止转载。
且听且吟
关注
没有绝世高手 2018.06.30 加入
还未添加个人简介
评论