写点什么

性能测试

用户头像
考尔菲德
关注
发布于: 2020 年 07 月 22 日

一、作业内容

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



二、代码实现

1、首先定义单次请求的TestTask

/**
* 测试请求task
*/
static class TestTask implements Callable<Long> {
private CyclicBarrier barrier;
private String url;
public TestTask(String url, CyclicBarrier barrier) {
this.url = url;
this.barrier = barrier;
}
@Override
public Long call() {
Long duration;
try {
HttpClient httpClient = createClient();
HttpGet httpGet = new HttpGet(url);
barrier.await(5, TimeUnit.SECONDS);
Long start = System.currentTimeMillis();
httpClient.execute(httpGet);
Long end = System.currentTimeMillis();
duration = end - start;
} catch (Exception e) {
System.out.println("test_task error," + e.toString());
duration = -1L;
}
return duration;
}
}



2、并发执行请求的测试代码如下:

public static Map<String, Long> concurrencyTest(int count, String url) {
// 初始化CyclicBarrier,通过barrier去保证各线程同时对url发起请求
CyclicBarrier barrier = new CyclicBarrier(count, () -> System.out.println("request current start"));
//用于存储数据计算统计的结果
Map<String, Long> statistics = new HashMap<>();
statistics.put("total", Long.valueOf(count));
List<FutureTask<Long>> futureList = new ArrayList<>();
try {
for (int i = 0; i < count; i++) {
// 基于TestTask够条件FutureTask,并创建线程进行执行
FutureTask<Long> futureTask = new FutureTask<>(new TestTask(url, barrier));
new Thread(futureTask).start();
futureList.add(futureTask);
}
} catch (Exception e) {
System.out.println("concurrency test error," + e.toString());
}
if (CollectionUtils.isNotEmpty(futureList)) {
List<Long> durations = new ArrayList<>();
for (int i = 0; i < count; i++) {
try {
Long duration = futureList.get(i).get();
if (duration > 0L) {
durations.add(duration);
}
} catch (Exception e) {
System.out.printf("future error,", e.toString());
}
}
Collections.sort(durations);
int index = (int) Math.floor(durations.size() * 0.95);
Long per95 = durations.get(index - 1);
Long avg = durations.stream().collect(Collectors.averagingLong(x -> x)).longValue();
statistics.put("success", Long.valueOf(durations.size()));
statistics.put("per95", per95);
statistics.put("avg", avg);
}
return statistics;
}

3、封装HttpClient的构建代码

// 构建 HttpClient
private static HttpClient createClient() throws KeyStoreException, NoSuchAlgorithmException, KeyManagementException {
RegistryBuilder<ConnectionSocketFactory> registryBuilder = RegistryBuilder.create();
ConnectionSocketFactory plainConnectionSocketFactory = new PlainConnectionSocketFactory();
registryBuilder.register("http", plainConnectionSocketFactory);
KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
//信任任何链接
SSLContext sslContext = SSLContexts.custom().useTLS().loadTrustMaterial(trustStore, (x509Certificates, s) -> true).build();
LayeredConnectionSocketFactory sslSF = new SSLConnectionSocketFactory(sslContext, SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
registryBuilder.register("https", sslSF);
Registry<ConnectionSocketFactory> registry = registryBuilder.build();
PoolingHttpClientConnectionManager clientConnectionManager = new PoolingHttpClientConnectionManager(registry);
clientConnectionManager.setMaxTotal(2);
clientConnectionManager.setDefaultMaxPerRoute(20);
return HttpClientBuilder.create().setConnectionManager(clientConnectionManager).build();
}



4、客户端调动代码如下:

public static void main(String[] args) {
String requestUrl = "https://www.taobao.com/";
int count1 = 10;
int count2 = 100;
Map<String, Long> result1 = RequestTest.concurrencyTest(count1, requestUrl);
Map<String, Long> result2 = RequestTest.concurrencyTest(count2, requestUrl);
showData(result1);
showData(result2);
}
public static void showData(Map<String, Long> statistics) {
StringBuilder builder = new StringBuilder();
builder.append("并发请求总数:");
builder.append(statistics.get("total"));
builder.append("\n");
builder.append("成功的请求数:");
builder.append(statistics.get("success"));
builder.append("\n");
builder.append("95百分位耗时:");
builder.append(statistics.get("per95"));
builder.append("ms");
builder.append("\n");
builder.append("平均请求耗时:");
builder.append(statistics.get("avg"));
builder.append("ms");
builder.append("\n");
System.out.println(builder.toString());
}



5、最终的执行代码如下:

并发请求总数:10
成功的请求数:10
95百分位耗时:430ms
平均请求耗时:394ms
并发请求总数:100
成功的请求数:100
95百分位耗时:4347ms
平均请求耗时:2141ms



用户头像

考尔菲德

关注

还未添加个人签名 2018.04.19 加入

还未添加个人简介

评论 (1 条评论)

发布
用户头像
100次并发和10次并发似乎不应该有这么大差别
2020 年 07 月 25 日 17:20
回复
没有更多了
性能测试