架构师训练营 - 作业 7
发布于: 2020 年 07 月 22 日

1.性能压测的时候,随着并发压力的增加,系统响应时间和吞吐量如何变化,为什么?
性能压测时,在性能测试,负载测试和压力测试时,系统响应时间变化如下图
 性能压测时,在性能测试,负载测试和压力测试时,系统吞吐量变化如下图
 由图可见,在性能测试阶段,系统响应时间近似不变,吞吐量近似于线性上升,在负载测试阶段,响应时间明显增大,吞吐量上升趋势减缓,在压力测试阶段,响应时间急剧增大,吞吐量下降直至系统崩溃。
其原因为:在性能测试阶段, 系统硬软件资源尚未完全被使用,可以通过增加系统软硬件资源的方式来响应不断增加的并发情求,在负载测试阶段,由于系统资源已经几乎完全被占用,所以会出现并发请求排队,系统线程调度等耗费,造成并发请求响应时间延长,吞吐量上升趋势减缓,到了压力测试阶段,由于系统资源耗尽,出现了大量并发请求拥堵等待,系统响应时间急剧增大,吞吐量下降直至系统不可用。
2.用你熟悉的语言编写一个 web 性能压测工具,输入参数:URL,请求总次数,并发数。输出参数:平均响应时间,95%响应时间。用这个测试工具以 10 并发,100 次请求压测 www.baidu.com。
代码如下:
import java.util.Map;import java.util.concurrent.ConcurrentHashMap;import java.util.concurrent.atomic.AtomicInteger;import java.net.URL;import java.net.URLConnection;import java.time.Instant;import java.time.temporal.ChronoUnit;import java.net.HttpURLConnection;import java.io.BufferedReader;import java.io.InputStreamReader;import java.io.IOException;
public class TestPerformance implements Runnable{	public static Map<String, Long> map = new ConcurrentHashMap<String, Long>();	  //每个线程的执行次数    private int totalCount;    //测试访问网站的URL    private String urlString;    //记录多线程的总执行次数,保证高并发下的原子性    public static AtomicInteger atomicInteger = new AtomicInteger(0);        public TestPerformance(int totalCount, String urlString) {        this.totalCount = totalCount;        this.urlString = urlString;    }     @Override    public void run() {        int count = 0;        while (count < totalCount) {            count++;            atomicInteger.getAndIncrement();            Instant now = Instant.now();            testConnectWebSite();            long used = ChronoUnit.MILLIS.between(now, Instant.now());            System.out.println("线程ID与对应的执行次数:" + Thread.currentThread().getId() + "--->" + count+" , 耗时"+used+"ms");    	      map.put("线程ID与对应的执行次数:" + Thread.currentThread().getId() + "--->" + count,used);        }          }        public void testConnectWebSite(){    	 try    	 {            URL url = new URL(urlString);            //连接网站            URLConnection urlConnection = url.openConnection();            HttpURLConnection connection = null;            if(!(urlConnection instanceof HttpURLConnection))            {            	System.out.println("请输入正确 URL 地址");                return;                           }            connection = (HttpURLConnection) urlConnection;            BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));                        //打印网站输出内容,用于验证网站可正常访问            String contents = "";            String current;            while((current = in.readLine()) != null)            {               contents += current;            }            System.out.println(contents);         }    	   catch(IOException e)         {            e.printStackTrace();         }      }}复制代码
 import java.util.Collections;import java.util.Comparator;import java.util.LinkedList;import java.util.List;import java.util.Map;import java.util.Map.Entry;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.TimeUnit;
public class StressTester {
	public void doTest(int threadSize,int totalCount, String urlString) throws InterruptedException{		if (threadSize<1){			System.out.println("线程并发数量不能小于1");			return;		}		if (totalCount<1){			System.out.println("线程运行次数不能小于1");			return;		}		if ((urlString == null)||(urlString.equals(""))){			System.out.println("测试连接网站URL不能为空");			return;		}		//创建线程池		ExecutorService executorService = Executors.newFixedThreadPool(threadSize);		    //让线程池中的每一个线程都开始工作		for (int j = 0; j < threadSize; j++) {		    //执行线程		    executorService.execute(new TestPerformance(totalCount,urlString));		}		//等线程全部执行完后关闭线程池		executorService.shutdown();		executorService.awaitTermination(Integer.MAX_VALUE, TimeUnit.DAYS);		List<Map.Entry<String, Long>> sortedEntryList = sortEntryByEntryValue(TestPerformance.map);		if (sortedEntryList.size()>1)		{				System.out.println("Performance test result show below:====================");			System.out.println("平均响应时间为:"+calculateAvgResponTime(sortedEntryList)+"ms");			System.out.println("95%请求响应时间为:"+calculateSpecifiedPercentageResponTime(sortedEntryList, 0.95)+"ms");			return;		}		System.out.println("未能获取测试数据");	}		//按照Entry的value(每次连接测试网站响应时间)大小排序并按照升序将Entry顺序放入list中	public LinkedList<Entry<String,Long>> sortEntryByEntryValue(Map<String, Long> map){	    LinkedList<Map.Entry<String,Long>> list = new LinkedList<Map.Entry<String,Long>>(map.entrySet());	    Comparator<Map.Entry<String,Long>> comparator = Comparator.comparing(Map.Entry::getValue); 	    Collections.sort(list,comparator);	    return list;	}		//根据按照Entry的value(每次连接测试网站响应时间)大小排序的list计算平均响应时间	public Double calculateAvgResponTime(List<Map.Entry<String, Long>> list){		return list.stream().mapToLong(Map.Entry::getValue).average().getAsDouble();	}		//根据按照Entry的value(每次连接测试网站响应时间)大小排序的list和给定百分比计算百分比响应时间(即)	public Long calculateSpecifiedPercentageResponTime(List<Map.Entry<String, Long>> list,double percentage){		return list.get(new Long(Math.round(list.size()*percentage)).intValue()-1).getValue();
	}		//模拟测试入口类	public static void main(String[] args) throws InterruptedException{		new StressTester().doTest(10, 100, "http://www.baidu.com");	}
}复制代码
 测试结果:
 平均响应时间为:48.593ms
95%请求响应时间为: 95ms
划线
评论
复制
发布于: 2020 年 07 月 22 日阅读数: 62
进击的炮灰
关注
还未添加个人签名 2020.05.13 加入
还未添加个人简介











    
评论