写点什么

架构师训练营 Week7 - 课后作业

用户头像
关注
发布于: 2020 年 11 月 08 日
架构师训练营 Week7 - 课后作业

并发数,响应时间,吞吐量

性能压测的时候,随着并发压力的增加,系统响应时间和吞吐量如何变化,为什么?

1,概念:

  • 响应时间:系统从收到请求到响应发出所占用的时间

  • 并发数:系统能同时处理的请求数量

  • 并发请求数

  • 在线用户数

  • 系统用户数

  • 吞吐量:单位时间内系统处理的请求数量。

  • QPS: 每秒查询数量

  • TPS: 每秒交易数量

  • HPS:每秒 HTTP 数量

2,关系:

整个系统从单机(垂直伸缩), 集群(水平伸缩)方面资源是有限的。同时站在成本收益比的角度,资源分配和最大可处理的请求达到一个比较好的平衡(理想情况下)。 借用课上的几张图:

  • 并发数 VS 吞吐量:

  • 初始阶段线性增加(a->b),系统资源充足。 随着并发数的增加吞吐量增加,系统资源逐步被占满。(a->b)

  • 吞吐量增加变慢:请求数量增加,系统需要分配一部分资源处理调度,等待资源释放。吞吐量增加速度减慢。

  • 临界点(c),当并发数达到某个数量级时,系统资源(CPU,数据库连接,JVM 堆内存/GC...)被充分占用,不能同时响应新的请求。此时就会出现请求等待排队。

  • 超过临界点(c->d), 当有更多的请求堆积等待,系统需要额外分出一部分资源去处理额外的等待请求。对于单机处理会出现频繁的线程切换,Full GC.这些处理都会有消耗,导致吞吐量下降。

  • 出错/崩溃:当请求数量大大超出系统处理能力,就会出现请求超时。系统内部资源处理不当会导致 OOM (GC 失败)或者系统 down 机。



  • 并发数 VS 响应时间 yu

与吞吐量对应。

初始状态:并发请求都可以分配到足够的系统资源处理,响应时间基本一致

响应时间增加:随着资源被占用,更多的请求不能立马被处理,平均响应市场增加。

临界点:当达到某个临界点,系统为处理额外的消耗占用的资源时间增加。单个请求等待的时常幅度增大

出错/崩溃:达到某个请求数量系统开始崩溃,响应时间达到最大值。系统超时,宕机。


Web 性能压测工具 - LoadRunner


1. 执行

  1. 执行 www.baidu.com 并发 10, 总数 100

> java -jar .\HttpLoadRunner-1.0-SNAPSHOT.jar http://www.baidu.com c10 t100
Testing Url: http://www.baidu.comConcurrent: 10, Total Num: 100================= Load Runner Result / Million Seconds ==================Executed Num: 100, Failure Num: 0Avg Time: 63.21, 95% Avg Time: 52.53, 95% Index: 95Total Duration: 6401, Sum of TimeSpent:6321
复制代码


  1. 执行 www.baidu.com 并发 100, 总数 100

> java -jar .\HttpLoadRunner-1.0-SNAPSHOT.jar http://www.baidu.com c100 t100
Testing Url: http://www.baidu.comConcurrent: 100, Total Num: 100================= Load Runner Result / Million Seconds ==================Executed Num: 100, Failure Num: 0Avg Time: 58.74, 95% Avg Time: 48.38, 95% Index: 95Total Duration: 5994, Sum of TimeSpent:5874
复制代码


  1. 执行 www.baidu.com 并发 100, 总数 1000

> java -jar .\HttpLoadRunner-1.0-SNAPSHOT.jar http://www.baidu.com c100 t1000
Testing Url: http://www.baidu.comConcurrent: 100, Total Num: 1000================= Load Runner Result / Million Seconds ==================Executed Num: 1000, Failure Num: 0Avg Time: 48.64, 95% Avg Time: 45.74, 95% Index: 950Total Duration: 49015, Sum of TimeSpent:48644
复制代码


2. 源代码

package io.http;
import org.apache.http.HttpEntity;import org.apache.http.HttpStatus;import org.apache.http.client.methods.CloseableHttpResponse;import org.apache.http.client.methods.HttpGet;import org.apache.http.impl.client.CloseableHttpClient;import org.apache.http.impl.client.HttpClients;
import java.util.Arrays;import java.util.concurrent.*;
public class LoadRunner { private static int concurrentNum = 10; private static int totalNum = 100; private static String url = "http://www.baidu.com"; public static void main(String[] args) throws Exception{ //init member variable; init(args);
System.out.printf("Testing Url: %s\n", url); System.out.printf("Concurrent: %3d, Total Num: % d\n", concurrentNum, totalNum);
long startTime = System.currentTimeMillis(); int failureNum = 0; long totalTime = 0; long sumOfTimeSpent = 0; double totalAvg = 0; double percAvg = 0; long[] durations = new long[totalNum]; ExecutorService executor = Executors.newFixedThreadPool(concurrentNum);
try{ for (int i = 0; i < totalNum; i++){ FutureTask<Long> requestTask = getLongFutureTask(i); executor.submit(requestTask); Long timeSpent = requestTask.get(30, TimeUnit.SECONDS); if (timeSpent != -1) { durations[i] = timeSpent; sumOfTimeSpent += timeSpent; } else { durations[i] = Long.MAX_VALUE; failureNum++; } } Arrays.sort(durations); totalAvg = Arrays.stream(durations).average().orElse(Double.NaN); int percIndex = Math.round((totalNum-failureNum) * 95/100); percAvg = Arrays.stream( Arrays.copyOfRange(durations, 0, percIndex)).average().orElse(Double.NaN); totalTime = System.currentTimeMillis() - startTime; System.out.println("================= Load Runner Result / Million Seconds =================="); System.out.printf("Executed Num: %d, Failure Num: %d\n", totalNum, failureNum); System.out.printf("Avg Time: %.2f, 95%% Avg Time: %.2f, 95%% Index: %d\n", totalAvg, percAvg, percIndex);
System.out.printf("Total Duration: %d, Sum of TimeSpent:%d\n", totalTime, sumOfTimeSpent); } finally { executor.shutdown(); } }
private static FutureTask<Long> getLongFutureTask(int i) { FutureTask<Long> requestTask = new FutureTask<Long>(new Callable<Long>() { public Long call() throws Exception { Long start = System.currentTimeMillis(); Long duration = -1L;
//HTTP client call CloseableHttpClient httpclient = HttpClients.createDefault(); HttpGet httpGet = new HttpGet(url); CloseableHttpResponse response = httpclient.execute(httpGet); try { HttpEntity responseEntity = response.getEntity(); if(HttpStatus.SC_OK == response.getStatusLine().getStatusCode()) { duration = System.currentTimeMillis() - start; } else { // other case consider as failed. duration = -1L; }// System.out.printf("Thread: %s, Duration: %s\n", Thread.currentThread().getName(), duration); } finally { response.close(); } return duration; } }) ; return requestTask; }
static void init(String[] args) { if(args == null) return;
for (String arg : args) { if (arg == null || arg.length() <= 1) continue;
//input url if (arg.startsWith("http://")) { url = arg; continue; }
String paramName = arg.substring(0,1); String paramValue = arg.substring(1); //input concurrent number if (paramName.equalsIgnoreCase("c") && paramValue.matches("[0-9]+")){ concurrentNum = Integer.parseInt(arg.substring(1)); continue; } //input duration seconds if (paramName.equalsIgnoreCase("t") && paramValue.matches("[0-9]+")){ totalNum = Integer.parseInt(arg.substring(1)); continue; } } }}
复制代码


发布于: 2020 年 11 月 08 日阅读数: 32
用户头像

关注

还未添加个人签名 2018.09.18 加入

还未添加个人简介

评论

发布
暂无评论
架构师训练营 Week7 - 课后作业