写点什么

架构师训练营 - 命题作业 第 7 周

用户头像
叶鹏
关注
发布于: 2020 年 07 月 22 日
  • 用你熟悉的编程语言写一个 web 性能压测工具,输入参数:URL,请求总次数,并发数。输出参数:平均响应时间,95% 响应时间。用这个测试工具以 10 并发、100 次请求压测 www.baidu.com。



1、先定义输入类:



package cn.yepeng.dto;
import lombok.Data;
@Data
public class TestInputDto {
/**
* 测试地址
*/
private String url;
/**
* 总请求数
*/
private long requestTime;
/**
* 总并发数
*/
private long concurrencyNum;
/**
* 每个线程要请求的次数.
* 不考虑除不断的情况
* @return 次数
*/
public long getTimePerThread() {
return requestTime / concurrencyNum;
}
@Override
public String toString() {
return String.format("压测地址: %s 压测次数: %s 并发数: %s", url, requestTime, concurrencyNum);
}
}

2、定义输出类:

package cn.yepeng.dto;
import lombok.Data;
import lombok.Synchronized;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;
@Data
public class TestOutputDto {
/**
* 收集所有的请求时长
*/
private SortedMap<Long, Long> map = new TreeMap<>();
@Synchronized
public void putTime(long time) {
map.put(time, 0L);
}
@Override
public String toString() {
long totalTime = 0; // 总的请求时长
long time95 = 0; // 95分位请求时长
long begin95 = map.size() * 95 / 100; // 95分位请求所在的索引位置
long idx = 0;
for (Map.Entry<Long, Long> item : map.entrySet()) {
if (idx == begin95)
time95 = item.getKey();
totalTime += item.getKey();
idx++;
}
long avg = totalTime / map.size();
return String.format("压测结果:平均响应时间: %s纳秒 95分位响应时间: %s纳秒", avg, time95);
}
}

3、定义压测类:

package cn.yepeng;
import cn.yepeng.dto.TestInputDto;
import cn.yepeng.dto.TestOutputDto;
import cn.yepeng.utils.HttpHelper;
import lombok.Synchronized;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ForTestService implements Runnable {
private TestInputDto inputDto;
private int threadNum;
TestOutputDto ret = new TestOutputDto();
public ForTestService(TestInputDto inputDto) {
this.inputDto = inputDto;
}
public TestOutputDto startTest() throws InterruptedException {
// 抛弃第一次请求,避免DNS解析等损耗
sendRequest();
ExecutorService pool = Executors.newCachedThreadPool();
// 并行启动ConsurrencyNum个线程
for (int i = 0; i < inputDto.getConcurrencyNum(); i++) {
pool.execute(this);
}
// 等待任务完成
do {
Thread.sleep(10000);
System.out.println(threadNum);
} while (threadNum > 0);
pool.shutdown();
return ret;
}
@Override
public void run() {
long perTime = inputDto.getTimePerThread();
addThread();
try {
// 每个线程顺序执行请求
for (int requestIdx = 0; requestIdx < perTime; requestIdx++) {
long costTime = sendRequest();
ret.putTime(costTime);
}
} catch (Exception exp) {
System.out.println("有线程出错了:" + exp.getMessage());
} finally {
decThread();
}
}
@Synchronized
private void addThread() {
threadNum++;
}
@Synchronized
private void decThread() {
threadNum--;
}
/**
* 发请求
* @return 返回请求耗时,纳秒
*/
private long sendRequest() {
long beginTime = System.nanoTime();
HttpHelper.GetPage(inputDto.getUrl(), "");
return System.nanoTime() - beginTime;
}
}

5、最终输出结果:

请输入测试地址,默认值 https://www.baidu.com/:
请输入总请求次数,默认值 100:
请输入并发数,默认值 10:
压测地址: https://www.baidu.com/ 压测次数: 100 并发数: 10 开始测试
0
测试完成: 压测结果:平均响应时间: 36782823纳秒 95分位响应时间: 119898912纳秒



用户头像

叶鹏

关注

还未添加个人签名 2018.09.25 加入

还未添加个人简介

评论 (1 条评论)

发布
用户头像
请加“极客大学架构师训练营”标签,便于分类
2020 年 07 月 22 日 18:17
回复
没有更多了
架构师训练营 - 命题作业 第 7 周