作业一
性能压测的时候,随着并发压力的增加,系统响应时间和吞吐量如何变化,为什么?
答:
随着并发压力的增加,系统的响应时间应该是越来越高。而对应的吞吐量应该在增加到一个临界点后随着并发压力的增加,吞吐量会越来越小。
下图横轴是并发数,纵轴是系统吞吐量,可以看到当并发数在[0,a]性能测试区间时,系统的吞吐量是 0。在[a-b]区间随着并发数的增加,系统吞吐量也随之增加,这一段接近于线性增长。在[b-c]负载测试区间继续增加并发数,系统吞吐量也在增加,但是增长很慢。到了 c 点,便是系统最大吞吐量。在[c-d]压力测试区间继续增加并发数,会使系统吞吐量骤减,这是因为并发请求越多,消耗的系统资源也就越多,线程不断争夺资源,而此时的并发请求数已经达到系统的极限,系统处理不了这么多的请求,响应时间变得越来越长,对应的系统吞吐量也就越来越小了。直到到达 d 点后,系统进入崩溃状态。
作业二
用你熟悉的编程语言写一个 web 性能压测工具,输入参数:URL,请求总次数,并发数。输出参数:平均响应时间,95%响应时间。用这个测试工具以 10 并发、100 次请求压测www.baidu.com
答:
输入参数:请求地址、请求总次数、并发数
static String url = "https://www.baidu.com";static int count = 100; // 请求总次数static int batchSize = 10; // 并发数
复制代码
开始测试,循环 100 次,每次并发 10 个线程请求,同时记录每次总响应时间。
int index = 0; // 请求次数long[] responseTimeArr = new long[count]; // 响应时间数组while(index < count) { // 循环100次 // 使用线程池,固定10个线程 ExecutorService executorService = Executors.newFixedThreadPool(batchSize); long t1 = System.currentTimeMillis(); // 开始时间 for(int i = 0; i < batchSize; i++) { executorService.submit(new Runnable() { @Override public void run() { getRequest(url); // 请求url } }); } executorService.shutdown(); while(!executorService.isTerminated()) { // 等待线程池关闭 } long t2 = System.currentTimeMillis(); // 结束时间 System.out.println(String.format("第%s批总耗时:%sms", index, (t2-t1))); responseTimeArr[index++] = t2 - t1;}
复制代码
HTTP 使用 GET 方法进行请求
public static String getRequest(String requestUrl){ HttpURLConnection connection = null; InputStream is = null; BufferedReader br = null; String result = null;// 返回结果字符串 try { // 创建远程url连接对象 URL url = new URL(requestUrl); // 通过远程url连接对象打开一个连接,强转成httpURLConnection类 connection = (HttpURLConnection) url.openConnection(); // 设置连接方式:get connection.setRequestMethod("GET"); // 设置连接主机服务器的超时时间:15000毫秒 connection.setConnectTimeout(15000); // 设置读取远程返回的数据时间:60000毫秒 connection.setReadTimeout(60000); // 发送请求 connection.connect(); // 通过connection连接,获取输入流 if (connection.getResponseCode() == 200) { is = connection.getInputStream(); // 封装输入流is,并指定字符集 br = new BufferedReader(new InputStreamReader(is, "UTF-8")); // 存放数据 StringBuffer sbf = new StringBuffer(); String temp = null; while ((temp = br.readLine()) != null) { sbf.append(temp); sbf.append("\r\n"); } result = sbf.toString(); } } catch (Exception e) { e.printStackTrace(); } finally { // 关闭资源 if (null != br) { try { br.close(); } catch (IOException e) { e.printStackTrace(); } }
if (null != is) { try { is.close(); } catch (IOException e) { e.printStackTrace(); } }
connection.disconnect();// 关闭远程连接 } return result;}
复制代码
计算响应时间和 95%响应时间
// 计算平均耗时long[] resTop6 = new long[6]; // 倒序存储最大的6个响应时间long sum = 0;for(int i = 0; i < responseTimeArr.length; i++) { long cur = responseTimeArr[i]; for(int j = 0; j < resTop6.length; j++) { if(resTop6[j] < cur) { for(int k = resTop6.length - 1; k > j; k--) { resTop6[k] = resTop6[k-1]; } resTop6[j] = cur; break; } } sum += cur;}long avg = sum / responseTimeArr.length; // 计算平均响应时间long res95 = resTop6[resTop6.length - 1]; // 95%响应时间for(int i = 0; i < resTop6.length; i++) { System.out.print(resTop6[i] + ", ");}System.out.println();System.out.println(String.format("平均响应时间:%sms,95响应时间:%sms", avg, res95));
复制代码
测试结果
1072, 164, 151, 107, 54, 52, // 响应时间最大的前6个平均响应时间:40ms,95响应时间:52ms
复制代码
评论