web 压力性能测试

用户头像
周冬辉
关注
发布于: 2020 年 07 月 21 日

1.用你熟悉的编程语言写一个web性能压测工具,输入参数URL,请求总次数,并发数。输出参数

求压测平均响应时间,95%响应时间。用这个测试工具以10并发、100次请压测。



  • 关键点

Http请求服务

线程池并发:线程池、运行N个线程、每个线程执行多次写的Http请求服务

数据统计和收集

  • 压力框架类图

  1. TestBaseRunnable.java:测试业务任务类

  2. TestBaseMainTest.java:测试业务线程池和并发任务类,统计数据



  • TestBaseRunnable.java代码

package ptf;



import java.util.ArrayList;

import java.util.List;

import java.util.concurrent.CyclicBarrier;



public class TestBaseRunnable implements Runnable {



private int cycleCount;// 循环次数



private long reponse_time;// 响应时间



private long fail_num;



private boolean isfail;



public List<TestResult> result;



private long startTime;



private long endTime;



private CyclicBarrier cyclicBarrier;



// private PerformanceTestBaseMainTest MainTest;



TestBaseRunnable(int nCycleCount, CyclicBarrier ccyclicBarrier) {

cycleCount = nCycleCount;

cyclicBarrier = ccyclicBarrier;



result = new ArrayList<TestResult>();

fail_num = 0;

}



public boolean request() {

return true;

}



public void run() {

try {

for (int i = 0; i < cycleCount; i++) {



threadStartBefore();

try {

isfail = request();

} catch (Exception e) {

e.printStackTrace();

isfail = false;

}

threadEndAfter();

}

cyclicBarrier.await();



} catch (Exception e) {

e.printStackTrace();

}

}



private java.lang.Object threadStartBefore() {

// 等待所有任务准备就绪

isfail = false;

startTime = System.currentTimeMillis();

return null;

}



private java.lang.Object threadEndAfter() {

endTime = System.currentTimeMillis();

reponse_time = endTime - startTime;

TestResult res = new TestResult(reponse_time, isfail);

this.result.add(res);

if (!isfail) {

fail_num++;

}

System.out.println(this.reponse_time + " " + this.isfail);

return null;

}



public long getFailNum() {

return fail_num;

}



public void setFailNum(long fail_num) {

this.failnum = failnum;

}



}

  • TestBaseMainTest.java代码

package ptf;



import java.util.ArrayList;

import java.util.Collections;

import java.util.List;

import java.util.concurrent.CyclicBarrier;

import java.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;



public class TestBaseMainTest {



private long total95_time;// 总时间



private long avg_time;// 平均时间



private long fail_time;// 失败次数



protected int cycleCount;//循环次数



protected int curCount;// 并发次数



private List<TestResult> result;



protected List<TestBaseRunnable> testRunnablelist;



private ExecutorService executorService;



protected CyclicBarrier cyclicBarrier;



TestBaseMainTest(int curCount, int cycleCount) {

this.curCount = curCount;

this.cycleCount = cycleCount;



testRunnablelist = new ArrayList<TestBaseRunnable>();



result = new ArrayList<TestResult>();



cyclicBarrier = new CyclicBarrier(curCount);



fail_time = 0;

avg_time=0;

}



void startMain() {

executorService = Executors.newFixedThreadPool(curCount);// 创建一个可缓存线程池



beforeRunTask();



creatAllThreadAndStratTest();



executorService.shutdown(); // Disable new tasks from being submitted



// 判断是否所有的线程已经运行完

while (!executorService.isTerminated()) {

try {

// 所有线程池中的线程执行完毕,执行后续操作

System.out.println("==============is sleep============");

Thread.sleep(10000);

System.out.println("==============is wake============");



} catch (InterruptedException e) {

e.printStackTrace();

}

}

afterRunTask();

}



// Optional

public void beforeRunTask()

{

for (int i = 0; i < curCount; i++) {

TestBaseRunnable testRunnable = new TestBaseRunnable(cycleCount, cyclicBarrier);

testRunnablelist.add(testRunnable);

}

}



// Optional

public void afterRunTask() {



int nsize = testRunnablelist.size();



long total_time = 0;// 总时间



for (int i = 0; i < nsize; i++) {

TestBaseRunnable testRunnable = testRunnablelist.get(i);



failtime = failtime + testRunnable.getFailNum();



int nresultsize = testRunnable.result.size();

for (int j = 0; j < nresultsize; j++) {



TestResult res = testRunnable.result.get(j);

totaltime += res.getReponsetime();

TestResult resth = new TestResult(res.getReponse_time(), res.isFail());

result.add(resth);

}

}



Collections.sort(result);



TestResult total95 = result.get(curCount cycleCount 95 / 100);

total95time = total95.getReponsetime();

avgtime=totaltime/curCount / cycleCount;



System.out.println("aver time: " + avg_time);

System.out.println("95% Response time: " + total95_time+"ms");



}



void creatAllThreadAndStratTest() {



for (int i = 0; i < curCount; i++) {

TestBaseRunnable testRunnable = testRunnablelist.get(i);

executorService.execute(testRunnable);

}

}

}

  • TestHttpRunnable.java代码

package ptf;



import java.util.concurrent.CyclicBarrier;



public class TestHttpRunnable extends TestBaseRunnable {



private String url;



public TestHttpRunnable(int nCycleCount, CyclicBarrier ccyclicBarrier) {

super(nCycleCount,ccyclicBarrier);

}



public String getUrl() {

return url;

}



public void setUrl(String url) {

this.url = url;

}

public boolean request() {



try {

HttpRequester request = new HttpRequester();

HttpResponser hr = request.sendGet(url);

return hr.getCode() <400 ? true : false;

} catch (Exception e) {

e.printStackTrace();

}

return false;

}

}



  • TestBaseMainTest.java代码

package ptf;



public class TestHttpMainTest extends TestBaseMainTest {

private String url;



public TestHttpMainTest(int curCount, int cycleCount) {

super(curCount, cycleCount);

}

public void beforeRunTask()

{

for (int i = 0; i < curCount; i++) {

TestHttpRunnable testRunnable = new TestHttpRunnable(cycleCount, cyclicBarrier);

testRunnable.setUrl(url);

testRunnablelist.add(testRunnable);

}

}



public String getUrl() {

return url;

}



public void setUrl(String url) {

this.url = url;

}

}



  • HttpResponser.java代码



package ptf;



import java.util.Vector;



/**

* 响应对象

*/

public class HttpResponser {

String urlString;

int defaultPort;

String file;

String host;

String path;

int port;

String protocol;

String query;

String ref;

String userInfo;

String contentEncoding;

String content;

String contentType;

int code;

String message;

String method;

int connectTimeout;

int readTimeout;

Vector<String> contentCollection;

public String getContent() {

return content;

}

public String getContentType() {

return contentType;

}

public int getCode() {

return code;

}

public String getMessage() {

return message;

}

public Vector<String> getContentCollection() {

return contentCollection;

}

public String getContentEncoding() {

return contentEncoding;

}

public String getMethod() {

return method;

}

public int getConnectTimeout() {

return connectTimeout;

}

public int getReadTimeout() {

return readTimeout;

}

public String getUrlString() {

return urlString;

}

public int getDefaultPort() {

return defaultPort;

}

public String getFile() {

return file;

}

public String getHost() {

return host;

}

public String getPath() {

return path;

}

public int getPort() {

return port;

}

public String getProtocol() {

return protocol;

}

public String getQuery() {

return query;

}

public String getRef() {

return ref;

}

public String getUserInfo() {

return userInfo;

}

}

  • HttpRequester.java代码

package ptf;



import java.io.BufferedReader;

import java.io.IOException;

import java.io.InputStream;

import java.io.InputStreamReader;

import java.net.HttpURLConnection;

import java.net.URL;

import java.nio.charset.Charset;

import java.util.Map;

import java.util.Vector;



/**

* HTTP请求对象

*

* @author YYmmiinngg

*/

public class HttpRequester {

private String defaultContentEncoding;



public HttpRequester() {

this.defaultContentEncoding = Charset.defaultCharset().name();

}



/**

* 发送GET请求

*

* @param urlString

* URL地址

* @return 响应对象

* @throws IOException

*/

public HttpResponser sendGet(String urlString) throws IOException {

return this.send(urlString, "GET", null, null);

}



/**

* 发送GET请求

*

* @param urlString

* URL地址

* @param params

* 参数集合

* @return 响应对象

* @throws IOException

*/

public HttpResponser sendGet(String urlString, Map<String, String> params) throws IOException {

return this.send(urlString, "GET", params, null);

}



/**

* 发送GET请求

*

* @param urlString

* URL地址

* @param params

* 参数集合

* @param propertys

* 请求属性

* @return 响应对象

* @throws IOException

*/

public HttpResponser sendGet(String urlString, Map<String, String> params, Map<String, String> propertys)

throws IOException {

return this.send(urlString, "GET", params, propertys);

}



/**

* 发送POST请求

*

* @param urlString

* URL地址

* @return 响应对象

* @throws IOException

*/

public HttpResponser sendPost(String urlString) throws IOException {

return this.send(urlString, "POST", null, null);

}



/**

* 发送POST请求

*

* @param urlString

* URL地址

* @param params

* 参数集合

* @return 响应对象

* @throws IOException

*/

public HttpResponser sendPost(String urlString, Map<String, String> params) throws IOException {

return this.send(urlString, "POST", params, null);

}



/**

* 发送POST请求

*

* @param urlString

* URL地址

* @param params

* 参数集合

* @param propertys

* 请求属性

* @return 响应对象

* @throws IOException

*/

public HttpResponser sendPost(String urlString, Map<String, String> params, Map<String, String> propertys)

throws IOException {

return this.send(urlString, "POST", params, propertys);

}



/**

* 发送HTTP请求

*

* @param urlString

* @return 响映对象

* @throws IOException

*/

private HttpResponser send(String urlString, String method, Map<String, String> parameters,

Map<String, String> propertys) throws IOException {

HttpURLConnection urlConnection = null;



if (method.equalsIgnoreCase("GET") && parameters != null) {

StringBuffer param = new StringBuffer();

int i = 0;

for (String key : parameters.keySet()) {

if (i == 0)

param.append("?");

else

param.append("&");

param.append(key).append("=").append(parameters.get(key));

i++;

}

urlString += param;

}

URL url = new URL(urlString);

urlConnection = (HttpURLConnection) url.openConnection();



urlConnection.setRequestMethod(method);

urlConnection.setDoOutput(true);

urlConnection.setDoInput(true);

urlConnection.setUseCaches(false);



if (propertys != null)

for (String key : propertys.keySet()) {

urlConnection.addRequestProperty(key, propertys.get(key));

}



if (method.equalsIgnoreCase("POST") && parameters != null) {

StringBuffer param = new StringBuffer();

for (String key : parameters.keySet()) {

param.append("&");

param.append(key).append("=").append(parameters.get(key));

}

urlConnection.getOutputStream().write(param.toString().getBytes());

urlConnection.getOutputStream().flush();

urlConnection.getOutputStream().close();

}



return this.makeContent(urlString, urlConnection);

}



/**

* 得到响应对象

*

* @param urlConnection

* @return 响应对象

* @throws IOException

*/

private HttpResponser makeContent(String urlString, HttpURLConnection urlConnection) throws IOException {

HttpResponser httpResponser = new HttpResponser();

try {

InputStream in = urlConnection.getInputStream();

BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(in));

httpResponser.contentCollection = new Vector<String>();

StringBuffer temp = new StringBuffer();

String line = bufferedReader.readLine();

while (line != null) {

httpResponser.contentCollection.add(line);

temp.append(line).append("\r\n");

line = bufferedReader.readLine();

}

bufferedReader.close();



String ecod = urlConnection.getContentEncoding();

if (ecod == null)

ecod = this.defaultContentEncoding;



httpResponser.urlString = urlString;



httpResponser.defaultPort = urlConnection.getURL().getDefaultPort();

httpResponser.file = urlConnection.getURL().getFile();

httpResponser.host = urlConnection.getURL().getHost();

httpResponser.path = urlConnection.getURL().getPath();

httpResponser.port = urlConnection.getURL().getPort();

httpResponser.protocol = urlConnection.getURL().getProtocol();

httpResponser.query = urlConnection.getURL().getQuery();

httpResponser.ref = urlConnection.getURL().getRef();

httpResponser.userInfo = urlConnection.getURL().getUserInfo();



httpResponser.content = new String(temp.toString().getBytes(), ecod);

httpResponser.contentEncoding = ecod;

httpResponser.code = urlConnection.getResponseCode();

httpResponser.message = urlConnection.getResponseMessage();

httpResponser.contentType = urlConnection.getContentType();

httpResponser.method = urlConnection.getRequestMethod();

httpResponser.connectTimeout = urlConnection.getConnectTimeout();

httpResponser.readTimeout = urlConnection.getReadTimeout();



return httpResponser;

} catch (IOException e) {

throw e;

} finally {

if (urlConnection != null)

urlConnection.disconnect();

}

}



/**

* 默认的响应字符集

*/

public String getDefaultContentEncoding() {

return this.defaultContentEncoding;

}



/**

* 设置默认的响应字符集

*/

public void setDefaultContentEncoding(String defaultContentEncoding) {

this.defaultContentEncoding = defaultContentEncoding;

}

}

  • PerformanceTest.java代码

package ptf;



public class PerformanceTest {



public PerformanceTest() {

}



public static void main(String[] args) {

TestHttpMainTest MainTest = new TestHttpMainTest(10,100);

MainTest.setUrl("http://live.sonoscape.com");

MainTest.startMain();

}

}



  • 运行结果



aver time: 105ms (平均响应时间)

95% Response time: 141ms(95%响应时间)

从开始的4743ms逐渐减少100ms,解释http://live.sonoscape.com采用了CDN进行缓存



  • 压力测试中遇到的问题:

压力测试中遇到登录微信扫码认证才能登录(解决方案将session进行缓存用于下次的任务测试)

单位时间发送的请求控制保证并发

什么场景下性能需要重点测试?



用户头像

周冬辉

关注

还未添加个人签名 2020.04.14 加入

还未添加个人简介

评论

发布
暂无评论
web压力性能测试