写点什么

极客时间架构 1 期:第 7 周 性能优化(一) - 命题作业

用户头像
Null
关注
发布于: 2020 年 11 月 08 日

作业一

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

对于吞吐量

  1. 当并发数上升的时,吞吐量会达到线性增加,到达系统最佳运行点

  2. 当并发数继续上升时,吞吐量上升趋势慢慢变缓,到达系统最大负载点

  3. 当并发继续上升时,吞吐量下降趋势慢慢增大,达到系统崩溃点

对于响应时间

  1. 当并发数上升的时,响应时间保持稳定不变,到达系统最佳运行点

  2. 当并发数继续上升时,响应时间会缓慢上升,到达系统最大负载点

  3. 当并发继续上升时,响应时间会快速上升,达到系统崩溃点


作业二

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


/**     * 带有连接池     * @param url     * @param reqSize     * @param currentSize     * @return     */    public PerformanceTestResponse testWithPool(String url, int reqSize, int currentSize) {        // 配置连接池        PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(600, TimeUnit.SECONDS);        cm.setValidateAfterInactivity(2_000);        cm.setDefaultMaxPerRoute(100);        cm.setMaxTotal(10);        CloseableHttpClient httpClient = HttpClients.custom().setConnectionManager(cm).build();        Executor executor = Executor.newInstance(httpClient);        return this.innerTest(reqSize, currentSize, () -> executor.execute(Request.Get(url)                .connectTimeout(1000)                .socketTimeout(1000))                .returnResponse().getStatusLine().getStatusCode());    }
/** * 默认不带有连接池 * @param url * @param reqSize * @param currentSize * @return */ public PerformanceTestResponse test(String url, int reqSize, int currentSize) { return this.innerTest(reqSize, currentSize, () -> Request.Get(url) .connectTimeout(1000) .socketTimeout(1000).execute() .returnResponse().getStatusLine().getStatusCode()); }
private PerformanceTestResponse innerTest(int reqSize, int currentSize, HttpHandler handler) { // 利用线程池 ExecutorService threadPool = Executors.newFixedThreadPool(currentSize); List<Future<Long>> results = new ArrayList<>(reqSize); for (int i = 0; i < reqSize; i++) { Future<Long> future = threadPool.submit(new ResponseTimeRunnable(handler)); results.add(future); } // 获取响应时间,并排序 List<Long> responseTimes = results.stream().map(x -> { try { return x.get(); } catch (InterruptedException | ExecutionException e) { e.printStackTrace(); } return 0L; }).sorted(Long::compareTo).collect(Collectors.toList());
PerformanceTestResponse testResponse = new PerformanceTestResponse(); // 计算平均响应时间 responseTimes.stream().mapToDouble(Double::valueOf).average().ifPresent(x -> { testResponse.setAverageTime(BigDecimal.valueOf(x).setScale(2, BigDecimal.ROUND_HALF_UP)); }); // 获取 95% 响应时间 testResponse.setP95Time(responseTimes.get((responseTimes.size()/100) * 95 - 1)); threadPool.shutdown(); return testResponse; }
private static class ResponseTimeRunnable implements Callable<Long> {
private final HttpHandler handler;
public ResponseTimeRunnable(HttpHandler handler) { this.handler = handler; }
@Override public Long call() { long startTime = System.currentTimeMillis(); try { if (handler.get() == 200) { return System.currentTimeMillis() - startTime; } } catch (IOException e) { e.printStackTrace(); } return 0L; } }
private interface HttpHandler { /** * http get 方法 * * @return 状态码 * @throws IOException */ int get() throws IOException; }
private static class PerformanceTestResponse { private BigDecimal averageTime; private Long p95Time;
public BigDecimal getAverageTime() { return averageTime; }
public void setAverageTime(BigDecimal averageTime) { this.averageTime = averageTime; }
public Long getP95Time() { return p95Time; }
public void setP95Time(Long p95Time) { this.p95Time = p95Time; } }
public static void main(String[] args) { PerformanceTest test = new PerformanceTest();// PerformanceTestResponse testResponse = test.test("https://www.baidu.com", 100, 10);// System.out.println(String.format("不使用连接池时,平均响应时间为 %.2f ms", testResponse.getAverageTime().doubleValue()));// System.out.println(String.format("不使用连接池时,95%% 响应时间为 %d ms", testResponse.getP95Time().intValue())); PerformanceTestResponse testResponse = test.testWithPool("https://www.baidu.com", 100, 10); System.out.println(String.format("使用连接池时,平均响应时间为 %.2f ms", testResponse.getAverageTime().doubleValue())); System.out.println(String.format("使用连接池时,95%% 响应时间为 %d ms", testResponse.getP95Time().intValue())); }
复制代码

带有连接池的版本,代码运行结果如下:

使用连接池时,平均响应时间为 37.55 ms使用连接池时,95% 响应时间为 303 ms
复制代码


不带有连接池的版本,运行结果如下:

不使用连接池时,平均响应时间为 80.42 ms不使用连接池时,95% 响应时间为 728 ms
复制代码

注意:两者不能同时运行,必须一个一个单独运行,因为存在缓存,会相互影响


用户头像

Null

关注

还未添加个人签名 2017.12.29 加入

还未添加个人简介

评论

发布
暂无评论
极客时间架构 1 期:第 7 周 性能优化(一) - 命题作业