极客时间架构 1 期:第 7 周 性能优化(一) - 命题作业
发布于: 2020 年 11 月 08 日
作业一
性能压测的时候,随着并发压力的增加,系统响应时间和吞吐量如何变化,为什么?
对于吞吐量
当并发数上升的时,吞吐量会达到线性增加,到达系统最佳运行点
当并发数继续上升时,吞吐量上升趋势慢慢变缓,到达系统最大负载点
当并发继续上升时,吞吐量下降趋势慢慢增大,达到系统崩溃点
对于响应时间
当并发数上升的时,响应时间保持稳定不变,到达系统最佳运行点
当并发数继续上升时,响应时间会缓慢上升,到达系统最大负载点
当并发继续上升时,响应时间会快速上升,达到系统崩溃点
作业二
用你熟悉的编程语言写一个 web 性能压测工具,输入参数:URL,请求总次数,并发数。输出参数:平均响应时间,95% 响应时间。用这个测试工具以 10 并发、100 次请求压测 www.baidu.com
/**
* 带有连接池
* @param url
* @param reqSize
* @param currentSize
* @return
*/
public PerformanceTestResponse testWithPool(String url, int reqSize, int currentSize) {
// 配置连接池
PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(600, TimeUnit.SECONDS);
cm.setValidateAfterInactivity(2_000);
cm.setDefaultMaxPerRoute(100);
cm.setMaxTotal(10);
CloseableHttpClient httpClient = HttpClients.custom().setConnectionManager(cm).build();
Executor executor = Executor.newInstance(httpClient);
return this.innerTest(reqSize, currentSize, () -> executor.execute(Request.Get(url)
.connectTimeout(1000)
.socketTimeout(1000))
.returnResponse().getStatusLine().getStatusCode());
}
/**
* 默认不带有连接池
* @param url
* @param reqSize
* @param currentSize
* @return
*/
public PerformanceTestResponse test(String url, int reqSize, int currentSize) {
return this.innerTest(reqSize, currentSize, () -> Request.Get(url)
.connectTimeout(1000)
.socketTimeout(1000).execute()
.returnResponse().getStatusLine().getStatusCode());
}
private PerformanceTestResponse innerTest(int reqSize, int currentSize, HttpHandler handler) {
// 利用线程池
ExecutorService threadPool = Executors.newFixedThreadPool(currentSize);
List<Future<Long>> results = new ArrayList<>(reqSize);
for (int i = 0; i < reqSize; i++) {
Future<Long> future = threadPool.submit(new ResponseTimeRunnable(handler));
results.add(future);
}
// 获取响应时间,并排序
List<Long> responseTimes = results.stream().map(x -> {
try {
return x.get();
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
return 0L;
}).sorted(Long::compareTo).collect(Collectors.toList());
PerformanceTestResponse testResponse = new PerformanceTestResponse();
// 计算平均响应时间
responseTimes.stream().mapToDouble(Double::valueOf).average().ifPresent(x -> {
testResponse.setAverageTime(BigDecimal.valueOf(x).setScale(2, BigDecimal.ROUND_HALF_UP));
});
// 获取 95% 响应时间
testResponse.setP95Time(responseTimes.get((responseTimes.size()/100) * 95 - 1));
threadPool.shutdown();
return testResponse;
}
private static class ResponseTimeRunnable implements Callable<Long> {
private final HttpHandler handler;
public ResponseTimeRunnable(HttpHandler handler) {
this.handler = handler;
}
@Override
public Long call() {
long startTime = System.currentTimeMillis();
try {
if (handler.get() == 200) {
return System.currentTimeMillis() - startTime;
}
} catch (IOException e) {
e.printStackTrace();
}
return 0L;
}
}
private interface HttpHandler {
/**
* http get 方法
*
* @return 状态码
* @throws IOException
*/
int get() throws IOException;
}
private static class PerformanceTestResponse {
private BigDecimal averageTime;
private Long p95Time;
public BigDecimal getAverageTime() {
return averageTime;
}
public void setAverageTime(BigDecimal averageTime) {
this.averageTime = averageTime;
}
public Long getP95Time() {
return p95Time;
}
public void setP95Time(Long p95Time) {
this.p95Time = p95Time;
}
}
public static void main(String[] args) {
PerformanceTest test = new PerformanceTest();
// PerformanceTestResponse testResponse = test.test("https://www.baidu.com", 100, 10);
// System.out.println(String.format("不使用连接池时,平均响应时间为 %.2f ms", testResponse.getAverageTime().doubleValue()));
// System.out.println(String.format("不使用连接池时,95%% 响应时间为 %d ms", testResponse.getP95Time().intValue()));
PerformanceTestResponse testResponse = test.testWithPool("https://www.baidu.com", 100, 10);
System.out.println(String.format("使用连接池时,平均响应时间为 %.2f ms", testResponse.getAverageTime().doubleValue()));
System.out.println(String.format("使用连接池时,95%% 响应时间为 %d ms", testResponse.getP95Time().intValue()));
}
复制代码
带有连接池的版本,代码运行结果如下:
使用连接池时,平均响应时间为 37.55 ms
使用连接池时,95% 响应时间为 303 ms
复制代码
不带有连接池的版本,运行结果如下:
不使用连接池时,平均响应时间为 80.42 ms
不使用连接池时,95% 响应时间为 728 ms
复制代码
注意:两者不能同时运行,必须一个一个单独运行,因为存在缓存,会相互影响
划线
评论
复制
发布于: 2020 年 11 月 08 日阅读数: 36
Null
关注
还未添加个人签名 2017.12.29 加入
还未添加个人简介
评论