架构师训练营 第七周 课后练习

发布于: 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%响应时间16ms
Process finished with exit code 0

注意点

在计算百分位响应时间的时候需要先把之前的所有的请求响应时间进行从小到大的排序后再取对应的百分位时间数据。

发布于: 2020 年 07 月 21 日 阅读数: 11
用户头像

且听且吟

关注

没有绝世高手 2018.06.30 加入

还未添加个人简介

评论

发布
暂无评论
架构师训练营 第七周 课后练习