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压力性能测试