架构师训练营 -week7- 作业
发布于: 2020 年 07 月 22 日
性能压测的时候,随着并发压力的增加,系统响应时间和吞吐量如何变化,为什么?
公式:吞吐量=(1000/响应时间 ms)*并发数
在性能压测的性能测试阶段,可根据公式可得出,当并发数增加,平均响应时间不变时,此时系统资源充足,吞吐量随着并发数增加而增加。
当并发数达到某个点时,进入负载测试阶段,当并发数增加,平均响应时间不变时,此时系统资源比较紧张,接近极限,吞吐量不再随着并发数线性增加,而是缓慢增加。
当吞吐量达到曲线峰值时,则进入压力测试阶段,此时并发数增加,此时系统资源被耗尽,平均响应时间增加,吞吐量随着并发数的增大而减小。
用你熟悉的编程语言写一个 web 性能压测工具,输入参数:URL,请求总次数、并发数。输出参数:平均响应时间、95%响应时间。用这个测试工具以 10 并发、100 次请求压测 www.baidu.com。
PerformanceBox
package week7;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Collections;
import java.util.Vector;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class PerformenceBox {
private int parCount;
private int requestTotalCount;
private String requestUrl;
private CyclicBarrier cyclicBarrier;
private ExecutorService pool;
private Vector<Long> cost;
private int currentThreadCount;
public PerformenceBox(int parCount, int requestTotalCount, String Url) {
this.parCount = parCount;
this.requestTotalCount = requestTotalCount;
this.requestUrl = Url;
this.currentThreadCount = parCount;
this.cost = new Vector<>();
this.pool = Executors.newFixedThreadPool(this.parCount);
this.cyclicBarrier = new CyclicBarrier(this.parCount);
}
public void Execute() throws InterruptedException {
// 开始执行
for (int i = 0; i < this.parCount; i++) {
pool.submit(new Task(cyclicBarrier, this.requestTotalCount
/ this.parCount));
}
do {
Thread.sleep(1000);
} while (currentThreadCount > 0);
pool.shutdown();
}
public String outputPerformance() {
//从小到大排序,方便计算95%响应时间
Collections.sort(cost, (o1, o2) -> o1.compareTo(o2));
int percentile95Indx = (int) Math.ceil(cost.size() * 0.95);
double total = 0;
for (int i = 0; i < cost.size(); i++) {
total += cost.get(i);
}
double avg = total / cost.size();
StringBuilder sb = new StringBuilder();
sb.append("平均响应时间:" + avg + "ms\r\n");
sb.append("95%响应时间:" + cost.get(percentile95Indx) + "ms\r\n");
return sb.toString();
}
class Task implements Runnable {
private CyclicBarrier cb;
private int requestCount;
public Task(CyclicBarrier cb, int requestCount) {
this.cb = cb;
this.requestCount = requestCount;
}
@Override
public void run() {
// TODO Auto-generated method stub
try {
// 等待线程准备好
cb.await();
startSending(requestCount);
} catch (InterruptedException | BrokenBarrierException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
delThread();
}
}
}
private void delThread() {
currentThreadCount--;
}
public void startSending(int requestCount) throws IOException {
// 每条线程执行requestCount次
for (int i = 0; i < requestCount; i++) {
this.cost.add(send());
}
}
private long send() throws MalformedURLException {
HttpURLConnection connection = null;
InputStream is = null;
OutputStream os = null;
BufferedReader br = null;
URL url = new URL(this.requestUrl);
long startTime = 0;
long endTime;
try {
connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("POST");
connection.setConnectTimeout(15000);
connection.setReadTimeout(60000);
connection.setDoOutput(true);
connection.setDoInput(true);
connection.setRequestProperty("Content-Type",
"application/x-www-form-urlencoded");
connection.setRequestProperty("Content-Type",
"application/x-www-form-urlencoded");
startTime = System.currentTimeMillis(); // 获取开始时间
os = connection.getOutputStream();
if (connection.getResponseCode() == 200) {
is = connection.getInputStream();
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");
}
// System.out.println(sbf.toString());
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
endTime = System.currentTimeMillis(); // 获取结束时间
if (null != br) {
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (null != os) {
try {
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (null != is) {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
connection.disconnect();
}
return endTime - startTime;
}
}
复制代码
PerformanceTest
package week7;
import junit.framework.TestCase;
public class PeformanceTest extends TestCase {
private int parCount;
private int reqTotalCount;
private String reqUrl;
@Override
protected void setUp() {
this.parCount = 10;
this.reqTotalCount = 100;
this.reqUrl = "https://www.baidu.com";
StringBuilder sb = new StringBuilder();
sb.append("并发数:" + this.parCount + "\r\n");
sb.append("请求总数:" + this.reqTotalCount + "\r\n");
sb.append("压测URL:" + this.reqUrl + "\r\n");
System.out.println(sb.toString());
}
public void testPerformance() {
PerformenceBox box = new PerformenceBox(this.parCount, this.reqTotalCount, this.reqUrl);
try {
box.Execute();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(box.outputPerformance());
}
}
复制代码
划线
评论
复制
发布于: 2020 年 07 月 22 日阅读数: 54
版权声明: 本文为 InfoQ 作者【晓-Michelle】的原创文章。
原文链接:【http://xie.infoq.cn/article/3324e87a008e73c6dc6c9815a】。未经作者许可,禁止转载。
晓-Michelle
关注
还未添加个人签名 2020.05.30 加入
还未添加个人简介
评论