架构师训练营 性能压测命题作业

发布于: 2020 年 07 月 18 日
  • 性能压测的时候,随着并发量的增加,系统响应时间和吞吐量如何变化?为什么?

系统都会有一个瓶颈,也就是系统能支持的最大并发数量,当并发逐渐增大的时候,响应时间通常是会随着并发不断的增加而缓慢降低的,而一旦并发超过系统的最大承受能力,系统的响应时间就会急剧下降。

  • 系统响应时间在并发上升初期会缓慢上升,而达到临界点后会急剧上升

举个例子,一个系统同时只能支撑100的并发,超过100并发后,后面过来的请求就只能阻塞等待,而一个请求执行耗时是x,那么超过100并发后,后面来的100请求耗时就是等待的时间加自己执行的时间,就是2x,假如后面来了1000个请求呢?那请求的耗时就会最大要到11x,已经慢了10倍。

而如果后面来的请求如果不是阻塞等待,而是一起竞争cpu资源的话,cpu假设x时间最多处理100个请求,这时候分在每个请求上的cpu时间是x/100,那这时候如果有200个请求过来的话,x时间,每个请求只能分到x/200,而每个请求至少要x/100的时间才能完成,那就需要2x的时间才能完成着200个请求,而如果来了1000个请求,那就需要10x的时间才能完成。

而且线程上下文切换还会有性能损耗,如果访问的数据库,数据库连接的资源也有限,需要排队等待,等等,所以,并发升高后应用的耗时是会逐渐上升的,只是在没达到系统瓶颈前,耗时上升应该比较缓慢,而上升到一个瓶颈,耗时就会急剧上升。

  • 吞吐量在早期会随着并发升高很快上升,而随着系统响应时间在临界点的急剧上升,吞吐量会开始急剧下降

吞吐量的计算公式是:吞吐量=并发数/平均响应时间

初期因为并发数不断上升,但是平均响应时间上升并不明显,所以吞吐量会不断升高。

而响应时间在达到临界点后急剧上升,吞吐量也就随着继续降低。

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

public class Press {
private String url;
private int concurrent;
private int count;
private ExecutorService executorService;
private Statistics statistics;
public Press(String url, int concurrent, int count) {
this.url = url;
this.concurrent = concurrent;
this.count = count;
this.statistics = new Statistics();
this.executorService = new ThreadPoolExecutor(concurrent, concurrent, 400, TimeUnit.SECONDS,
new LinkedBlockingDeque<>(concurrent));
}
public Statistics execute() throws InterruptedException {
CountDownLatch latch = new CountDownLatch(10);
for (int i = 0; i < concurrent; i++) {
this.executorService.execute(() -> {
try {
new Request(url, statistics).request(count);
} finally {
latch.countDown();
}
});
}
latch.await();
return statistics;
}
public static void main(String[] args) throws InterruptedException {
String url = "http://www.baidu.com";
int concurrent = 10;
int count = 300;
Statistics statistics = new Press(url, concurrent, count).execute();
System.out.println("平均执行耗时:" + statistics.avgCost());
System.out.println("95%耗时在:" + statistics.cost95());
}
}

public class Request {
private String url;
private Statistics statistics;
private RestTemplate restTemplate;
public Request(String url, Statistics statistics) {
this.url = url;
this.statistics = statistics;
this.restTemplate = new RestTemplate();
}
public void request(int count) {
for (int i = 0; i < count; i++) {
long start = System.currentTimeMillis();
restTemplate.exchange(url, HttpMethod.GET, null, String.class);
long end = System.currentTimeMillis();
statistics.add(end - start);
}
}
public static void main(String[] args) {
RestTemplate restTemplate = new RestTemplate();
String url = "http://www.baidu.com";
ResponseEntity<String> str = restTemplate.exchange(url, HttpMethod.GET, null, String.class);
System.out.println(str.getBody());
}
}

public class Statistics {
private AtomicInteger count;
private List<Long> requestCost;
public Statistics() {
this.count = new AtomicInteger(0);
this.requestCost = new CopyOnWriteArrayList<>();
}
public void add(long cost) {
count.incrementAndGet();
requestCost.add(cost);
}
public BigDecimal avgCost() {
long total = requestCost.stream().mapToLong(o -> o).sum();
return BigDecimal.valueOf(total).divide(BigDecimal.valueOf(count.get()), 2, BigDecimal.ROUND_UP);
}
public long cost95() {
Collections.sort(requestCost);
int index = (int)(count.get() * 0.95);
int offset = count.get() - index;
return requestCost.get(offset);
}
}

最后输出:

平均执行耗时:39.73
95%耗时在:30

发布于: 2020 年 07 月 18 日 阅读数: 10
用户头像

Cloud.

关注

还未添加个人签名 2020.05.14 加入

还未添加个人简介

评论

发布
暂无评论
架构师训练营 性能压测命题作业