写点什么

架构师训练营 -Week07

用户头像
Just顾
关注
发布于: 2020 年 07 月 23 日



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

吞吐量开始时会增加,系统响应时间不怎么变化。 到达峰值后吞吐量开始下降,并且响应时间开始变长。因为并发量达到一定程度,网卡,CPU,内存,磁盘 都会遇到性能瓶颈,导致系统处理能力下降,请求积压吞吐量下降,响应时间变长。



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

//http 请求工具类
package crawler;
import java.io.IOException;
import java.nio.charset.Charset;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
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.entity.ContentType;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.util.EntityUtils;
public class HttpPoster {
public static CloseableHttpClient getHttpClient() {
// 创建cookie store的本地实例
// CookieStore cookieStore = new BasicCookieStore();
// // 创建HttpClient上下文
// HttpClientContext context = HttpClientContext.create();
// context.setCookieStore(cookieStore);
//
// BasicClientCookie cookie = new BasicClientCookie("4&_device",
// "android&3c00676f-0e58-3aaa-aae8-4a8cc5eb95bf&6.5.63");
// cookie.setDomain(".ximalaya.com"); //设置范围
// cookie.setPath("/");
// cookieStore.addCookie(cookie);
//采用绕过验证的方式处理https请求
SSLContext sslcontext = null;
try {
sslcontext = createIgnoreVerifySSL();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (KeyManagementException e) {
e.printStackTrace();
}
//设置协议http和https对应的处理socket链接工厂的对象
Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory> create()
.register("http", PlainConnectionSocketFactory.INSTANCE)
.register("https", new SSLConnectionSocketFactory(sslcontext)).build();
PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(
socketFactoryRegistry);
return HttpClients.custom().setConnectionManager(connManager).build();
}
/**
* 绕过验证
*
* @return
* @throws NoSuchAlgorithmException
* @throws KeyManagementException
*/
public static SSLContext createIgnoreVerifySSL() throws NoSuchAlgorithmException, KeyManagementException {
SSLContext sc = SSLContext.getInstance("SSLv3");
// 实现一个X509TrustManager接口,用于绕过验证,不用修改里面的方法
X509TrustManager trustManager = new X509TrustManager() {
@Override
public void checkClientTrusted(java.security.cert.X509Certificate[] paramArrayOfX509Certificate,
String paramString) throws CertificateException {
}
@Override
public void checkServerTrusted(java.security.cert.X509Certificate[] paramArrayOfX509Certificate,
String paramString) throws CertificateException {
}
@Override
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
};
sc.init(null, new TrustManager[] { trustManager }, null);
return sc;
}
public static String parseResponse(CloseableHttpResponse response) throws IOException {
HttpEntity entity = response.getEntity();
ContentType contentType = ContentType.getOrDefault(entity);
Charset charset = contentType.getCharset();
String mimeType = contentType.getMimeType();
// 获取字节数组
byte[] content = EntityUtils.toByteArray(entity);
if (charset == null) {
// 默认编码转成字符串
String temp = new String(content);
String regEx = "(?=<meta).*?(?<=charset=[\\'|\\\"]?)([[a-z]|[A-Z]|[0-9]|-]*)";
Pattern p = Pattern.compile(regEx, Pattern.CASE_INSENSITIVE);
Matcher m = p.matcher(temp);
if (m.find() && m.groupCount() == 1) {
charset = Charset.forName(m.group(1));
} else {
charset = Charset.forName("ISO-8859-1");
}
}
return new String(content, charset);
}
}
//压测工具类
package performance;
import crawler.HttpPoster;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import java.io.IOException;
import java.util.Arrays;
import java.util.Queue;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.CyclicBarrier;
public class WebPressureTestUtil {
public static class Time {
private long averageTime;
private long time95;
private Long[] times;
public long getAverageTime() {
return averageTime;
}
public long getTime95() {
return time95;
}
public Time(Long[] times) {
this.times = times;
Arrays.sort(times);
}
public void calculateAverageTime() {
// long total = 0L;
// for (int i = 0; i < times.length; i++) {
// total += times[i];
// }
// this.averageTime = total / times.length;
this.averageTime = times[times.length / 2 - 1];
}
public void calculateTime95() {
int index = times.length * 95 / 100;
this.time95 = times[index];
}
}
private static class Task implements Runnable {
private CountDownLatch signal;
private CountDownLatch finish;
private String url;
private long runCount;
private Queue<Long> timeCostArray;
public Task(CountDownLatch signal, CountDownLatch finish, String url, long runCount,
Queue<Long> timeCostArray) {
this.signal = signal;
this.finish = finish;
this.url = url;
this.runCount = runCount;
this.timeCostArray = timeCostArray;
}
@Override
public void run() {
CloseableHttpClient httpClient = HttpPoster.getHttpClient();
HttpGet get = new HttpGet(url);
try {
signal.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
for (int i = 0; i < runCount; i++) {
long start = System.currentTimeMillis();
try (CloseableHttpResponse response = httpClient.execute(get)) {
timeCostArray.offer(System.currentTimeMillis() - start);
// System.err.println("response:"+HttpPoster.parseResponse(response));
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
finish.countDown();
}
}
public static Time perform(String url, int totalNum, int concurrentNum) throws Exception {
//准备指定并发数量的线程,执行http请求,
//使用countdownlatch 触发并发执行
int runCount = totalNum / concurrentNum;
int remainCount = totalNum % concurrentNum;
CountDownLatch signal = new CountDownLatch(1);
CountDownLatch finish = new CountDownLatch(concurrentNum);
Queue<Long> timeCostArray = new ArrayBlockingQueue<>(totalNum);
for (int i = 0; i < concurrentNum; i++) {
if (i == concurrentNum - 1) {
new Thread(new Task(signal, finish, url, runCount + remainCount, timeCostArray)).start();
} else {
new Thread(new Task(signal, finish, url, runCount, timeCostArray)).start();
}
}
signal.countDown();
finish.await();
Long[] times = new Long[totalNum];
timeCostArray.toArray(times);
return new Time(times);
}
public static void main(String[] args) throws Exception {
Time time = perform("https://www.baidu.com/", 100, 10);
time.calculateAverageTime();
time.calculateTime95();
System.err.println("平均响应时间:" + time.getAverageTime() + "ms");
System.err.println("95%响应时间:" + time.getTime95() + "ms");
}
}



用户头像

Just顾

关注

还未添加个人签名 2018.05.06 加入

还未添加个人简介

评论 (1 条评论)

发布
用户头像
作业请加“极客大学架构师训练营”标签,便于分类
2020 年 07 月 27 日 17:16
回复
没有更多了
架构师训练营 -Week07