Web 性能压测工具(训练营第七课)

用户头像
看山是山
关注
发布于: 2020 年 07 月 22 日



作业

用你熟悉的编程语言写一个 web 性能压测工具

输入参数:URL,请求总次数,并发数

输出参数:平均响应时间,95% 响应时间

测试目标:用这个测试工具以 10 并发、100 次请求压测 www.baidu.com。

解题

application.properties

perftest.url=https://www.baidu.com
perftest.total_request=100
perftest.concurrent_count=10
perftest.interval_per_request=100



PerfTestExecutor

采用 OkHttpClient 来发送请求,通过 CountDownLatch 来控制启动和结束

@Slf4j
public class PerfTestExecutor {
private final OkHttpClient okHttpClient;
private final PerfTestConf perfTestConf;
private final Request perfTestRequest;
private final int loopCount;
private final Map<String, List<Long>> requestTimesMap = new ConcurrentHashMap<>();
private final CountDownLatch startSignal;
private final CountDownLatch doneSignal;
public PerfTestExecutor(OkHttpClient okHttpClient, PerfTestConf perfTestConf) {
assert perfTestConf.getConcurrentCount() > 0;
assert perfTestConf.getTotalRequest() >= perfTestConf.getConcurrentCount();
this.okHttpClient = okHttpClient;
this.perfTestConf = perfTestConf;
perfTestRequest = new Request.Builder().url(perfTestConf.getUrl()).build();
loopCount = (int) Math.ceil((double) perfTestConf.getTotalRequest() / perfTestConf.getConcurrentCount());
System.out.println("loopCount: " + loopCount);
this.startSignal = new CountDownLatch(1);
this.doneSignal = new CountDownLatch(perfTestConf.getConcurrentCount());
init();
}
private void init() {
for (int j = 0; j < perfTestConf.getConcurrentCount(); j++) {
final String threadName = "Thread-" + j;
new Thread(() -> {
try {
startSignal.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
long requestTime;
for (int i = 0; i < loopCount; i++) {
long startTimeInMilli = System.currentTimeMillis();
try (Response response = okHttpClient.newCall(perfTestRequest).execute()) {
log.info("Response " + i + " from " + perfTestConf.getUrl());
requestTime = System.currentTimeMillis() - startTimeInMilli;
requestTimesMap.computeIfAbsent(threadName, k -> new ArrayList<>()).add(requestTime);
if (perfTestConf.getIntervalPerRequest() > 0 && requestTime < perfTestConf.getIntervalPerRequest()) {
Thread.sleep(perfTestConf.getIntervalPerRequest() - requestTime);
}
} catch (InterruptedException | IOException e) {
log.warn("Exception", e);
}
}
doneSignal.countDown();
}).start();
}
}
public void start() {
startSignal.countDown();
}
public void await() throws InterruptedException {
doneSignal.await();
}
public List<Long> getRequestTimeList() {
return requestTimesMap.values().stream().flatMap(Collection::stream).sorted().collect(Collectors.toList());
}
}

PerfTestApplication

@SpringBootApplication
public class PerfTestApplication implements ApplicationRunner {
@Autowired
private OkHttpClient okHttpClient;
@Autowired
private PerfTestConf perfTestConf;
public static void main(String[] args) {
SpringApplication.run(PerfTestApplication.class, args);
}
@Override
public void run(ApplicationArguments args) throws Exception {
System.out.println(perfTestConf);
PerfTestExecutor testExecutor = new PerfTestExecutor(okHttpClient, perfTestConf);
testExecutor.start();
testExecutor.await();
generateStatistics(testExecutor.getRequestTimeList());
}
public void generateStatistics(List<Long> longList) {
// longList.forEach(System.out::println);
double average = longList.stream().mapToLong(l -> l).average().getAsDouble();
int p95Count = (int) Math.floor(perfTestConf.getTotalRequest() * 0.95);
long p95 = longList.stream().mapToLong(l -> l).skip(p95Count - 1).findFirst().getAsLong();
System.out.println("Average: " + average);
System.out.println("95%: " + p95);
}
}

Result

Average: 35.41
95%: 206
// 下面是所有的 100 个请求时间
10
11
11
11
11
11
11
11
11
11
11
11
12
12
12
12
12
12
12
12
12
12
12
12
12
12
13
13
13
13
13
13
13
13
13
13
13
13
13
13
13
13
13
13
13
13
14
14
14
14
14
14
14
14
14
14
14
14
14
15
15
15
15
15
15
15
15
15
16
17
17
17
17
17
17
17
18
18
18
18
18
18
18
22
36
42
56
57
62
69
206
206
206
206
206
206
206
206
206
206




用户头像

看山是山

关注

还未添加个人签名 2018.11.16 加入

还未添加个人简介

评论

发布
暂无评论
Web 性能压测工具(训练营第七课)