架构师培训第七周练习
1、性能压测,随着并发压力的增加,系统响应时间和吞吐量如何变化,为什么?
并发数、吞吐量、平均响应时间三者之间关系
性能测试阶段:系统并发访问数在系统的指定目标之内,系统硬件资源处于不饱合,此时系统的响应时间短,系统吞吐量未到达系统上线,所以吞吐量处于线性增长趋势,响应时间比较短,增长缓慢。
负载测试阶段:随着并发用户数的增加,系统硬件资源利用率上升,直到系统某些硬件资源达到饱和状态,此时由于需要等待硬件资源的使用,并发请求来不及及时处理,如果继续增加并发数,系统吞吐量增加缓慢,达到系统临界点后系统吞吐量开始降低,响应时间快速增长。
压力测试阶段:系统资源使用率到达饱和状态之后,继续增加并发量,此时系统吞吐量快速降低,直到系统压跨,响应时间无线长,系统不再处理任何请求。
2、用你熟悉的编程语言写一个 web 性能压测工具,输入参数:URL,请求总次数,并发数。输出参数:平均响应时间,95% 响应时间。用这个测试工具以 10 并发、100 次请求压测 www.baidu.com。
(1)压测类 WebLoadTester.java
package com.cfcc.demo;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class WebLoadTester {
// 总共请求数
private int totalNums = 100;
// 并发数
private int concurrentNums = 10;
// 压测地址
private String url;
public WebLoadTester(int totalNums, int concurrentNums, String url) {
this.totalNums = totalNums;
this.concurrentNums = concurrentNums;
this.url = url;
}
public LoadTestResult run() throws InterruptedException {
// 用于协调线程执行,并发数10, 请求100次
CountDownLatch countDownLatch = new CountDownLatch(totalNums * concurrentNums);
CopyOnWriteArrayList timecollection = new CopyOnWriteArrayList<Object>();
// 创建线程池用于执行线程
ExecutorService threadPool = Executors.newFixedThreadPool(this.concurrentNums);
// 请求100次
for (int j = 0; j < totalNums; j++) {
// 每次并发为10
for (int i = 0; i < concurrentNums; i++) {
RequestThread requestThread = new RequestThread(url, countDownLatch, timecollection);
threadPool.execute(requestThread);
}
// 间隔一秒
Thread.sleep(1000);
}
// 等待所有线程执行完毕
countDownLatch.await();
LoadTestResult result = new LoadTestResult();
// 响应时间排序
Collections.sort(timecollection, new Comparator<Object>() {
public int compare(Object o1, Object o2) {
Long l1 = (Long) o1;
Long l2 = (Long) o2;
return l1.compareTo(l2);
}
});
if (timecollection.size() > 0) {
// 计算95%的响应时间
int index = timecollection.size() * 95 / 100;
result.setPercent95Time((Long) timecollection.get(index));
// 计算平均响应时间
Long total = (long) 0;
for (Iterator iterator = timecollection.iterator(); iterator.hasNext();) {
Long object = (Long) iterator.next();
total = total + object;
}
result.setAverageTime(total / timecollection.size());
}
return result;
}
}
(2)压测线程类 RequestThread.java
package com.cfcc.demo;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.X509Certificate;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CountDownLatch;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.impl.client.DefaultHttpClient;
public class RequestThread implements Runnable {
private CountDownLatch countDownLatch;
private String requestUrl;
private CopyOnWriteArrayList timecollection;
private Log log = LogFactory.getLog(RequestThread.class);
public RequestThread(String requestUrl, CountDownLatch countDownLatch,CopyOnWriteArrayList timecollection) {
this.requestUrl = requestUrl;
this.countDownLatch = countDownLatch;
this.timecollection = timecollection;
}
private static void sslClient(HttpClient httpClient) {
try {
SSLContext ctx = SSLContext.getInstance("TLS");
X509TrustManager tm = new X509TrustManager() {
public X509Certificate[] getAcceptedIssuers() {
return null;
}
public void checkClientTrusted(X509Certificate[] xcs, String str) {
}
public void checkServerTrusted(X509Certificate[] xcs, String str) {
}
};
ctx.init(null, new TrustManager[] { tm }, null);
SSLSocketFactory ssf = new SSLSocketFactory(ctx);
ssf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
ClientConnectionManager ccm = httpClient.getConnectionManager();
SchemeRegistry registry = ccm.getSchemeRegistry();
registry.register(new Scheme("https", 443, ssf));
} catch (KeyManagementException ex) {
throw new RuntimeException(ex);
} catch (NoSuchAlgorithmException ex) {
throw new RuntimeException(ex);
}
}
public void run() {
try {
HttpClient httpClient = new DefaultHttpClient();
if (requestUrl.startsWith("https://")) {
sslClient(httpClient);
}
HttpGet request = new HttpGet(requestUrl);
//调用起始时间
long begin = System.currentTimeMillis();
httpClient.execute(request);
//调用结束时间
long end = System.currentTimeMillis();
//计算调用时间
long time = (end-begin);
//放入list用于统计
timecollection.add(time);
countDownLatch.countDown();
} catch (Exception e) {
countDownLatch.countDown();
log.error("请求失败",e);
}
}
}
(3)压测结果类,用于存放压测结果 LoadTestResult.java
package com.cfcc.demo;
public class LoadTestResult {
// 95%的响应时间
private Long percent95Time;
// 平均响应时间
private Long averageTime;
public Long getPercent95Time() {
return percent95Time;
}
public void setPercent95Time(Long percent95Time) {
this.percent95Time = percent95Time;
}
public Long getAverageTime() {
return averageTime;
}
public void setAverageTime(Long averageTime) {
this.averageTime = averageTime;
}
}
(4)测试main函数
package com.cfcc.demo;
public class Test {
public static void main(String[] args) throws InterruptedException {
//初始化压测类,并发10,访问100次,访问地址 https://www.baidu.com/
WebLoadTester loader = new WebLoadTester(100,10,"https://www.baidu.com/");
try {
LoadTestResult result = loader.run();
System.out.println("平均响应时间: "+result.getAverageTime()+" 毫秒");
System.out.println("95%响应时间: "+result.getPercent95Time()+" 毫秒");
} catch (InterruptedException e) {
System.out.println("请求失败:"+e.getMessage());
}
}
}
测试执行结果:
平均响应时间: 305 毫秒
95%响应时间: 812 毫秒
评论 (1 条评论)