写点什么

架构师训练营 -Week 07 命题作业

发布于: 2020 年 07 月 22 日



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

系统资源未饱和的情况下,随着并发压力的增加,系统的响应时间不变或缓慢增长,吞吐量上升;

到达系统资源饱和的点之后,随着并发压力的增加,系统的响应时间急剧增长,吞吐量下降;

因为CPU、磁盘/网络IO等系统资源是有限的,超过资源的消耗,会倒置系统的处理能力下降,甚至系统会崩溃不能正常运行。

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

线程并发主要用了Executor框架中的自定义ThreadPoolExecutor线程池来实现,web请求实现了Callable接口返回响应时间,executor.invokeAll对多个线程任务统一返回处理请求结果。

采用了HttpURLCollection来对URL进行Web请求,本来打算用的是HttpClient或者Okhttp来实现web请求,但是底层实现有连接池,如果连接池没设计好可能会影响测试,所以还是用来单线程同步请求的HttpURLCollection类来实现。

ConcurrencyTestResult类:

/**
* 并发测试结果
*/
public class ConcurrencyTestResult {
/**
* 平均响应时间(毫秒)
*/
private long averageResponseTime;
/**
* 95%响应时间(毫秒)
*/
private long ninetyFivePercentageResponseTime;
/**
* 最小响应时间(毫秒)
*/
private long minPercentageResponseTime;
/**
* 最大响应时间(毫秒)
*/
private long maxPercentageResponseTime;
/**
* 请求成功次数
*/
private int requestSucceedNum;
/**
* 请求失败次数
*/
private int requestFailedNum;
public ConcurrencyTestResult() {
}
public ConcurrencyTestResult(long averageResponseTime, long ninetyFivePercentageResponseTime, long minPercentageResponseTime, long maxPercentageResponseTime, int requestSucceedNum, int requestFailedNum) {
this.averageResponseTime = averageResponseTime;
this.ninetyFivePercentageResponseTime = ninetyFivePercentageResponseTime;
this.minPercentageResponseTime = minPercentageResponseTime;
this.maxPercentageResponseTime = maxPercentageResponseTime;
this.requestSucceedNum = requestSucceedNum;
this.requestFailedNum = requestFailedNum;
}
public long getAverageResponseTime() {
return averageResponseTime;
}
public void setAverageResponseTime(long averageResponseTime) {
this.averageResponseTime = averageResponseTime;
}
public long getNinetyFivePercentageResponseTime() {
return ninetyFivePercentageResponseTime;
}
public void setNinetyFivePercentageResponseTime(long ninetyFivePercentageResponseTime) {
this.ninetyFivePercentageResponseTime = ninetyFivePercentageResponseTime;
}
public long getMinPercentageResponseTime() {
return minPercentageResponseTime;
}
public void setMinPercentageResponseTime(long minPercentageResponseTime) {
this.minPercentageResponseTime = minPercentageResponseTime;
}
public long getMaxPercentageResponseTime() {
return maxPercentageResponseTime;
}
public void setMaxPercentageResponseTime(long maxPercentageResponseTime) {
this.maxPercentageResponseTime = maxPercentageResponseTime;
}
public int getRequestSucceedNum() {
return requestSucceedNum;
}
public void setRequestSucceedNum(int requestSucceedNum) {
this.requestSucceedNum = requestSucceedNum;
}
public int getRequestFailedNum() {
return requestFailedNum;
}
public void setRequestFailedNum(int requestFailedNum) {
this.requestFailedNum = requestFailedNum;
}
public void print() {
System.out.printf("平均响应时间: %s(ms)\n", averageResponseTime);
System.out.printf("百分之95响应时间: %s(ms)\n", ninetyFivePercentageResponseTime);
System.out.printf("最小响应时间: %s(ms)\n", minPercentageResponseTime);
System.out.printf("最大响应时间: %s(ms)\n", maxPercentageResponseTime);
System.out.printf("请求成功次数: %s次\n", requestSucceedNum);
System.out.printf("请求失败次数: %s次\n", requestFailedNum);
}
}



RequestTask类:

/**
* 请求任务
*
*/
public class RequestTask implements Callable<RequestTaskResult> {
private String url;
private String method;
public RequestTask(String url, String method) {
this.url = url;
this.method = method;
}
@Override
public RequestTaskResult call() {
HttpURLConnection connection = null;
RequestTaskResult result = new RequestTaskResult();
Long responseTime = 0L;
Boolean requestSuccess = false;
try {
long startTime = System.currentTimeMillis();
connection = (HttpURLConnection) new URL(url).openConnection();
connection.setRequestMethod(method);
connection.connect();
int code = connection.getResponseCode();
if (code == 200) {
responseTime = System.currentTimeMillis() - startTime;
requestSuccess = true;
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (connection != null) {
connection.disconnect();
}
}
result.setRequestSuccess(requestSuccess);
result.setResponseTime(responseTime);
return result;
}
}

RequestTaskResult类:

/**
* 请求任务结果
*
*/
public class RequestTaskResult {
private Long responseTime;
private Boolean requestSuccess;
public Long getResponseTime() {
return responseTime;
}
public void setResponseTime(Long responseTime) {
this.responseTime = responseTime;
}
public Boolean getRequestSuccess() {
return requestSuccess;
}
public void setRequestSuccess(Boolean requestSuccess) {
this.requestSuccess = requestSuccess;
}
}

WebPerformanceTesting接口:

/**
* 性能测试
*/
public interface WebPerformanceTesting {
/**
* 并发测试
*
* @param url 请求URL
* @param method 请求方式
* @param concurrencyNum 并发数
* @param requestTotal 请求总次数
*/
public ConcurrencyTestResult concurrencyTest(String url, String method, int concurrencyNum, int requestTotal);
}

WebPerformanceTestingImpl接口:

public class WebPerformanceTestingImpl implements WebPerformanceTesting {
@Override
public ConcurrencyTestResult concurrencyTest(String url, String method, int concurrencyNum, int requestTotal) {
ThreadPoolExecutor executor = new ThreadPoolExecutor(concurrencyNum, concurrencyNum, 0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<>());
List<RequestTask> taskList = new ArrayList<>(requestTotal);
for (int i = 0;i < requestTotal; i++) {
taskList.add(new RequestTask(url, method));
}
long averageResponseTime = 0L;
long ninetyFivePercentageResponseTime = 0L;
long minPercentageResponseTime = 0L;
long maxPercentageResponseTime = 0L;
int requestSucceedNum = 0;
int requestFailedNum = 0;
try {
List<Future<RequestTaskResult>> resultList = executor.invokeAll(taskList);
if (resultList != null && !resultList.isEmpty()) {
List<Long> responseTimeList = new ArrayList<>();
for (Future<RequestTaskResult> future : resultList) {
RequestTaskResult result = future.get();
responseTimeList.add(result.getResponseTime());
if (result.getRequestSuccess()) {
requestSucceedNum++;
}
}
maxPercentageResponseTime = responseTimeList.stream().max(Long::compareTo).get();
minPercentageResponseTime = responseTimeList.stream().min(Long::compareTo).get();
averageResponseTime = responseTimeList.stream().reduce(Long::sum).get() / responseTimeList.size();//平均值
Collections.sort(responseTimeList);
int index = new Double(responseTimeList.size() * 0.95).intValue() - 1;
index = (index >= 0) ? index : 0;
ninetyFivePercentageResponseTime = responseTimeList.get(index);
requestFailedNum = requestTotal - requestSucceedNum;
}
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
ConcurrencyTestResult concurrencyTestResult = new ConcurrencyTestResult(
averageResponseTime,
ninetyFivePercentageResponseTime,
minPercentageResponseTime,
maxPercentageResponseTime,
requestSucceedNum,
requestFailedNum
);
return concurrencyTestResult;
}
public static void main(String[] args) {
WebPerformanceTesting webPerformanceTesting = new WebPerformanceTestingImpl();
String url = "https://www.baidu.com";
String method = "GET";
int concurrencyNum = 10;
int requestTotal = 100;
ConcurrencyTestResult concurrencyTestResult = webPerformanceTesting.concurrencyTest(url, method, concurrencyNum, requestTotal);
System.out.printf("请求URL: %s\n", url);
System.out.printf("请求方法: %s\n", method);
System.out.printf("并发数: %s\n", concurrencyNum);
System.out.printf("请求总数: %s\n", requestTotal);
concurrencyTestResult.print();
}
}



测试结果:

请求URL: https://www.baidu.com
请求方法: GET
并发数: 10
请求总数: 100
平均响应时间: 92(ms)
百分之95响应时间: 453(ms)
最小响应时间: 34(ms)
最大响应时间: 461(ms)
请求成功次数: 100次
请求失败次数: 0次



评论

发布
暂无评论
架构师训练营 -Week 07 命题作业