写点什么

第 7 周性能优化

用户头像
关注
发布于: 2020 年 07 月 22 日

作业一:

以下两题,至少选做一题

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



图例解释:随着并发量越来越多,响应时间也越来越长,当并发量达到系统最大负载点(c)后,并发数再增加,响应时间将以指数级增大,直到系统崩溃点(d),服务器宕机,不再响应。

图例解释:随着并发量越来越多,系统吞吐量TPS随之增高,系统资源利用率增高,当并发量达到系统最大负载点(c)后,并发数再增加,TPS将以下降,直到系统资源被耗尽(d),服务器宕机,不再响应。



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

实现逻辑:性能压测的实现逻辑为多线程执行(并发),每个线程执行10次的http get请求。10个线程每个线程执行10次,总计100次。

难点:多线程执行时为了计算平均响应时长,需要实现多线程的回调,在回调函数里实现所有线程执行完成后的总调用时长,然后根据总调用时长除以总次数即为平均调用时长。

这里采用list来记录每个线程每次调用的时长,95%响应时长可以按照Collections.sort(list)来正向排序,取95个然后再计算平均时长,即可得到95%响应时长。

1、先定义回调接口

package com.wxprogram;

import java.util.List;

/**
* 回调接口
*/
public interface CallBack {
/**
* 回调函数
*
* @param result
*/
void call();
}

2、调用方

package com.wxprogram;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
* 调用方
* 实现回调接口
*/
public class Caller implements CallBack {
//用于计数
private int length, count;
private static List<Long> list = new ArrayList<Long>();
/**
* 构造函数
*/
public Caller() {
length = 10;
count = 0;
}
/**
* 构造函数
*/
public Caller(int len) {
this.length = len;
}
/**
* 要调用的Deal方法的函数,模拟length条线程进行处理
* 总线程数length
*/
public void deal(int finalI) {
Executor dev = new Executor();
for (int i = 0; i < length; i++) {
new Thread(new Runnable() {
@Override
public void run() {
//调用具体逻辑,传入此对象
dev.deal(Caller.this, finalI,list);
}
}).start();
}
}
/**
* 回调函数处理逻辑,等所有线程处理完,进行后续逻辑处理
*
* @param result
*/
public void call() {
synchronized (Caller.class) {
//输出执行状态
// System.out.println(result);
length--;
count++;
System.out.println("执行线程数量统计=" + count);
if (length == 0) {
System.out.println("所有线程执行完毕"+list.size());
Collections.sort(list);
long requestTimeCounts =0L;
for (Long l : list) {
requestTimeCounts+=l;
}
long avgrequestTime = requestTimeCounts/100;
System.out.println("请求URL:http://www.baidu.com 并发数:"+10+" 请求次数"+list.size()+" 响应总时长:"+requestTimeCounts+" 平均响应时长:"+avgrequestTime);
int j = list.size()%95;
long requestTimeCountsPer95 = 0;
for(int i=0;i<j;i++) {
requestTimeCountsPer95+=list.get(i);
}
System.out.println("95%响应时长为:"+requestTimeCountsPer95/j);
}
}
}
}


3、执行方 调用回调函数

package com.wxprogram;

import java.util.List;
import java.util.Random;

import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;

/**
* 执行方 调用回调函数
*/
public class Executor {

/**
*处理逻辑 并调用回调方法
*一条线程执行count次数
* @param callBack
* @param index
*/
public void deal(CallBack callBack, int count,List list) {
// System.out.println("第" + index + "条线程开始执行");
// 随机数模拟方法执行一段时间
// long m = new Random().nextInt(5);
try {
// Thread.sleep(m * 1000);
for(int i=0;i<count;i++) {
long beginTime = System.currentTimeMillis();
CloseableHttpClient client = HttpClients.createDefault(); // 创建一个http客户端
HttpGet httpGet = new HttpGet("http://www.baidu.com"); // 通过httpget方式来实现我们的get请求
CloseableHttpResponse Response = client.execute(httpGet);
if (Response.getStatusLine().getStatusCode() == 200) {
// 正确响应
}
Response.close(); // 关闭
long end = System.currentTimeMillis();
list.add(end - beginTime);
System.out.println("执行时长:" + (end - beginTime));
}
} catch (Exception e) {
e.printStackTrace();
System.out.println("sleep异常");
}
// String result = "第" + index + "条线程执行完成,执行" + m + "秒";
// 执行完成调用回调函数
callBack.call();
}

}



4、测试类

package com.wxprogram;

public class HttpClientTest{
public static void main(String[] args) {
Caller master = new Caller(10);
master.deal(10);
}
}

5、执行后打印日志:

执行时长:71
执行线程数量统计=10
所有线程执行完毕100
请求URL:http://www.baidu.com 并发数:10 请求次数100 响应总时长:59649 平均响应时长:596
95%响应时长为:41



作业二:

性能优化前,需要先进行性能测试,不能对没有经过测试的项目进行性能优化。



用户头像

关注

还未添加个人签名 2018.04.25 加入

还未添加个人简介

评论 (1 条评论)

发布
用户头像
请加“极客大学架构师训练营”标签,便于分类
2020 年 07 月 22 日 18:18
回复
没有更多了
第7周性能优化