架构师课作业 - 第七周
发布于: 2020 年 07 月 22 日
作业:
- 性能压测的时候,随着并发压力的增加,系统响应时间和吞吐量如何变化,为什么? 
答:
- 随着并发压力从0开始增加, 分为三个阶段, 性能测试阶段、负载测试阶段、压力测试阶段 
- 性能测试阶段: 每项系统资源都充裕, 系统响应时间基本保持不变, 而吞吐量则线性上升 
- 负载测试阶段: 系统资源仍然有余, 可能由于并发导致的线程上下文切换影响了系统开销, 系统响应时间会略微上升, 而吞吐量基本也呈线性上升 
- 压力测试阶段: 此时系统资源的某一项或多项到达瓶颈, 系统响应时间会极速上升, 吞吐量也会极速下降, 直到系统崩溃 
作业:
- 用你熟悉的编程语言写一个 web 性能压测工具,输入参数:URL,请求总次数,并发数。输出参数:平均响应时间,95% 响应时间。用这个测试工具以 10 并发、100 次请求压测 www.baidu.com。 
分析:
- 给予持续的10并发压力, 总共请求100次 
- 使用 Semaphore信号量 确保并发数 (实际应该可以不用, 线程池已确保) 
- 使用 CountDownLatch计数器 阻塞等待所有线程完成, 再执行统计 
- Http工具使用池化减少响应时间影响 

package com.tulane.hatch.pressure;import com.tulane.hatch.util.HttpUtils;import java.util.Map;import java.util.SortedMap;import java.util.TreeMap;import java.util.concurrent.CountDownLatch;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.Semaphore;/** * 压测 */public class PressureTest {    private String url;    private int requestNum;    private int concurrentNum;    private SortedMap<Long, Integer> timeMap;    public PressureTest(String url, int requestNum, int concurrentNum) {        this.url = url;        this.requestNum = requestNum;        this.concurrentNum = concurrentNum;        timeMap = new TreeMap<>();    }    public void doExcute(){        ExecutorService executorService = Executors.newFixedThreadPool(concurrentNum);        Semaphore semaphore = new Semaphore(concurrentNum);        CountDownLatch countDownLatch = new CountDownLatch(requestNum);        concurrentRequest(executorService, semaphore, countDownLatch);        // 计算时间        long avgTime = mathAvgTime();        long majorityTime = mathMajorityTime();        System.out.println("请求数为: " + requestNum + " , 并发数为: " + concurrentNum + " , 平均时间: " + avgTime + " , 95%响应时间: " + majorityTime);    }    private void concurrentRequest(ExecutorService executorService, Semaphore semaphore, CountDownLatch countDownLatch) {        for (int i = 0; i < requestNum; i++) {            try {                semaphore.acquire();                executorService.execute(() -> {                    long startTime = System.currentTimeMillis();                    HttpUtils.get(url);                    long endTime = System.currentTimeMillis();                    synchronized (timeMap.getClass()){                        Long key = endTime - startTime;                        final Integer num = timeMap.getOrDefault(key, 0);                        timeMap.put(key, num + 1);                    }                    semaphore.release();                    countDownLatch.countDown();                });            } catch (InterruptedException e) {                e.printStackTrace();            }        }        try {            countDownLatch.await();            executorService.shutdown();        } catch (InterruptedException e) {            e.printStackTrace();        }    }    /**     * 计算平均时间     */    private long mathAvgTime() {        Long sumTime = 0l;        int count = 0;        for (Map.Entry<Long, Integer> entry : timeMap.entrySet()) {            for (Integer i = 0; i < entry.getValue(); i++) {                sumTime += entry.getKey();                count++;            }        }        return sumTime / count;    }    /**     * 计算95%响应时间     */    private long mathMajorityTime() {        int count = 0;        for (Map.Entry<Long, Integer> entry : timeMap.entrySet()) {            for (Integer i = 0; i < entry.getValue(); i++) {                count++;            }        }        int start = 0;        int end = (int) (count / 100D * 95D);        for (Map.Entry<Long, Integer> entry : timeMap.entrySet()) {            for (Integer i = 0; i < entry.getValue(); i++) {                if(++start == end){                    return entry.getKey();                }            }        }        return 0l;    }    public static void main(String[] args) {        final PressureTest pressureTest = new PressureTest("https://www.baidu.com", 100, 10);        pressureTest.doExcute();    }}
HttpUtils
package com.tulane.hatch.util;import org.apache.http.HttpEntity;import org.apache.http.NameValuePair;import org.apache.http.client.config.RequestConfig;import org.apache.http.client.entity.UrlEncodedFormEntity;import org.apache.http.client.methods.CloseableHttpResponse;import org.apache.http.client.methods.HttpGet;import org.apache.http.client.methods.HttpPost;import org.apache.http.config.Registry;import org.apache.http.config.RegistryBuilder;import org.apache.http.conn.socket.ConnectionSocketFactory;import org.apache.http.conn.socket.PlainConnectionSocketFactory;import org.apache.http.conn.ssl.SSLConnectionSocketFactory;import org.apache.http.conn.ssl.TrustSelfSignedStrategy;import org.apache.http.entity.ContentType;import org.apache.http.entity.StringEntity;import org.apache.http.impl.client.CloseableHttpClient;import org.apache.http.impl.client.DefaultHttpRequestRetryHandler;import org.apache.http.impl.client.HttpClients;import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;import org.apache.http.message.BasicNameValuePair;import org.apache.http.ssl.SSLContextBuilder;import org.apache.http.util.EntityUtils;import java.io.IOException;import java.util.ArrayList;import java.util.List;import java.util.Map;public class HttpUtils {    private static CloseableHttpClient httpClient;    static {        try {            SSLContextBuilder builder = new SSLContextBuilder();            builder.loadTrustMaterial(null, new TrustSelfSignedStrategy());            SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(builder.build()); // 配置同时支持 HTTP 和 HTPPS            Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create()                    .register("http", PlainConnectionSocketFactory.getSocketFactory())                    .register("https", sslsf)                    .build();            PoolingHttpClientConnectionManager poolConnManager = new PoolingHttpClientConnectionManager(                    socketFactoryRegistry);            poolConnManager.setMaxTotal(200);            poolConnManager.setDefaultMaxPerRoute(100);            int socketTimeout = 2000;            int connectTimeout = 2000;            int connectionRequestTimeout = 2000;            RequestConfig requestConfig = RequestConfig.custom().setConnectionRequestTimeout(connectionRequestTimeout).setSocketTimeout(socketTimeout).setConnectTimeout(connectTimeout).build();            httpClient = HttpClients.custom().setConnectionManager(poolConnManager).setDefaultRequestConfig(requestConfig).setRetryHandler(new DefaultHttpRequestRetryHandler(0, false)).build();        } catch (Exception e) {        }    }    public static String get(String url) {        return get(url, null, null);    }    public static String get(String url, Map<String, Object> params) {        return get(url, params, null);    }    public static String get(String url, Map<String, Object> params, Map<String, String> headers) {        StringBuilder requestUrl = new StringBuilder(url);        if (params != null) {            requestUrl.append("?");            for (Map.Entry<String, Object> entry : params.entrySet()) {                requestUrl.append(entry.getKey()).append("=").append(String.valueOf(entry.getValue()));                requestUrl.append("&");            }        }        CloseableHttpResponse response = null;        String result = null;        HttpGet httpGet = new HttpGet(requestUrl.toString());        if (headers != null) {            for (Map.Entry<String, String> entry : headers.entrySet()) {                httpGet.addHeader(entry.getKey(), entry.getValue());            }        }        try {            response = httpClient.execute(httpGet);            HttpEntity entity = response.getEntity();            if (entity != null) {                result = EntityUtils.toString(entity);            }        } catch (IOException e) {        } finally {            httpGet.abort();            try {                if (response != null) {                    response.close();                }            } catch (IOException e) {                e.printStackTrace();            }        }        return result;    }    public static String postJson(String url) {        return postJson(url, null, null);    }    public static String postJson(String url, String json) {        return postJson(url, json, null);    }    public static String postJson(String url, String json, Map<String, String> headers) {        HttpPost httpPost = new HttpPost(url);        if (headers != null) {            for (Map.Entry<String, String> entry : headers.entrySet()) {                httpPost.addHeader(entry.getKey(), entry.getValue());            }        }        if (json != null) {            StringEntity stringEntity = new StringEntity(json, ContentType.APPLICATION_JSON);            httpPost.setEntity(stringEntity);        }        String result = null;        CloseableHttpResponse response = null;        try {            response = httpClient.execute(httpPost);            HttpEntity entity = response.getEntity();            if (entity != null) {                result = EntityUtils.toString(entity);            }        } catch (IOException e) {            e.printStackTrace();        } finally {            httpPost.abort();            try {                if (response != null) {                    response.close();                }            } catch (IOException e) {                e.printStackTrace();            }        }        return result;    }    public static String postForm(String url) {        return postForm(url, null, null);    }    public static String postForm(String url, Map<String, String> params) {        return postForm(url, params, null);    }    public static String postForm(String url, Map<String, String> params, Map<String, String> headers) {        HttpPost httpPost = new HttpPost(url);        String result = null;        CloseableHttpResponse response = null;        try {            if (headers != null) {                for (Map.Entry<String, String> entry : headers.entrySet()) {                    httpPost.addHeader(entry.getKey(), entry.getValue());                }            }            if (params != null) {                List<NameValuePair> paramPairs = new ArrayList<NameValuePair>();                for (Map.Entry<String, String> entry : params.entrySet()) {                    paramPairs.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));                }                UrlEncodedFormEntity entity = new UrlEncodedFormEntity(paramPairs, "UTF-8");                httpPost.setEntity(entity);            }            response = httpClient.execute(httpPost);            HttpEntity entity = response.getEntity();            if (entity != null) {                result = EntityUtils.toString(entity);            }        } catch (IOException e) {            e.printStackTrace();        } finally {            httpPost.abort();            try {                if (response != null) {                    response.close();                }            } catch (IOException e) {                e.printStackTrace();            }        }        return result;    }}
划线
评论
复制
发布于: 2020 年 07 月 22 日阅读数: 59

Tulane
关注
还未添加个人签名 2018.09.18 加入
还未添加个人简介











 
    
评论